supervisor —— 非 systemd 场景的进程守护

运维工具手册 05-服务与计划任务 7.3 KB 原文

supervisor —— 非 systemd 场景的进程守护

分类:05 服务与计划任务 适用:Linux / macOS(Python 实现),老系统、容器内、无 systemd 环境 一句话:把任意前台脚本变成"挂了自动拉起、能统一启停看日志"的托管服务。

1. 它解决什么问题

  • CentOS 6 或容器里没有 systemd,脚本挂了没人管。
  • 一台机器上跑十几个 Python/Node 小任务,想要一个面板统一管理。
  • 需要把进程的 stdout 自动切成日志文件并轮转。
  • 非 root 用户管理自己的进程组。

不适合:有 systemd 的现代 Linux 上管理正式服务——直接用 systemd 更可靠。

2. 安装

# Python 环境(推荐 pip,版本新)
python3 -m pip install supervisor

# 发行版
apt install -y supervisor
dnf install -y supervisor

配置文件位置:

安装方式 主配置 子配置目录
apt /etc/supervisor/supervisord.conf /etc/supervisor/conf.d/
pip /etc/supervisord.conf(需自己生成) 自定义
源码 同 pip

生成默认配置:

echo_supervisord_conf > /etc/supervisord.conf

3. 启动方式

# 有 systemd 的系统(用它托管 supervisor 自身)
systemctl enable --now supervisor

# 无 systemd
supervisord -c /etc/supervisord.conf
supervisorctl -c /etc/supervisord.conf status

# 前台运行(容器内作 PID 1)
supervisord -n -c /etc/supervisord.conf

容器里用 -n(nodaemon)让 supervisord 在前台,否则容器会立刻退出。

4. 配置结构

; /etc/supervisord.conf
[unix_http_server]
file=/var/run/supervisor.sock
chmod=0700

[supervisord]
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
childlogdir=/var/log/supervisor
loglevel=info
nodaemon=false

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock

[include]
files = /etc/supervisor/conf.d/*.conf

单个程序

; /etc/supervisor/conf.d/myapp.conf
[program:myapp]
command=/opt/app/venv/bin/python /opt/app/main.py --port 8080
directory=/opt/app
user=app
autostart=true
autorestart=true
startsecs=5
startretries=3
stopwaitsecs=30
stopsignal=TERM
environment=PYTHONUNBUFFERED="1",TZ="Asia/Shanghai",DATABASE_URL="mysql://..."
stdout_logfile=/var/log/supervisor/myapp.out.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=5
stderr_logfile=/var/log/supervisor/myapp.err.log
stderr_logfile_maxbytes=50MB
stderr_logfile_backups=5
redirect_stderr=false
priority=100

关键字段

字段 作用 建议
command 启动命令 必须前台运行,不能自己 daemonize
directory 工作目录 避免相对路径问题
user 运行用户 生产别用 root
autostart supervisord 启动时自动起 true
autorestart 退出后重启 true / unexpected / false
startsecs 启动后存活多少秒算成功 5~10,太短会误判
startretries 启动失败重试次数 3
stopwaitsecs 停止时等待优雅退出 按业务,30
stopsignal 停止信号 一般 TERM
environment 环境变量 用逗号分隔,值要引号
stdout_logfile 标准输出日志 必须配,否则可能丢失
maxbytes/backups 日志轮转 50MB × 5
redirect_stderr stderr 合并到 stdout 不配则分文件
priority 启动顺序(小先起) 有依赖时用
numprocs 启动几个实例 配合 process_name=%(program_name)s_%(process_num)02d
umask 文件权限掩码 022

多实例

[program:worker]
command=/opt/app/worker
process_name=%(program_name)s_%(process_num)02d
numprocs=4
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/worker-%(process_num)02d.log

分组(统一启停)

[group:backend]
programs=myapp,worker
priority=999

之后可以 supervisorctl restart backend:*。

5. supervisorctl

supervisorctl status                    # 所有程序状态
supervisorctl status myapp
supervisorctl start myapp
supervisorctl stop myapp
supervisorctl restart myapp
supervisorctl restart all
supervisorctl update                    # 应用配置变更(增删程序)
supervisorctl reread                    # 只读配置,不应用
supervisorctl reload                    # 重启 supervisord 本身(会重启所有子进程)
supervisorctl tail -f myapp stderr      # 跟踪错误日志
supervisorctl tail -100 myapp stdout    # 最近 100 行
supervisorctl clear myapp               # 清空日志文件
supervisorctl pid myapp
supervisorctl signal HUP myapp
supervisorctl avail                     # 未加载的配置

status 输出:

myapp        RUNNING   pid 1234, uptime 1 day, 3:12:45
worker:00    FATAL     Exited too quickly (process log may have details)
状态 含义
RUNNING 正常
STARTING 启动中(startsecs 内)
BACKOFF 启动失败,正在重试
FATAL 重试次数用尽,放弃
STOPPED 已停止
EXITED 正常退出(autorestart=false)
UNKNOWN 状态异常,通常 supervisord 与子进程失联

6. 增删改程序的正确流程

# 1. 新增/修改 /etc/supervisor/conf.d/xxx.conf
# 2. 读取新配置
supervisorctl reread
# 3. 应用(会启动新增的、停掉删除的、重启改动的)
supervisorctl update
# 4. 验证
supervisorctl status

只 reread 不 update 不会生效,这是最常见的操作失误。

7. 实战场景

7.1 托管一个 Python 服务

[program:api]
command=/opt/api/venv/bin/gunicorn -w 4 -b 0.0.0.0:8000 app:app
directory=/opt/api
user=api
environment=PATH="/opt/api/venv/bin:%(ENV_PATH)s",PYTHONUNBUFFERED="1"
autostart=true
autorestart=true
startsecs=10
stopwaitsecs=30
stdout_logfile=/var/log/api/access.log
stderr_logfile=/var/log/api/error.log

%(ENV_PATH)s 引用 supervisord 进程的 PATH。

7.2 容器内多进程

Dockerfile:

RUN apt-get update && apt-get install -y supervisor && rm -rf /var/lib/apt/lists/*
COPY supervisord.conf /etc/supervisor/conf.d/app.conf
CMD ["supervisord", "-n", "-c", "/etc/supervisord.conf"]
[supervisord]
nodaemon=true
logfile=/dev/stdout
logfile_maxbytes=0
pidfile=/tmp/supervisord.pid

[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true

[program:app]
command=/opt/app/server
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true

容器最佳实践仍是"一个容器一个进程"。用 supervisor 是折中,注意信号转发问题(见坑 8)。

7.3 失败自动拉起并留证

[program:crawler]
command=/opt/crawler/run.sh
autorestart=true
startretries=10
startsecs=3
stdout_logfile=/var/log/crawler/out.log
stderr_logfile=/var/log/crawler/err.log

FATAL 时先看 err.log,再 supervisorctl clear crawler + start。

7.4 用 HTTP 接口远程管理

[inet_http_server]
port=127.0.0.1:9001
username=admin
password=StrongPass

浏览器访问 http://127.0.0.1:9001。只绑 127.0.0.1,要远程访问走 SSH 隧道,别暴露公网。

8. 常见坑

  1. 程序自己 daemonize:supervisor 要求前台运行,程序 fork 到后台会被判定"启动后立即退出"。加 -g "daemon off;"(nginx)或 --nodaemon。
  2. reread 后没 update:配置不生效。
  3. command 用相对路径:找不到可执行文件,FATAL。写绝对路径。
  4. 环境变量没继承:PATH、JAVA_HOME、代理都要在 environment 里显式给。
  5. startsecs 太短:程序启动需要 20 秒,设 5 秒会不停重启。
  6. 日志不轮转:不配 maxbytes/backups 会把磁盘写满。supervisor 自己轮转,不要再用 logrotate 管同一文件。
  7. redirect_stderr=true 后 stderr 文件不生成:正常,错误都进 stdout 文件了。
  8. 容器里信号转发:supervisord 作 PID 1 时,docker stop 的 SIGTERM 由它接收,需配置 stopsignal 并确保子进程能优雅退出,否则 10 秒后被 SIGKILL。
  9. user= 需要 root 启动:supervisord 以普通用户运行时无法切换用户。
  10. supervisorctl reload 会重启所有进程:生产用 reread + update。
  11. unix_http_server 权限:socket 权限不对时 supervisorctl 报 Permission denied,配 chmod=0700 并用同用户执行。
  12. SELinux:/var/log/supervisor 上下文不对会写不进日志,restorecon -Rv 修复。
  13. Python 3.12+ 兼容:老版本 supervisor 4.2 之前有兼容问题,升级到 4.2.5+。
  14. numprocs 改了要 update,不是 restart。

9. 速查表

# 安装与启动
pip install supervisor
echo_supervisord_conf > /etc/supervisord.conf
supervisord -c /etc/supervisord.conf
systemctl enable --now supervisor

# 管理
supervisorctl status
supervisorctl start|stop|restart <name>
supervisorctl restart all
supervisorctl reread && supervisorctl update      # 改配置的标准流程
supervisorctl reload                              # 重启 supervisord(慎用)
supervisorctl tail -f <name> stderr
supervisorctl clear <name>
supervisorctl avail

# 配置要点
# command 用绝对路径且前台运行
# autostart=true autorestart=true startsecs=5
# 配 stdout_logfile + maxbytes + backups
# environment 显式声明变量
supervisor —— 非 systemd 场景的进程守护 - 知识库 - 起航社区