作为一名运维工程师,我每天都要和各种后台服务打交道。最让我头疼的就是那些需要手动启动的命令行程序——每次服务器重启都得重新敲一遍命令,程序崩溃了还得手动去查看日志、重新启动。直到我发现了 Supervisor 这个神器,这些问题才迎刃而解。
Supervisor 是一个用 Python 开发的进程管理工具,它能把普通的命令行程序变成守护进程(daemon),实现以下功能:
提示:Supervisor 特别适合管理那些没有内置 daemon 模式的应用,比如各种开源工具、自定义脚本等。
根据不同的 Linux 发行版,安装方式略有差异:
bash复制# Debian/Ubuntu 系
sudo apt update
sudo apt install -y supervisor
# RHEL/CentOS 系
sudo yum install -y epel-release
sudo yum install -y supervisor
安装完成后,建议设置开机自启:
bash复制sudo systemctl enable --now supervisor
安装完成后,关键目录如下:
code复制/etc/supervisor/
├── conf.d/ # 用户自定义配置目录
├── supervisord.conf # 主配置文件
└── supervisord.d/ # 可能存在的附加配置目录
注意:最佳实践是将每个程序的配置单独放在 conf.d 目录下,而不是直接修改主配置文件。这样既清晰又便于管理。
假设我们要管理一个 FRP 客户端,在 /etc/supervisor/conf.d/ 下新建 frpc.conf:
ini复制[program:frpc]
directory=/apps/frp/frp_0.63.0
command=/apps/frp/frp_0.63.0/frpc -c frpc.toml
autostart=true
startsecs=10
autorestart=true
startretries=3
user=root
priority=999
stopsignal=INT
redirect_stderr=true
stdout_logfile_maxbytes=500MB
stdout_logfile_backups=10
stdout_logfile=/apps/frp/frp_0.63.0/stdout.log
stopasgroup=true
killasgroup=true
进程组管理:
stopasgroup=true 和 killasgroup=true 确保停止时清理所有子进程日志管理:
maxbytes 和 backups 控制启动策略:
startsecs=10 给了程序足够的初始化时间startretries=3 防止无限重启消耗资源安全考虑:
user=frpuser)避坑指南:如果程序需要绑定 1024 以下端口,可以考虑用
capabilities而不是直接使用 root:bash复制sudo setcap 'cap_net_bind_service=+ep' /path/to/your/program
bash复制# 重新加载配置(新增/修改配置后必须执行)
sudo supervisorctl update
# 查看所有程序状态
sudo supervisorctl status
# 管理单个程序
sudo supervisorctl start program_name
sudo supervisorctl stop program_name
sudo supervisorctl restart program_name
批量操作:
bash复制sudo supervisorctl start all
sudo supervisorctl stop all
sudo supervisorctl restart all
日志查看:
bash复制sudo supervisorctl tail program_name
sudo supervisorctl tail -f program_name # 实时跟踪
重载配置:
bash复制sudo supervisorctl reread
sudo supervisorctl update
我习惯用环境变量来区分不同环境:
ini复制[program:myapp]
command=/usr/bin/env APP_ENV=%(ENV_APP_ENV)s /path/to/app
然后在启动 supervisor 前设置环境变量:
bash复制export ENV_APP_ENV=production
supervisord -n
对于可能消耗大量资源的程序,可以添加限制:
ini复制[program:memory_hungry]
command=/path/to/program
environment=MALLOC_ARENA_MAX=2 # 限制内存分配
priority=100 # 降低优先级
结合 startsecs 和自定义脚本实现健康检查:
ini复制[program:web_service]
command=/path/to/start_script.sh
startsecs=30
其中 start_script.sh 可以包含 curl 检查等逻辑。
检查日志:
bash复制sudo supervisorctl tail program_name
确认执行权限:
bash复制ls -l /path/to/program
测试直接运行:
bash复制sudo -u specified_user /path/to/program
确保执行了 update:
bash复制sudo supervisorctl update
检查配置文件语法:
bash复制sudo supervisorctl reread
查看主日志:
bash复制sudo tail -n 100 /var/log/supervisor/supervisord.log
检查退出代码:
bash复制sudo supervisorctl status
调整 startretries 和 autorestart 参数
考虑使用 stopwaitsecs 给程序更多退出时间
Supervisor 自带一个简单的 Web 管理界面,在 /etc/supervisor/supervisord.conf 中启用:
ini复制[inet_http_server]
port = 127.0.0.1:9001
username = youruser
password = yourpass
安全提示:生产环境建议:
- 只绑定到 127.0.0.1
- 使用强密码
- 通过 SSH 隧道访问:
bash复制ssh -L 9001:localhost:9001 your_server然后在本地访问 http://localhost:9001
虽然 Supervisor 很好用,但根据场景不同,也可以考虑:
| 工具 | 优势 | 劣势 |
|---|---|---|
| systemd | 系统原生支持,性能好 | 配置复杂,日志管理较弱 |
| Docker | 隔离性好,便于部署 | 资源开销大,不适合简单场景 |
| PM2 | Node.js 生态友好 | 主要面向 Node 应用 |
| Screen/Tmux | 简单易用 | 缺乏自动重启等高级功能 |
对于大多数传统服务管理场景,Supervisor 仍然是平衡性最好的选择。
在实际使用中,我总结了几个关键点:
日志轮转:一定要配置合理的日志大小和备份数,我曾经因为忘记设置导致磁盘被日志塞满。
用户权限:尽量使用非 root 用户运行,权限问题可以通过 setfacl 解决:
bash复制sudo setfacl -Rm u:appuser:rwx /path/to/directory
启动顺序:对于有依赖关系的服务,可以用 priority 参数控制启动顺序。
环境隔离:建议每个程序都明确设置 directory 和环境变量,避免意外。
监控集成:可以将 supervisorctl status 的输出接入到 Prometheus 等监控系统。
Supervisor 已经成为了我服务器上的标配工具,几乎管理着所有需要长期运行的服务。它的简单可靠让我可以更专注于业务本身,而不是这些基础服务的维护工作。