Supervisor 基础

Supervisor

Supervisor 的官方标语是

A Process Control System

它是用 Python 实现的,不过它能管理任何非 Daemon 的进程,并会帮你把被管理的进程转成 Daemon 进程(只要你交给 Supervisor 的进程是非 daemon 的,无需在原程序中增加任何用于实现 daemon 的代码,就能实现 daemon)。

是不是感觉很方便?废话不多说,直接动手搞起来。

安装

安装 Supervisor 的方式多种多样,选择自己喜欢的方式吧

1
2
3
4
5
# easy_install supervisor        // yum install python-setuptools
# apt-cache show supervisor // ubuntu
# yum info supervisor // redhat centos
# pip install supervisor --pre // pip >= 1.4
# pip install supervisor // pip < 1.4

还可以直接去官网下载后,python setup.py install

配置

安装完成后执行如下命令生成默认的配置文件

1
# echo_supervisord_conf > /etc/supervisord.conf

如果没有 root 权限的话,可以随便放一个能放的位置,只不过启动的时候需要加-c指定配置文件的路径

1
2
$ echo_supervisord_conf > $HOME/supervisord.conf
$ supervisord -c $HOME/supervisord.conf

以下启动顺序,由上到下优先级依次递减

1
2
3
4
$ supervisord                             #默认去找$CWD/supervisord.conf,也就是当前目录
$ supervisord #默认$CWD/etc/supervisord.conf,也就当前目录下的etc目录
$ supervisord #默认去找/etc/supervisord.conf的配置文件
$ supervisord -c $HOME/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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#vim /etc/supervisord.conf

[unix_http_server] ; supervisord的unix socket服务配置
file=/var/tmp/supervisor.sock ; socket文件的保存目录
chmod=0777 ; socket的文件权限 (default 0700)
chown=root:root ; socket的拥有者和组名
;username=user ; 使用supervisorctl连接的时候认证的用户,非必须
;password=123 ; 可以直接使用明码,也可以使用SHA加密,如:{SHA}82ab876d1387bfafe46cc1c8a2ef074eae50cb1d
[inet_http_server] ; supervisord的tcp服务配置 Web管理界面设定
port=*:9001 ; tcp端口,ip_address:port specifier, *:port for all iface
username=user ; tcp登陆用户
password=123 ; tcp登陆密码

[supervisord] ; supervisord的主进程配置
logfile=/data/log/supervisor/main.log ; 主进程日志
logfile_maxbytes=50MB ; 最大日志体积,默认50MB,当超过50M的时候,会生成一个新的日志文件。当设置为0时,表示不限制文件大小
logfile_backups=10 ; 日志文件备份数目,默认10。当设置为0时,表示不限制文件的数量
loglevel=info ; 日志级别,默认info; 还有:critical, error, warn, debug, trace, blather
pidfile=/var/run/supervisord.pid ; supervisord的pidfile文件
nodaemon=false ; false: 以守护进程的方式启动 superviser
minfds=1024 ; 最少系统空闲的文件描述符,低于这个值supervisor将不会启动
minprocs=200 ; 最最小可用的进程描述符,低于这个值supervisor也将不会正常启动
;umask=022 ; 进程文件的umask,默认200
user=root ; 默认为当前用户,如果为root则必填。这个参数可以设置一个非root用户,
; 当我们以root用户启动supervisor之后,这里设置的这个用户,也可以对supervisor进行管理
;identifier=supervisor ; supervisord的表示符, 默认是'supervisor'。主要是给XML_RPC用的。
; 当有多个supervisor的时候,而且想调用XML_RPC统一管理,就需要为每个supervisor设置不同的标识符了
;directory=/tmp ; 当supervisor作为守护进程运行的时候,设置这个参数的话,启动主进程之前,会先切换到这个目录
nocleanup=true ; 当为false的时候,会在supervisord进程启动的时候,把以前子进程
; 产生的日志文件(路径为AUTO的情况下)清除掉。有时候咱们想要看历史日志,当
; 然不想日志被清除了。所以可以设置为true
childlogdir=/data/log/supervisor ; 当子进程日志路径为AUTO的时候,子进程日志文件的存放路径。
;environment=A="1",B="2" ; 可在这里可以设置supervisord进程特有的其他环境变量
; supervisord启动子进程时,子进程会拷贝父进程的内存空间内容。 所以设置的这些环境变量也会被子进程继承。
;strip_ansi=false ; 如果设置为true,会清除子进程日志中的所有 ANSI 序列

[supervisorctl] ; 针对supervisorctl的一些配置
serverurl=unix:///tmp/supervisor.sock ; 注意这个是和前面的[unix_http_server]对应的
serverurl=http://127.0.0.1:9001 ; 注意这个和前面的[inet_http_server]对应
username=user ; 如果设置应该与http_username相同
password=123 ; 如果设置应该与http_password相同
;prompt=mysupervisor ; 命令行提示符,默认"mysupervisor"
;history_file=~/.sc_history ; 命令行历史纪录,和shell中的history类似

; 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] ; 这个选项是给XML_RPC用的
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface


;[program:example] ; 管理的单个进程的配置,可以添加多个program
command=/bin/sh ~/example.sh ; 被监控程序指定的运行脚本
; 如果command的栏运行的是shell脚本,那么在shell脚本启动被监控程序时要用exec修饰
; 例如: echo $RUN_CMD
; eval exec $RUN_CMD
; 否则,supervisord停止不了启动的进程.此外,shell脚本里不能出现&之类的后台运行符号
;process_name=%(program_name)s ; 进程名表达式,默认为%(program_name)s,如果下面的numprocs参数为1的话,就不用管这个参数
;numprocs=1 ; 默认启动的进程数目,默认为1
;directory=/opt ; 进程运行前,会前切换到这个目录
;umask=022 ; 进程umask,默认None
priority=999 ; 程序运行的优先级,默认999
autostart=true ; 默认随supervisord自动启动,默认true
autorestart=true ; 被监控程序异常中断是否自动重启,有三个选项,false,unexpected和true。
; 为false时,无论什么情况下,都不会被重新启动,
; 为unexpected时,只有当进程的退出码不在下面的exitcodes里面定义的退出码的时候,才会被自动重启。
; 为true时,只要子进程挂掉,将会被无条件的重启
startsecs=5 ; 进程持续运行多久才认为是启动成功
startretries=3 ; 被监控程序启动失败重试的次数,默认3次,当超过3次后,supervisor将把此进程的状态置为FAIL
;exitcodes=0,2 ; 期望的退出码,默认0,2,即当退出码不为0或2时,认为是unexpected的。
;stopsignal=QUIT ; 进程停止信号,可以为TERM, HUP, INT, QUIT, KILL, USR1, USR2等,默认TERM
; 当用设定的信号去干掉进程,退出码会被认为是expected
;stopwaitsecs=10 ; 最长结束等待时间,否则使用 SIGKILL,默认10
;stopasgroup=false ; 向unix进程组发送停止信号,默认false,适用于supervisord管理的子进程本身还有子进程的情况
;killasgroup=false ; 向unix进程组发送SIGKILL信号,默认false,适用于supervisord管理的子进程本身还有子进程的情况
;user=root ; 为运行程序的unix帐号设置setuid
;redirect_stderr=true ; 重定向程序的标准错误到标准输出,默认false
;stdout_logfile=/a/path ; 标准输出的日志路径。可以指定路径,AUTO,none等三个选项。
; 建议指定路径,使用AUTO选项的话,每次reload的时候都会在childlogdir下生成一个"process_name-随机字符串.log"文件
;stdout_logfile_maxbytes=1MB ; 日志文件最大值,否则循环写入 (default 50MB)
;stdout_logfile_backups=10 ; 标准输出日志备份数目 (default 10)
;stdout_capture_maxbytes=1MB ; 定capture管道的大小,当值不为0的时候,子进程可以从stdout发送信息,而supervisor可以根据信息,发送相应的event。
; 默认为0,为0的时候表示关闭管道
;stdout_events_enabled=false ; 当设置为ture的时候,当子进程由stdout向文件描述符中写日志的时候,将
; 触发supervisord发送PROCESS_LOG_STDOUT类型的event,默认为false
;stderr_logfile=/a/path ; 标准错误输出日志路径, 和stdout_logfile选项类似
;stderr_logfile_maxbytes=1MB ; 日志文件最大值,否则循环写入 (default 50MB)
;stderr_logfile_backups=10 ; 标准错误日志备份数目 (default 10)
;stderr_capture_maxbytes=1MB ; 和stdout_capture_maxbytes一样
;stderr_events_enabled=false ; 和stdout_events_enabled一样
;environment=A=1,B=2 ; 进程附加环境,这个是该子进程的环境变量,和别的子进程是不共享的
;serverurl=AUTO ; override serverurl computation (childutils)

; The below sample eventlistener section shows all possible
; eventlistener subsection values, create one or more 'real'
; eventlistener: sections to be able to handle event notifications
; sent by supervisor.
; 下面是事件监听器的可选配置, supervisor能够处理事件通知.
; eventlistener和program的地位是一样的,也是suopervisor启动的子进程,配置和program相似
; listener的实现可以参考这篇文章 http://widnmt.com/2016/02/02/supervisor-event/

;[eventlistener:theeventlistenername]
;command=/bin/eventlistener ; 运行的程序 (相对使用PATH路径, 可以使用参数)
;process_name=%(program_name)s ; 进程名表达式,默认为%(program_name)s
;numprocs=1 ; 默认启动的进程数目,默认为1
;events=EVENT ; event事件的类型,comma-separated,只有写在这个地方的事件类型才会被发送
;buffer_size=10 ; 事件缓冲区队列大小,默认10
;directory=/tmp ; 在运行前cwd到指定的目录,默认不执行cmd
;umask=022 ; 进程umask,默认None
;priority=-1 ; 程序运行的优先级,默认-1
;autostart=true ; 默认随supervisord自动启动,默认true
;autorestart=unexpected ; whether/when to restart (default: unexpected)
;startsecs=1 ; number of secs prog must stay running (def. 1)
;startretries=3 ; max # of serial start failures (default 3)
;exitcodes=0,2 ; 期望的退出码,默认0,2
;stopsignal=QUIT ; 杀死进程的信号,默认TERM
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
;stopasgroup=false ; 向unix进程组发送停止信号,默认false
;killasgroup=false ; 向unix进程组发送SIGKILL信号,默认false
;user=chrism ; setuid to this UNIX account to run the program
;redirect_stderr=true ; redirect proc stderr to stdout (default false)
;stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO
;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
;stdout_events_enabled=false ; emit events on stdout writes (default false)
;stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups ; # of stderr logfile backups (default 10)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A=1,B=2 ; process environment additions
;serverurl=AUTO ; override serverurl computation (childutils)

; The below sample group section shows all possible group values,
; create one or more 'real' group: sections to create "heterogeneous"
; process groups.
; 下面是进程组的可选配置,可以创建一个或多个进程组。
; 注意:program被划分到组里面之后,就相当于原来的配置从supervisor的配置文件里消失了,
; supervisor只会对组进行管理,而不再会对组里面的单个program进行管理了

[group:appgroup]
programs=wapp,wfapp ; 这里的进程名是上文 [program:x] 的 x
;priority=999 ; 程序运行的优先级,默认999

; The [include] section can just contain the "files" setting. This
; setting can list multiple files (separated by whitespace or
; newlines). It can also contain wildcards. The filenames are
; interpreted as relative to this file. Included files *cannot*
; include files themselves.
; 这个东西挺有用的,当我们要管理的进程很多的时候,写在一个文件里面就有点大了。
; 我们可以把配置信息写到多个文件中,然后include过来

;[include]
;files = relative/directory/*.ini

; 配置一组进程,对于类似的program可以通过这种方式添加,避免手工一个个添加
;[program:bsapp]
;command=/usr1/app/run/%(program_name)s_%(process_num)02d wapp /usr1/app/log/%(program_name)s_%(process_num)02d.tr
;numprocs=3
;process_name=%(program_name)s_%(process_num)02d
;autostart=true
;autorestart=true</span><span style="font-family: 微软雅黑, 'Microsoft YaHei', Oswald, 'Helvetica Neue', Helvetica, Verdana, arial, sans-serif;">

(更多配置说明请参考:http://supervisord.org/configuration.html

注意:;是注释,修改的时候一定要把要配置的行前边那个;删了,
当时我配置的时候因为没有去掉; [inet_http_server]前边的;而浪费半个小时的时间。

命令

修改好配置文件后,直接执行supervisord即可启动。
然后可以用supervisorctl或用浏览器访问 http://serverhost:9001 ,就可以管理进程了。

更多命令如下:

1
2
3
4
5
6
7
8
9
supervisord,初始启动Supervisord,启动、管理配置中设置的进程。
supervisorctl stop programxxx,停止某一个进程(programxxx),programxxx 为[program:example] 里配置的值,这个示例就是 example。
supervisorctl start programxxx,启动某个进程
supervisorctl restart programxxx,重启某个进程
supervisorctl stop groupworker: ,重启所有属于名为 groupworker 这个分组的进程(start,restart 同理)
supervisorctl stop all,停止全部进程,注:start、restart、stop 都不会载入最新的配置文件。
supervisorctl reload,载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程。
supervisorctl update,根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启。
注意:显式用 stop 停止掉的进程,用 reload 或 update 都不会自动重启。

常见错误

1
2
3
4
5
$ supersivord
/usr/lib/python2.7/site-packages/supervisor-3.1.3-py2.7.egg/supervisor/options.py:296: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security.
'Supervisord is running as root and it is searching '
Error: The directory named as part of the path /data/log/supervisor/main.log does not exist.
For help, use /usr/bin/supervisord -h

这个目录/data/log/supervisor/不存在,手动创建就好了

1
2
/usr/lib/python2.7/site-packages/supervisor-3.1.3-py2.7.egg/supervisor/options.py:296: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security.
'Supervisord is running as root and it is searching '

使用supervisord -c /etc/supervisord.conf启动

1
2
$ supervisorctl
unix:///var/run/supervisor.sock no such file

应该是你的 supervisord 没有启动起来,ps -ef | grep supervisord看看

1
2
$ supervisorctl
http://127.0.0.1:9001 refused connection

首先还是看的 supervisord 启动了没有;其次netstats -apn | grep 9001看看端口是否被占用,换个端口试试;最后就是看看配置文件里有没有写错或没去掉前边的那个;; [inet_http_server]

参考
Supervisor – 服务管理
用Supervisord管理进程