Linux 下用 systemd 管理一个 Python 服务的入门实践

举报
yd_240066378 发表于 2026/11/11 08:44:20 2026/11/11
【摘要】 把一段 Python 脚本变成开机自启、崩溃可拉起的后台服务,不一定非要上 supervisord 或容器。systemd 在主流发行版里已经是默认初始化系统,学会写一个 unit 文件,日常运维会轻松很多。下面用一个最小可运行的例子走一遍从脚本、单元文件到启停排查的完整路径。 1. 准备一个最简单的服务脚本先不要直接拿业务代码开刀。用一个只写日志的脚本确认整条链路是通的:#!/usr/bi...

把一段 Python 脚本变成开机自启、崩溃可拉起的后台服务,不一定非要上 supervisord 或容器。systemd 在主流发行版里已经是默认初始化系统,学会写一个 unit 文件,日常运维会轻松很多。下面用一个最小可运行的例子走一遍从脚本、单元文件到启停排查的完整路径。

1. 准备一个最简单的服务脚本

先不要直接拿业务代码开刀。用一个只写日志的脚本确认整条链路是通的:

#!/usr/bin/env python3
import logging
import signal
import sys
import time

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(message)s",
    stream=sys.stdout,
)
running = True

def handle_stop(signum, _frame):
    global running
    logging.info("received signal %s, shutting down", signum)
    running = False

signal.signal(signal.SIGTERM, handle_stop)
signal.signal(signal.SIGINT, handle_stop)

logging.info("demo service started")
while running:
    logging.info("heartbeat")
    time.sleep(10)
logging.info("demo service stopped")

把文件放到 /opt/demo-service/app.py,并赋予执行权限:

sudo mkdir -p /opt/demo-service
sudo cp app.py /opt/demo-service/app.py
sudo chmod 755 /opt/demo-service/app.py

注意两点:脚本要用前台循环而不是自己 daemonize;日志打到 stdout,方便 journald 收集。

2. 编写 systemd unit

新建 /etc/systemd/system/demo-py.service:

[Unit]
Description=Demo Python service
After=network.target

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/demo-service
ExecStart=/usr/bin/python3 /opt/demo-service/app.py
Restart=on-failure
RestartSec=3
# 把 Python 的 stdout/stderr 交给 journal
Environment=PYTHONUNBUFFERED=1

# 稍作收紧,避免服务进程写到不该写的地方
ProtectSystem=full
PrivateTmp=true

[Install]
WantedBy=multi-user.target

几个容易踩坑的字段:

  • Type=simple 适合一直挂在前台的进程。如果脚本自己 fork 到后台,systemd 会误判它已经退出。
  • User= 不要用 root 跑普通业务。提前确认该用户对工作目录有读权限。
  • PYTHONUNBUFFERED=1 让日志立即出现在 journalctl 里,否则你会以为服务没起来。
  • Restart=on-failure 只在非零退出时拉起;若希望被 kill -9 后也自动恢复,可以改成 Restart=always。

权限也要同步改好:

sudo chown -R www-data:www-data /opt/demo-service

3. 加载、启动和确认状态

sudo systemctl daemon-reload
sudo systemctl enable --now demo-py.service
systemctl status demo-py.service --no-pager
journalctl -u demo-py.service -f

enable --now 会同时写入开机启动并立即拉起服务。看到 active (running),并且日志里每隔十秒出现 heartbeat,就说明单元已经工作。

常用操作可以记这几条:

sudo systemctl restart demo-py.service
sudo systemctl stop demo-py.service
sudo systemctl disable demo-py.service
journalctl -u demo-py.service -n 100 --no-pager

4. 排障时先看这三处把一段 Python 脚本变成开机自启、崩溃可拉起的后台服务。

服务起不来,先不要改代码。按这个顺序看:

# 单元文件语法是否有误
systemd-analyze verify /etc/systemd/system/demo-py.service

# 最近一次启动失败原因
systemctl status demo-py.service -l --no-pager
journalctl -u demo-py.service -n 50 --no-pager

我实际碰到过三类问题:

  1. ExecStart 写成了 python3 app.py,工作目录虽然对,但 PATH 里没有虚拟环境,结果直接 exit 1。应写绝对路径,或在 Environment=PATH=... 里补上 venv。
  2. 目录属主还是 root,User=www-data 后脚本无法写运行时文件。ProtectSystem=full 会把 /usr 和 /boot 变成只读,数据文件应放在 /var/lib 或服务自己的目录。
  3. 改完 unit 忘记 daemon-reload,systemd 仍在用旧配置,表现为“我明明改了却不生效”。

如果服务能起来但隔几秒就重启,用 systemctl show demo-py.service -p NRestarts,Result,ExecMainStatus 看退出码,再对照脚本里是否把普通逻辑异常直接 sys.exit(1) 了。

5. 一点可落地的建议

对于只有一个进程的小型 Python 服务,systemd 已经够用:开机自启、失败重启、日志查询都能在系统内完成。等后面要加定时任务,可以再补一个 demo-py.timer;如果要限制 CPU 或内存,给 unit 加上 CPUQuota=、MemoryMax= 即可,不必先上容器。

先把“能启动、能看日志、能自动拉起”这三件事做稳,再把真正的业务脚本替换进去,比一开始就堆很复杂的部署方案更不容易返工。

部署前可以用一台空闲虚拟机先演练一遍:先手动前台运行 python3 /opt/demo-service/app.py,确认脚本本身没有 ImportError,再交给 systemd 托管。两者日志格式不一致时,优先相信 journalctl。等服务稳定后,再把心跳间隔、重启策略按业务调整,避免刚上线就在生产环境里反复试错。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。