用 systemd 托管 Python 服务:开机自启、崩溃重启、日志托管

米阳 2023-2-11 4 2/11

以前用 nohup 跑服务,重启服务器就没了,进程崩了也没人管。systemd 是 Linux 自带的服务管理器,把这些事一次做完。

写一个 unit 文件

/etc/systemd/system/kb-web.service:

[Unit]
Description=KB Web Service
After=network.target

[Service]
Type=simple
User=www
WorkingDirectory=/www/blog-ai/app
Environment="PYTHONUNBUFFERED=1"
ExecStart=/www/blog-ai/.venv/bin/python -m uvicorn serve:app --host 127.0.0.1 --port 8800
Restart=always
RestartSec=3
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

几个关键项:

  • WorkingDirectory 必须写,否则相对路径(数据库文件、配置文件)全部找错
  • User 用非 root,减少被入侵后的影响面
  • Restart=always 崩溃自动拉起,RestartSec 防止疯狂重启
  • PYTHONUNBUFFERED=1 让 print 立即刷到日志,否则缓冲区里的内容看不到

启用

systemctl daemon-reload
systemctl enable --now kb-web
systemctl status kb-web

enable 是开机自启,--now 是立即启动。两个都要,很多人只 start 了,重启机器后发现服务没起来。

看日志

journalctl -u kb-web -f            # 实时
journalctl -u kb-web -n 100       # 最近 100 行
journalctl -u kb-web --since "10 min ago"
journalctl -u kb-web -p err        # 只看错误

比翻日志文件方便。默认日志会被 journald 轮转,不会把磁盘写满。

环境变量放哪

.env 文件可以用 EnvironmentFile:

EnvironmentFile=-/www/blog-ai/app/.env

前面的 - 表示文件不存在也不报错。注意 EnvironmentFile 的格式是 KEY=value,不能有 export,不能有引号包裹整个值(有些写法会带进变量里)。

.env 权限设成 600,只有服务用户能读。

常见故障

status 显示 failed,日志只有一行退出码:先手动跑一遍 ExecStart 那条命令,通常是路径错或依赖缺失。

改了代码要重启:

systemctl restart kb-web

改了 unit 文件没生效:忘了 daemon-reload。

服务起来但访问 502:多半是监听地址不对。127.0.0.1:8800 只能本机访问,Nginx 反代没问题;如果直接开公网端口,要 0.0.0.0——但不建议,让 Nginx 挡在前面更安全。

为什么不用 supervisor

supervisor 也能做同样的事,但 systemd 是系统自带的,不需要额外装 Python 环境,日志集成到 journalctl,开机自启天然支持。新项目我一律用 systemd。

- THE END -

米阳

2月11日09:50

最后修改:2023年2月11日
0

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论