Supervisor 是一个用于管理和监控进程的工具,像 Gunicorn 创建的 WSGI,也可以通过 Supervisor 进行管理。

安装

  • apt: apt install supervisor

安装完成后,有三个执行文件:

  • echo_supervisord_conf: 用于生成配置
  • supervisorctl: 命令行控制
  • supervisord: 守护进程

配置

supervisord.conf

如果使用 apt 或者是 yum 等方式安装,一般会在默认位置生成配置,这次我们只需要在 include 增加目录即可。

# 在项目根目录生成配置
echo_supervisord_conf > supervisord.conf
# 或者使用默认路径
echo_supervisord_conf > /etc/supervisor/supervisord.conf
# 然后打开生成的配置文件,找到最后两行取消注释,并更改 files 路径
[include]
files = conf/*.conf # conf 目录和对应文件需要手动创建
 
# 如果想通过 Web 界面管理进程,可在这里配置
[inet_http_server]
port=:9001
username=username
password=password

server.conf

默认地址: /etc/supervisor/conf.d/

最小化配置

[program: sanic]                   ; program 后面是服务名 不能重复
command=/usr/bin/python3 server.py ; 要运行的 Python 文件
stdout_logfile=log/%(program_name)s.log       ; 日志输出文件
stderr_logfile=log/%(program_name)s.error.log ; 错误日志输出文件
[program: myweb]
user=immwind                        ; 指定用户来启动该进程
directory=/home/developer/demo      ; 执行 command 之前,先切换到指定目录
command=/usr/bin/python server.py   ; 要运行的 Python 文件
numprocs=1                          ; 默认为1
process_name=%(program_name)s
autorestart=true                    ; 意外退出时重启,默认 true,3次
redirect_stderr=true                ; 重定向输出日志,默认 false
stdout_logfile=log/server.log       ; 日志输出文件
loglevel=info                       ; 日志级别
  • log 目录必须提前创建
  • 设定环境变量: environment=KEY=“value”
    • 引用环境变量: {KEY}
    • Python 内调用 os.environ[‘KEY’]

命令

服务管理

supervisorctl shutdown               # 停止服务
 
# service
sudo service supervisor stop
sudo service supervisor start
 
# systemctl
sudo systemctl stop supervisor
sudo systemctl restart supervisor

进程管理

进程的起停不会载入最新的配置

# program_name 为前面配置的进程名称
supervisorctl stop program_name    # 停止指定进程
supervisorctl start program_name   # 启动
supervisorctl restart program_name # 重启
# 停止所有进程
supervisorctl stop all
 
# 查看所有进程状态 (也支持查看当个进程状态)
supervisorctl status
 
# 停止所有进程,并使用最新配置启动
supervisorctl reload
# 重启配置变更为的进程(未变更过的不影响)
supervisorctl update
 
# 重新读取配置文件
supervisorctl reread

报错

unix:///tmp/supervisor.sock no such file

这个报错一般是 /etc/supervisor/supervisord.conf[unix_http_server] -> file 的值不是 /tmp/supervisor.sock 导致

另一个碰到类似报错是 log 目录未创建导致:unix:///var/run/supervisor.sock no such file。

加入 Supervisor 管理

如果是通过 pip 安装,可能会遇到需要假如 Supervisor 的情况:

[Unit]
Description=API daemon

[Service]
ProtectHome=false
Type=forking
ExecStart=/usr/local/bin/supervisord -c /home/username/ipc/supervisord.conf
ExecStop=/usr/local/bin/supervisorctl shutdown
ExecReload=/usr/local/bin/supervisorctl reload
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target

拷贝文件: sudo cp supervisord.service /usr/lib/systemd/system/

  • 重新加载:sudo systemctl daemon-reload
  • 开机自启: sudo systemctl enable <service>

说明

命令示例

; The below sample program section shows all possible program subsection values,
; create one or more 'real' program: sections to be able to control them under
; supervisor.

;[program:theprogramname]
;command=/bin/cat              ; 指定要运行的命令
;process_name=%(program_name)s ; 指定进程名称(默认是 %(program_name)s),这个名称与“numprocs”的值有关,如果“numprocs=1”说明只给它开一个进程,一个进程的名称直接跟“program_name”相同即可(program_name就是中括号中“program:”后面那个名称),但如果“numprocs”不等于1,也就是进程不只有一个,那就不能写“%(program_name)s ”了,因为多个进程的名称明显不能相同。具体怎样写,由于我刚开始用,还没研究。
;numprocs=1                    ; 指定进程数,默认为1
;directory=/tmp                ; 执行程序前要切换到的目录
;umask=022                     ; 进程创建的文件拥有的权限(注意不是进程本身的权限,而是进程生成的文件,比如进程会产生log文件,这个umask的值就是这个log文件的权限)
;priority=999                  ; 优先级,因为supervisor可以管理很多程序,即我们可以配置先多个[program:redis],[program:nginx]等等,因为有多个,那么程序启动就要分先后,这个priority就是指定先后的,数字越小,优先级越高。 (默认 999)
;autostart=true                ; 是否自动启动?自动启动的意思是当启动supervisord守护进程的时候,是否要启动该程序 (默认: true)
;autorestart=true              ; 如果程序运行过程中意外退出了,是否要自动重启它? (默认: true)
;startsecs=10                  ; 指定程序启动后要保持启动状态几秒才能认为它确实已经启动成功了 (默认1秒),因为有些程序可能由于某些原因,启动两三秒后又突然退出,这显然不能认为已经启动了。
;startretries=3                ; 如果启动失败重试的次数 (默认 3次)
;exitcodes=0,2                 ; '期望的' 进程退出码 (默认为 0,2)
;stopsignal=QUIT               ; 进程停止信号,可以为TERM, HUP, INT, QUIT, KILL, USR1, or USR2等信号(Linux的知识),默认为TERM ,当用设定的信号去干掉进程,退出码会被认为是expected的,即会被认为是正常退出(比如你执行了stop),而不是意外退出。 (默认 TERM)
;stopwaitsecs=10               ; 是当我们向子进程发送stopsignal信号后,到系统返回信息给supervisord,所等待的最大时间。 超过这个时间,supervisord会向该子进程发送一个强制kill的信号。 (默认10秒)
;user=chrism                   ; 设置以哪个用户去运行,这个我猜你必须要用root权限运行supervisord,这里的设置才有效
;redirect_stderr=true          ; 重定向标准错误输出到标准输出流 (默认 false)
;stdout_logfile=/a/path        ; 标准输出日志路径, 如果设置为“NONE”表示不指定,默认是“AUTO”
;stdout_logfile_maxbytes=1MB   ; 标准输出日志文件最大值,超过后会重新创建一个新的文件 (默认 50MB)
;stdout_logfile_backups=10     ; # 因为日志一直在输出,单个日志超过stdout_logfile_maxbytes设置的大小后,将会创建一个新文件接收日志,这样日志肯定会越来越多, stdout_logfile_backups配置项就是用于设置最多能有多少个日志文件,如果超出了,那么最先生成的文件将会被删除(默认 10)
;stdout_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false   ; 当设置为ture的时候,当子进程由stdout向文件描述符中写日志的时候,将触发supervisord发送PROCESS_LOG_STDOUT类型的event。 (默认 false)
;stderr_logfile=/a/path        ; 与stdout_logfile类似
;stderr_logfile_maxbytes=1MB   ; 与stdout_logfile_maxbytes类似 (默认 50MB)
;stderr_logfile_backups=10     ; # 与stdout_logfile_backups类似 (默认 10)
;stderr_capture_maxbytes=1MB   ;  这个东西是设定capture管道的大小,当值不为0的时候,子进程可以从stdout发送信息,而supervisor可以根据信息,发送相应的event。(默认 0,表示关闭管道)
;stderr_events_enabled=false   ; 设置为ture的时候,当子进程由stdout向文件描述符中写日志的时候,将触发supervisord发送PROCESS_LOG_STDOUT类型的event。(默认 false)
;environment=A=1,B=2           ; 这个是该子进程的环境变量,和别的子进程是不共享的 (默认无)
;serverurl=AUTO                ; override serverurl computation (childutils)

参考