Supervisor 入门教程

Superviosr 介绍

Supervisor是一款用采用Client/Server架构、开源(github地址)的进程监控管理工具。

Supervisor稳定、简单、高效、可扩展、兼容性好,可以在大部分类Unix系统(Debian、Solaris、Mac OS、FreeBSD等)上使用(不支持Windows,可用NSSN替代)。

Supervisor可以很方便的管理批量进程,不仅支持启动、重启、关闭、重载,还支持监控进程,进程意外僵死后可自动拉起。

Supervisor虽然是用Python开发,但是可以用来管理任意进程,而不仅仅是Python进程。

Supervisor目前最新版本3.3.4,暂不支持Python 3,不过即将推出的4.0版本将会支持Python3.4+。

Supervisor由以下4部分组成:

  • supervisord

    supervisord是supervisor的后台服务。它负责启动supervisor管理的子进程、响应来自client的请求、重启闪退或异常退出的子进程、把子进程的stderr或stdout记录到日志文件中、生成和处理Event等。

  • supervisorctl

    supervisorctl相当于supervisor的客户端。它有一个类shell的命令行界面,可以通过命令查看、启动、停止、重启子进程,supervisorctl不仅可以通过UNIX socket连接本机的supervisord管理进程,还可以通过TCP socket连接远程的supervisord管理进程。supervisorctl和supervisord之间的通信,是通过xml_rpc完成的,相应的配置在[supervisorctl]块里面。

  • Web Server

    Web Server主要可以在界面上管理进程,Web Server其实是通过XML_RPC来实现的,可以向supervisor请求数据,也可以控制supervisor及子进程。配置在[inet_http_server]块里面。

  • XML-RPC Interface

    supervisorctl和Web Server通过XML-RPC接口调用supervisord,实现进程的管理。当然你也可以在你自己的服务里调用这些XML-RPC接口,来管理子进程。

Supervisor 安装

通过源码安装

$ git clone https://github.com/Supervisor/supervisor.git

$ python setup.py install

通过pip安装

$ pip install supervisor

通过apt-get安装

在Ubuntu上,可以直接运行apt-get install supervisor安装

通过easy_install安装

$ easy_install supervisor

easy_install 是一个基于setuptools的工具,帮助我们自动下载、编译、安装和管理python packages。

pip是easy_install的改进版,平常用pip就可以了,但还有老版本的Python只有easy_install。

Supervisor 配置

Supervisor的配置文件采用的Windows INI格式,推荐命名为supervisord.confsupervisordsupervisorctl都会用到这个配置文件。Supervisor启动时可以通过-c参数指定配置文件,如果没有指定,supervisor则会在以下路径依次寻找supervisord.conf,直到读取到supervisord.conf。

1
2
3
4
5
6
$CWD/supervisord.conf				# $CWD表示运行supervisord程序的目录
$CWD/etc/supervisord.conf # $CWD表示运行supervisord程序的目录
/etc/supervisord.conf
/etc/supervisor/supervisord.conf # Supervisor3.3.0新加
../etc/supervisord.conf # 相对脚本执行的路径
../supervisord.conf # 相对脚本执行的路径

安装完毕后,可以通过echo_supervisord_conf生成一份默认初始配置文件。
$ echo_supervisord_conf > your_path/supervisord.conf

supervisord.conf主要由以下9个部分组成。其中常用的为前面6个部分,后面3个很少用到。

[unix|inet]_http_server

supervisorctl通过unix socket或tcp socket与supervisord通信,Web Server通过tcp与supervisord通信。unix_http_serverinet_http_server两者必须配置一个,否则无法管理supervisord。

1
2
3
4
5
6
7
8
9
10
11
[unix_http_server]
file=/tmp/supervisor.sock ; unix socket文件路径
;chmod=0700 ; unix socket文件的mode,默认是0700
;chown=nobody:nogroup ; unix socket文件的owner,格式:uid:gid,默认为启动supervisord进程的用户及属组
;username=user ; supervisorctl连接时认证的用户,默认为不需要用户
;password=123 ; 和上面的用户名对应的密码,可以直接使用明码,也可以使用SHA加密,如:{SHA}82ab876d1387bfafe46cc1c8a2ef074eae50cb1d

[inet_http_server]
;port=127.0.0.1:9001 ; tcp监听地址和端口
;username=user ; supervisorctl和web server连接时认证的用户,默认无需用户名
;password=123 ; 和上面的用户名对应的密码,可以直接使用明码,也可以使用SHA加密,如:{SHA}82ab876d1387bfafe46cc1c8a2ef074eae50cb1d

supervisord

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[supervisord]
logfile=/tmp/supervisord.log ; supervisord主进程日志文件路径,默认是$CWD/supervisord.log
logfile_maxbytes=50MB ; supervisord主进程日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小
logfile_backups=10 ; supervisord主进程日志文件保留备份数量默认10,设为0表示不备份
loglevel=info ; 日志级别,默认info,其它: debug,warn,trace
pidfile=/tmp/supervisord.pid ; supervisord主进程的pid文件路径,默认名为supervisord.pid
nodaemon=false ; supervisord主进程是否在前台启动,默认是false,即以 daemon 的方式启动
minfds=1024 ; supervisord主进程可以打开的文件描述符的最小值,默认 1024
minprocs=200 ; supervisord主进程可以打开的进程数的最小值,默认 200
;umask=022 ; supervisord主进程创建文件的掩码,默认为022
;user=chrism ; 这个参数可以设置一个非root用户,当我们以root用户启动supervisord之后。这里面设置的这个用户,也可以对supervisord进行管理
;identifier=supervisor ; 这个参数是supervisord的标识符,主要是给XML_RPC用的。当你有多supervisor的时候,而且想调用XML_RPC统一管理,就需要为每个supervisor设置不同的标识符了,默认是supervisord
;directory=/tmp ; 这个参数是当supervisord作为守护进程运行的时候,设置这个参数的话,启动supervisord进程之前,会先切换到这个目录
;nocleanup=true ; 这个参数当为false的时候,会在supervisord进程启动的时候,把以前子进程产生的日志文件(路径为AUTO的情况下)清除掉。有时候需要查看历史日志,可以设置为true
;childlogdir=/tmp ; 当子进程日志路径为AUTO的时候,子进程日志文件的存放路径。默认路径是这个东西,执行下面的这个命令看看就OK了,python -c "import tempfile;print tempfile.gettempdir()"
;environment=KEY="value" ; 这个是用来设置环境变量的,supervisord在linux中启动默认继承了linux的环境变量,在这里可以设置supervisord进程特有的其他环境变量。supervisord启动子进程时,子进程会拷贝父进程的内存空间内容。 所以设置的这些环境变量也会被子进程继承。小例子:environment=name="haha",age="hehe"
;strip_ansi=false ; 这个选项如果设置为true,会清除子进程日志中的所有ANSI 序列。什么是ANSI序列呢?就是我们的\n,\t这些东西

supervisord的配置也可以不写入配置文件,可在启动supervisord时当参数传入,如下所示。

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
$ supervisord -h
supervisord -- run a set of applications as daemons.

Usage: /usr/local/bin/supervisord [options]

Options:
-c/--configuration FILENAME -- configuration file path (searches if not given)
-n/--nodaemon -- run in the foreground (same as 'nodaemon=true' in config file)
-h/--help -- print this usage message and exit
-v/--version -- print supervisord version number and exit
-u/--user USER -- run supervisord as this user (or numeric uid)
-m/--umask UMASK -- use this umask for daemon subprocess (default is 022)
-d/--directory DIRECTORY -- directory to chdir to when daemonized
-l/--logfile FILENAME -- use FILENAME as logfile path
-y/--logfile_maxbytes BYTES -- use BYTES to limit the max size of logfile
-z/--logfile_backups NUM -- number of backups to keep when max bytes reached
-e/--loglevel LEVEL -- use LEVEL as log level (debug,info,warn,error,critical)
-j/--pidfile FILENAME -- write a pid file for the daemon process to FILENAME
-i/--identifier STR -- identifier used for this instance of supervisord
-q/--childlogdir DIRECTORY -- the log directory for child process logs
-k/--nocleanup -- prevent the process from performing cleanup (removal of
old automatic child log files) at startup.
-a/--minfds NUM -- the minimum number of file descriptors for start success
-t/--strip_ansi -- strip ansi escape codes from process output
--minprocs NUM -- the minimum number of processes available for start success
--profile_options OPTIONS -- run supervisord under profiler and output
results based on OPTIONS, which is a comma-sep'd
list of 'cumulative', 'calls', and/or 'callers',
e.g. 'cumulative,callers')

supervisorctl

当你使用unix socket与supervisord通信时,serverurl配置unix://path/supervisor.sock。当你使用tcp socket与supervisord通信时,serverurl配置http://ip:port

如果[unix|inet]_http_server中有设置username和password,此处不配置的话,则通过supervisorctl管理时需要显式传入username 和 password。如果你不希望别人查看管理你的program,这种方式就有用了。

1
2
3
4
5
6
7
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; unix socket文件路径
;serverurl=http://127.0.0.1:9001 ; tcp socket监听的ip:port
;username=chris ; 如果设置则必须与[unix|inet]_http_server中的username一致
;password=123 ; 如果设置则必须与[unix|inet]_http_server中的username一致
;prompt=mysupervisor ; cmd line prompt (default "supervisor")
;history_file=~/.sc_history ; use readline history if available

supervisorctl的配置也可以不写入配置文件,可在启动supervisorctl时当参数传入,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ supervisorctl -h
supervisorctl -- control applications run by supervisord from the cmd line.

Usage: /usr/local/bin/supervisorctl [options] [action [arguments]]

Options:
-c/--configuration FILENAME -- configuration file path (searches if not given)
-h/--help -- print usage message and exit
-i/--interactive -- start an interactive shell after executing commands
-s/--serverurl URL -- URL on which supervisord server is listening
(default "http://localhost:9001").
-u/--username USERNAME -- username to use for authentication with server
-p/--password PASSWORD -- password to use for authentication with server
-r/--history-file -- keep a readline history (if readline is available)

action [arguments] -- see below

Actions are commands like "tail" or "stop". If -i is specified or no action is
specified on the command line, a "shell" interpreting actions typed
interactively is started. Use the action "help" to find out about available
actions.

program

应用程序配置信息,x是应用程序的唯一标识,不能重复。后续对该程序的所有操作(start, restart等)都通过该名字来实现。

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
;[program:x]
;command=/bin/cat ; program的运行命令,支持相对路径,可以带参数
;process_name=%(program_name)s ; 进程名称,默认是%(program_name)s,如果numprocs大于1,则必须将”%(process_num)s”变量放入”process_name”中,防止多个进程同名导致启动出错
;numprocs=1 ; 同时启动的进程个数,用来实现并发,默认是1
;directory=/tmp ; 如果配置了这个目录,那program运行前,会先切换到这个目录
;umask=022 ; umask for process (default None)
;priority=999 ; program进程优先级,决定了启动和关闭program进程的顺序,默认是最大值999
;autostart=true ; 启动supervisord时,program进程是否自动启动,默认是true
;startsecs=1 ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
;startretries=3 ; 启动失败自动重试次数,默认是3
;autorestart=unexpected ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启
;exitcodes=0,2 ; 'expected' exit codes used with autorestart (default 0,2)
;stopsignal=QUIT ; signal used to kill process (default TERM)
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
;stopasgroup=false ; 进程被杀死时,是否向这个进程组发送stop信号,包括program子进程,默认false
;killasgroup=false ; 向进程组发送kill信号,包括program子进程,默认false
;user=chrism ; 运行program进程的用户,默认同supervisord服务的启动用户。如果supervisord由root启动,而你又不想给program进程root,你可以配置这个参数
;redirect_stderr=true ; 把stderr重定向到stdout,默认false
;stdout_logfile=/a/path ; 由于program进程由supervisord启动,所以其stdout将无法输出到系统的标准输出上,所以你要将program进程的stdout写入到日志文件中。这个参数指定了该日志文件的位置,默认是 $CWD/supervisord.log。(需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录)
;stdout_logfile_maxbytes=1MB ; 日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小
;stdout_logfile_backups=10 ; 日志文件保留备份数量默认10,设为0表示不备份
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false ; emit events on stdout writes (default false)
;stderr_logfile=/a/path ; 同stdout_logfile,这里指定了stderr写入的日志文件位置
;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups=10 ; # of stderr logfile backups (0 means none, default 10)
;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A="1",B="2" ; 通过 environment 来添加需要的环境变量,一种常见的用法是修改 PYTHONPATH
;serverurl=AUTO ; override serverurl computation (childutils)

include

1
2
[include]
;files = relative/directory/*.ini ; 可以指定一个或多个以.ini结束的配置文件

group

1
2
3
[group:x]
;programs=progname1,progname2 ; each refers to 'x' in [program:x] definitions
;priority=999 ; the relative start priority (default 999)

rpcinerface

这个选项是给XML_RPC用的,当然你如果想使用supervisord或者web server 这个选项必须要开启的

1
2
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

fcgi-program

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
;[fcgi-program:x]
;command=/bin/cat ; program的运行命令,支持相对路径,可以带参数
;socket=unix:///var/run/supervisor/%(program_name)s.sock
;socket=tcp://localhost:9002
;socket_owner=user:group
;socket_mode=0700
;process_name=%(program_name)s ; 进程名称,默认是%(program_name)s,如果numprocs大于1,则必须将”%(process_num)s”变量放入”process_name”中,防止多个进程同名导致启动出错
;numprocs=1 ; 同时启动的进程个数,用来实现并发,默认是1
;directory=/tmp ; 如果配置了这个目录,那program运行前,会先切换到这个目录
;umask=022 ; umask for process (default None)
;priority=999 ; program进程优先级,决定了启动和关闭program进程的顺序,默认是最大值999
;autostart=true ; 启动supervisord时,program进程是否自动启动,默认是true
;startsecs=1 ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
;startretries=3 ; 启动失败自动重试次数,默认是3
;autorestart=unexpected ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启
;exitcodes=0,2 ; 'expected' exit codes used with autorestart (default 0,2)
;stopsignal=QUIT ; signal used to kill process (default TERM)
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
;stopasgroup=false ; 进程被杀死时,是否向这个进程组发送stop信号,包括program子进程,默认false
;killasgroup=false ; 向进程组发送kill信号,包括program子进程,默认false
;user=chrism ; 运行program进程的用户,默认同supervisord服务的启动用户。如果supervisord由root启动,而你又不想给program进程root,你可以配置这个参数
;redirect_stderr=true ; 把stderr重定向到stdout,默认false
;stdout_logfile=/a/path ; 由于program进程由supervisord启动,所以其stdout将无法输出到系统的标准输出上,所以你要将program进程的stdout写入到日志文件中。这个参数指定了该日志文件的位置,默认是 $CWD/supervisord.log。(需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录)
;stdout_logfile_maxbytes=1MB ; 日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小
;stdout_logfile_backups=10 ; 日志文件保留备份数量默认10,设为0表示不备份
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false ; emit events on stdout writes (default false)
;stderr_logfile=/a/path ; 同stdout_logfile,这里指定了stderr写入的日志文件位置
;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups=10 ; # of stderr logfile backups (0 means none, default 10)
;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A="1",B="2" ; 通过 environment 来添加需要的环境变量,一种常见的用法是修改 PYTHONPATH
;serverurl=AUTO ; override serverurl computation (childutils)

eventlistenner

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
;[eventlistenner:x]
;command=/bin/eventlistener ; the program (relative uses PATH, can take args)
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
;numprocs=1 ; number of processes copies to start (def 1)
;events=EVENT ; event notif. types to subscribe to (req\'d)
;buffer_size=10 ; event buffer queue size (default 10)
;directory=/tmp ; directory to cwd to before exec (def no cwd)
;umask=022 ; umask for process (default None)
;priority=-1 ; the relative start priority (default -1)
;autostart=true ; start at supervisord start (default: true)
;startsecs=1 ; # of secs prog must stay up to be running (def. 1)
;startretries=3 ; max # of serial start failures when starting (default 3)
;autorestart=unexpected ; autorestart if exited after running (def: unexpected)
;exitcodes=0,2 ; 'expected' exit codes used with autorestart (default 0,2)
;stopsignal=QUIT ; signal used to kill process (default TERM)
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
;stopasgroup=false ; send stop signal to the UNIX process group (default false)
;killasgroup=false ; SIGKILL the UNIX process group (def false)
;user=chrism ; setuid to this UNIX account to run the program
;redirect_stderr=false ; redirect_stderr=true is not allowed for eventlisteners
;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 (0 means none, 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=10 ; # of stderr logfile backups (0 means none, 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)

Supervisor 命令

  • 启动supervisor服务

    $ install_path/supervisord -c supervisord.conf

    如果是apt-get安装,可通过service supervisor start启动

  • 停止supervisor服务

    $ supervisorctl [-c supervisord.conf] shutdown

    如果是apt-get安装,可通过service supervisor stop停止

  • 查看supervisor管理的program列表及状态

    $ supervisorctl [-c supervisord.conf] status

  • 管理单个或多个进程

    $ supervisorctl [-c supervisord.conf] [start|status|stop|restart] program_name_1 [program_name_n...]

  • 管理进程组

    $ supervisorctl [-c supervisord.conf] [start|status|stop|restart] groupworker:group_name

  • 启动新配置的program、重启配置有改动的program

    $ supervisorctl [-c supervisord.conf] update

  • 停止原所有进程,并按新的配置启动program

    $ supervisorctl [-c supervisord.conf] reload

  • 停止所有program

    $ supervisorctl [-c supervisord.conf] stop all

  • 进入supervisorctl交互式环境

    $supervisorctl [-c supervisord.conf]

说明

  1. Supervisor 只能管理在前台运行的程序,所以如果应用程序有后台运行的选项,需要关闭。

  2. 如果program还有子进程,为确保所有program子进程都能正确停止,[program:x]下的stopasgroupkillasgroup都必须设置为true,否则program子进程就可能变成僵尸进程。

  3. 按照官方文档的定义,一个 [program:x] 实际上是表示一组相同特征或同类的进程组,也就是说一个 [program:x] 可以启动多个进程。这组进程的成员是通过 numprocsprocess_name 这两个参数来确定的。

  4. Supervisor 同时还提供了另外一种进程组的管理方式,通过这种方式,可以使用 supervisorctl 命令来管理一组进程。跟 [program:x] 的进程组不同的是,这里的进程是一个个的 [program:x] 。

  5. Supervisor的Web Server界面长这样

    supervisor web页面

参考资料:
Linux上的后台进程管理工具Supervisor
supervisor(一)基础篇