Linux · 运维 · Supervisor
用 Supervisor 守护你的后台进程
从安装、配置到日常运维,快速掌握如何用 Supervisor 管理 Python、Node.js 等长期运行的服务。
手动在终端里启动一个 Web 服务很直接:运行命令,看到日志,服务就起来了。但 SSH 连接断开、进程异常退出或机器重启后,服务往往也随之消失。对于还没有接入 systemd、容器编排平台的小型服务,Supervisor 是一个简单可靠的进程守护工具。
它负责启动指定命令、观察进程状态、在需要时重启进程,并把标准输出和错误输出写入日志。它并不替代 Nginx、数据库或发布系统;更适合用来管理常驻的应用进程、队列消费者和定时任务。
安装与启动
Supervisor 通常通过 Python 包管理器安装。建议在系统 Python 或专门的运维虚拟环境中安装,避免依赖某个应用自己的虚拟环境:
python3 -m pip install supervisor
安装后先生成一份默认配置,再按发行版习惯将它放到 /etc/supervisord.conf 或其他统一的位置:
echo_supervisord_conf > supervisord.conf
supervisord -c supervisord.conf
supervisorctl -c supervisord.conf status
许多 Linux 发行版也提供系统包。通过系统包装好后,服务名、默认配置路径和开机启动方式可能不同;先查看该发行版的包说明或 systemd 单元文件,不要混用两套配置。
配置一个程序
实际项目中,通常保留主配置文件,只把每个程序写成独立的 conf.d/*.conf 文件,再通过 [include] 统一加载:
; /etc/supervisor/conf.d/my-api.conf
[program:my-api]
directory=/srv/my-api
command=/srv/my-api/.venv/bin/gunicorn app:app --bind 127.0.0.1:8000
user=www-data
autostart=true
autorestart=unexpected
startsecs=5
startretries=3
stdout_logfile=/var/log/supervisor/my-api.log
stderr_logfile=/var/log/supervisor/my-api-error.log
environment=APP_ENV="production",PORT="8000"
主配置中加入下面的片段即可加载该目录:
[include]
files = /etc/supervisor/conf.d/*.conf
几个字段尤其重要:
command是实际执行的命令。尽量使用解释器和可执行文件的绝对路径,避免 Supervisor 的环境变量与交互式 shell 不一致。directory指定工作目录;应用依赖相对路径、.env或资源文件时很有用。user让进程以低权限账户运行。除非确有必要,不要让应用长期以 root 身份运行。autostart控制 supervisord 启动时是否拉起程序;autorestart=unexpected表示仅在非预期退出时重启。startsecs要求进程至少存活一段时间才算启动成功;对启动即退出的脚本尤其有帮助。environment用于补充必要环境变量。含逗号或引号的值需要遵守 INI 的转义规则,复杂配置更适合放入应用自己的配置文件。
对于 Node.js 服务,同样的思路适用,只需把 command 改为 Node 的绝对路径和启动脚本,例如 /usr/bin/node /srv/my-app/dist/server.js。
让配置生效
修改或新增配置后,按下面的顺序操作:
supervisorctl reread
supervisorctl update
supervisorctl status
reread 只重新扫描配置,并不启动或停止任何进程;update 才会根据差异添加新程序、移除已删除的程序,并重启发生配置变化的程序。把两者分开执行,有助于在生产环境确认变更范围。
日常控制命令也很直观:
supervisorctl status
supervisorctl start my-api
supervisorctl restart my-api
supervisorctl stop my-api
supervisorctl tail -f my-api stderr
如果配置了组,还可以使用 group:* 一次操作整个组。例如将多个消费者放进 [group:workers],再运行 supervisorctl restart workers:*。
日志、退出码与重启策略
Supervisor 能重启进程,但不能判断业务是否健康。因此要把“进程还活着”和“服务可用”分开对待:前者由 Supervisor 负责,后者仍需要健康检查、监控与告警。
默认情况下,程序以退出码 0 退出会被视为预期退出。一个原本应长期运行的服务若因配置错误很快退出,startsecs 会让 Supervisor 将其认定为启动失败;超过 startretries 后,程序状态会变成 FATAL,避免无限快速重启。
常见日志排查顺序如下:
- 运行
supervisorctl status,确认程序是RUNNING、BACKOFF还是FATAL。 - 查看应用的
stderr_logfile,优先寻找启动命令、权限、端口占用和依赖缺失等错误。 - 查看 supervisord 自身日志,确认配置是否被加载、用户是否有权限创建日志文件。
- 在与配置相同的
user、directory和环境变量下手动执行command,缩小 Supervisor 与应用本身之间的问题边界。
日志文件会持续增长。生产环境应配合 logrotate,或使用集中式日志系统;不要仅依赖磁盘上的单个无限增长文件。
几个容易踩到的坑
- 不要依赖 shell 初始化文件。
supervisord通常不会加载.bashrc、.zshrc,因此nvm、pyenv或临时设置的PATH可能失效。使用绝对路径,或明确设置environment。 - 不要用它守护一次性任务。 数据迁移、备份这类完成后自然退出的命令更适合由 cron、systemd timer 或 CI 执行;否则自动重启会重复执行任务。
- 避免把敏感信息直接写进配置。 环境变量可能被具有读取权限的用户看到。密钥应使用权限受控的配置文件、密钥管理服务或部署平台的注入机制。
- 明确谁负责开机启动。 Supervisor 自身需要由 systemd 等系统初始化器拉起;确认
supervisord的服务单元已启用后,再验证机器重启后的恢复行为。
何时选择其他方案
在现代 Linux 服务器上,如果服务本身由 systemd 管理,直接编写 systemd unit 往往更贴合系统的日志、权限和依赖管理。若应用已经运行在 Docker、Kubernetes 或其他编排平台里,也应优先使用对应平台的重启策略与健康检查。
Supervisor 的价值在于它的配置简单、控制接口统一,并且能快速把多个普通命令变成可观察、可重启的后台服务。先让启动命令能在命令行稳定运行,再交给 Supervisor 守护,通常会是最顺畅的开始。