Supervisor安装与配置

目录
  1. 1. 安装
  2. 2. supervisord 配置
  3. 3. program 配置
  4. 4. 使用 supervisorctl 客户端命令
  5. 5. 其他

Supervisor是一个用Python写的进程管理工具,可以很方便的用来启动、重启、关闭进程(不仅仅是Python进程)。除了对单个进程的控制,还可以同时启动、关闭多个进程,比如很不幸的服务器出问题导致所有应用程序都被杀死,此时可以用 supervisor 同时启动所有应用程序而不是一个一个地敲命令启动。

安装

当前Supervisor的最高版本是3.0,之前尝试使用2.x版本管理实验集群中的若干mdrill进程,发现使用客户端无法有效启动和停止服务器端管理的各个子进程,从网上搜索错误发现2.x版本有一些bug,建议升级到3.0版本。因此我卸载了2.x版本,重新安装了3.0版本,发现3.0版本很好使。3.0版本相对2.x版本,配置文件不同部分的配置项都发生了变化,详见官方文档。

1
2
sudo yum install python-setuptools-devel
easy_install supervisor 或 sudo pip install supervisor

使用pip安装时提示:Supervisor is known to work with Python 2.4 or later but will not work under any version of Python 3.
解决方案:更改安装方式
1.获取supervisor包:【https://pypi.python.org/pypi/supervisor】
wget https://pypi.python.org/packages/80/37/964c0d53cbd328796b1aeb7abea4c0f7b0e8c7197ea9b0b9967b7d004def/supervisor-3.3.1.tar.gz
2.解压supervisor-3.3.1.tar.gz 并安装
tar zxvf supervisor-3.3.1.tar.gz && cd supervisor-3.3.1
python setup.py install

如果是 Ubuntu 系统,还可以使用 apt-get 安装
apt-get install supervisor

supervisord 配置

Supervisor 相当强大,提供了很丰富的功能,不过我们可能只需要用到其中一小部分。安装完成之后,可以编写配置文件,来满足自己的需求。为了方便,我们把配置分成两部分:supervisord(supervisor 是一个 C/S 模型的程序,这是 server 端,对应的有 client 端:supervisorctl)和应用程序(即我们要管理的程序)。
首先来看 supervisord 的配置文件。安装完 supervisor 之后,可以运行echo_supervisord_conf
命令输出默认的配置项,也可以重定向到一个配置文件里:
echo_supervisord_conf > /etc/supervisord.conf

去除里面大部分注释和“不相关”的部分,注释符号为分号,我们可以先看这些配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[unix_http_server]
file=/tmp/supervisor.sock ; UNIX socket 文件,supervisorctl 会使用
;chmod=0700 ; socket 文件的 mode,默认是 0700
;chown=nobody:nogroup ; socket 文件的 owner,格式: uid:gid

;[inet_http_server] ; HTTP 服务器,提供 web 管理界面
;port=127.0.0.1:9001 ; Web 管理后台运行的 IP 和端口,如果开放到公网,需要注意安全性
;username=user ; 登录管理后台的用户名
;password=123 ; 登录管理后台的密码

[supervisord]
logfile=/tmp/supervisord.log ; 日志文件,默认是 $CWD/supervisord.log
logfile_maxbytes=50MB ; 日志文件大小,超出会 rotate,默认 50MB
logfile_backups=10 ; 日志文件保留备份数量默认 10
loglevel=info ; 日志级别,默认 info,其它: debug,warn,trace
pidfile=/tmp/supervisord.pid ; pid 文件
nodaemon=false ; 是否在前台启动,默认是 false,即以 daemon 的方式启动
minfds=1024 ; 可以打开的文件描述符的最小值,默认 1024
minprocs=200 ; 可以打开的进程数的最小值,默认 200

; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; 通过 UNIX socket 连接 supervisord,路径与 unix_http_server 部分的 file 一致
;serverurl=http://127.0.0.1:9001 ; 通过 HTTP 的方式连接 supervisord

; 包含其他的配置文件
[include]
files = relative/directory/*.ini ; 可以是 *.conf 或 *.ini

我们把上面这部分配置保存到/etc/supervisord.conf(或其他任意有权限访问的文件),然后启动 supervisord(通过-c选项指定配置文件路径,如果不指定会按照这个顺序查找配置文件:$CWD/supervisord.conf, $CWD/etc/supervisord.conf, /etc/supervisord.conf):

supervisord -c /etc/supervisord.conf 或 supervisord

program 配置

上面我们已经把 supervisrod 运行起来了,现在可以添加我们要管理的进程的配置文件。可以把所有配置项都写到 supervisord.conf 文件里,但并不推荐这样做,而是通过 include 的方式把不同的程序(组)写到不同的配置文件里。
为了举例,我们新建一个目录/etc/supervisor/用于存放这些配置文件,相应的,把 /etc/supervisord.conf里 include 部分的的配置修改一下,支持自定义路径:

1
2
[include]
files = /etc/supervisor/*.conf

现在编写一份配置文件来管理这个进程,自定义栗子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[program:flume]
directory = /export/flume/apache-flume-1.6.0-bin/
command = nohup bin/flume-ng agent -c conf -f conf/flume.conf -n agent -Dflume.root.logger=INFO,console > /dev/null 2>&1 &
autostart = true
startsecs = 5
autorestart = true
startretries = 3
user = root
redirect_stderr = true
stdout_logfile_maxbytes = 20MB
stdout_logfile_backups = 10
stdout_logfile = /export/flume/logs/sup_flume_stdout.log
;IT will stop all processes including child process
stopasgroup=true

栗子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[program:usercenter]
directory = /home/leon/projects/usercenter ; 程序的启动目录
command = gunicorn -c gunicorn.py wsgi:app ; 启动命令,可以看出与手动在命令行启动的命令是一样的
process_name=%(program_name)s ; process_name expr (default %(program_name)s)
numprocs=1 ; number of processes copies to start (def 1)
autostart = true ; 在 supervisord 启动的时候也自动启动
startsecs = 1 ; 启动 1 秒后没有异常退出,就当作已经正常启动了
autorestart = true ; 程序异常退出后自动重启
startretries = 3 ; 启动失败自动重试次数,默认是 3
user = leon ; 用哪个用户启动
redirect_stderr = true ; 把 stderr 重定向到 stdout,默认 false
stdout_logfile_maxbytes = 20MB ; stdout 日志文件大小,默认 50MB
stdout_logfile_backups = 10 ; stdout 日志文件备份数
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile = /data/logs/usercenter_stdout.log
;这一配置项的作用是:如果supervisord管理的进程px又产生了若干子进程,使用supervisorctl停止px进程,停止信号会传播给px产生的所有子进程,确保子进程也一起停止。这一配置项对希望停止所有进程的需求是非常有用的。
stopasgroup=true

; 可以通过 environment 来添加需要的环境变量,一种常见的用法是修改PYTHONPATH ;process environment additions
; environment=PYTHONPATH=$PYTHONPATH:/path/to/somewhere

有几个配置项值得解释一下,可以根据需要自行设置。

1.stopasgroup=true。这一配置项的作用是:如果supervisord管理的进程px又产生了若干子进程,使用supervisorctl停止px进程,停止信号会传播给px产生的所有子进程,确保子进程也一起停止。这一配置项对希望停止所有进程的需求是非常有用的。
2.autostart=true。这一配置项的作用是:当启动supervisord的时候会将该配置项设置为true的所有进程自动启动。
3.一份配置文件至少需要一个[program:x]部分的配置,来告诉 supervisord 需要管理那个进程。[program:x]语法中的 x 表示 program name,会在客户端(supervisorctl 或 web 界面)显示,在 supervisorctl 中通过这个值来对程序进行 start、restart、stop 等操作。

启动supervisor进程后,可以配置通过web界面查看,效果如下:

出于安全考虑,默认配置是没有开启web管理界面,需要修改supervisord.conf配置文件打开http访权限,将下面的配置:

1
2
3
4
;[inet_http_server]         ; inet (TCP) server disabled by default
;port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface)
;username=user ; (default is no username (open server))
;password=123 ; (default is no password (open server))

修改成:

1
2
3
4
[inet_http_server]         ; inet (TCP) server disabled by default
port=0.0.0.0:9001 ; (ip_address:port specifier, *:port for all iface)
username=user ; (default is no username (open server))
password=123 ; (default is no password (open server))

确保配置无误后可以在每台主机上使用下面的命令启动supervisor的服务器端supervisord
【启动supervisord】  
supervisord -c /etc/supervisord.conf 或 supervisord

【停止supervisord】
supervisorctl shutdown

【重新加载配置文件】
supervisorctl reload

【进程管理】
1.启动supervisord管理的所有进程
supervisorctl start all

2.停止supervisord管理的所有进程
supervisorctl stop all

3.启动supervisord管理的某一个特定进程
supervisorctl start program-name // program-name为[program:xx]中的xx

4.停止supervisord管理的某一个特定进程
supervisorctl stop program-name // program-name为[program:xx]中的xx

5.重启所有进程或所有进程
supervisorctl restart all // 重启所有supervisorctl reatart program-name // 重启某一进程,program-name为[program:xx]中的xx

6.查看supervisord当前管理的所有进程的状态
supervisorctl status

使用 supervisorctl 客户端命令

Supervisorctl 是 supervisord 的一个命令行客户端工具,启动时需要指定与 supervisord 使用同一份配置文件,否则与 supervisord 一样按照顺序查找配置文件
supervisorctl -c /etc/supervisord.conf

上面这个命令会进入 supervisorctl 的 shell 界面,然后可以执行不同的命令了:

1
2
3
4
5
6
> status    # 查看程序状态
> stop usercenter # 关闭 usercenter 程序
> start usercenter # 启动 usercenter 程序
> restart usercenter # 重启 usercenter 程序
> reread # 读取有更新(增加)的配置文件,不会启动新添加的程序
> update # 重启配置文件修改过的程序

上面这些命令都有相应的输出,除了进入 supervisorctl 的 shell 界面,等同于直接在 bash 终端运行:

1
2
3
4
5
6
$ supervisorctl status
$ supervisorctl stop usercenter
$ supervisorctl start usercenter
$ supervisorctl restart usercenter
$ supervisorctl reread
$ supervisorctl update

其他

除了supervisorctl之外,还可以配置supervisrod启动web管理界面,这个web后台使用Basic Auth的方式进行身份认证。
除了单个进程的控制,还可以配置group,进行分组管理。
经常查看日志文件,包括supervisord的日志和各个pragram的日志文件,程序crash或抛出异常的信息一半会输出到stderr,可以查看相应的日志文件来查找问题。

1.遇到问题及解决方案
在使用命令supervisorctl start all启动控制进程时,遇到如下错误
unix:///tmp/supervisor.sock no such file

出现上述错误的原因是supervisord并未启动,只要在命令行中使用命令sudo supervisord启动supervisord即可。

2.遗留问题
当集群规模扩大后,登录到每台主机使用supervior控制进程也是很麻烦的,能不能用一台主机作为客户端,同时连接集群中的所有主机,以一种中心化的方式统一管理集群中的所有进程?之前一直使用的方式是使用交互式工具expect。supervisor本身有没有提供一种机制实现集群中所有进程的中央化管理?

目前测试成功的是使用一台主机作为客户端(supervisorctl),控制另一台服务器(supervisord)主机上的状态。方法是在服务器端配置[inet_http_server]部分,开启TCP端口监听。客户端配置[supervisorctl]部分,指定服务器端的serverurl,连接服务器端监听的端口。但是一个客户端只能连接一个服务器,无法指定多个服务器。

3.管理Nginx
supervisord还要求管理的程序是非daemon程序,supervisord会帮你把它转成daemon程序,因此如果用supervisord来管理nginx的话,必须在nginx的配置文件里添加一行设置daemon off让nginx以非daemon方式启动。

1
2
3
4
5
6
7
8
9
10
11
[program:up_nginx]
command=/usr/sbin/nginx
process_name=%(program_name)s
numprocs=4 ; 启动几个进程
autostart=true ; 随着supervisord的启动而启动
autorestart=true ; 自动重启。。当然要选上了
startretries=10 ; 启动失败时的最多重试次数
exitcodes=0 ; 正常退出代码(是说退出代码是这个时就不再重启了吗?待确定)
stopsignal=KILL ; 用来杀死进程的信号
stopwaitsecs=10 ; 发送SIGKILL前的等待时间
redirect_stderr=true ; 重定向stderr到stdout

当然除了此处配置完成后就可以启动了。但是这样的话会有一个问题,就是当你是使用supervisorctl status来查看你这个程序的状态时,你发现它不是running的状态,这是因为supervisor只是对于不能自动生成后台进程的程序有效,当启动nginx的命令执行完成后将会退出,所以我们需要再nginx的配置文件中加入:daemon off;


php脚本执行报BACKOFF Exited too quickly (process log may have details)错误解决:
对于执行时间很短的php脚本,点击进程执行会报以上错误

1
2
3
4
5
6
7
8
9
10
11
12
<?php
require 'db.class.php';

$dbHost = 'localhost';
$dbUser = 'xxxxxx';
$dbPasswd = 'xxxxxx';
$dbName = 'test';

$pdo = db::getInstance($dbHost, $dbUser, $dbPasswd, $dbName);
$pdo->insert('test', ['name' => 'wml']);

sleep(2); #在php脚本最后一行加上一句,可解决该问题

Supervisor 有很丰富的功能,还有其他很多项配置,可以在官方文档获取更多信息:http://supervisord.org/index.html
参考资料-使用supervisor管理进程

扩展阅读:
Supervisor安装与配置(Linux/Unix进程管理工具)
supervisor 使用及管理nginx+gunicorn
Linux后台进程管理工具:Supervisor