Fork me on GitHub

Supervisor简介、安装、配置

本文主要介绍了supervisor的安装、使用。

1. 什么是supervisor

Supervisor是一个Python开发的client/server系统,可以管理和监控类unix上面的进程。类似daemontools

什么情况下我们需要进程管理呢?就是执行一些需要以守护进程方式执行的程序,比如一个后台任务,如经常会碰到要写一些守护进程,简单做法放入后台:

1
shell> nohup python xxx.py &

除此之外,Supervisor 还能很友好的管理程序在命令行上输出的日志,可以将日志重定向到自定义的日志文件中,还能按文件大小对日志进行分割。

2. 为啥用supervisor

方便

为啥简单呢?因为咱们通常管理linux进程的时候,一般来说都需要自己编写一个能够实现进程start/stop/restart/reload功能的脚本,然后丢到/etc/init.d/下面。这么做有很多不好的地方,第一我们要编写这个脚本,这就很耗时耗力了。第二,当这个进程挂掉的时候,linux不会自动重启它的,想要自动重启的话,我们还要自己写一个监控重启脚本。而supervisor则可以完美的解决这些问题。supervisor管理进程,是通过fork/exec的方式把这些被管理的进程,当作supervisor的子进程来启动。这样的话,我们只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去就OK了。这样就省下了我们如同linux管理进程的时自己写控制脚本的麻烦了。第二,被管理进程作为supervisor的子进程,当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,所以当然也就可以对挂掉的子进程进行自动重启了,当然重启还是不重启,也要看你的配置文件里面有木有设置autostart=true了。

精确

Supervisord将进程作为子进程启动,因此可以一直知晓子进程的状态,可以方便查询。而基于pid文件文件获取进程状态有时候不靠谱

权限代理

某些进程需要root或者sudo权限运行,而又不方便把机器的root权限和sudo权限开放给用户的时候,普通用户可以借助supervisor的命令和web UI进行进程的启动和关闭

进程组

linux系统没有批量启动关闭进程的功能,我们想要停止多个进程,只能一个一个的去停止,要么就自己写个脚本去批量停止。Supervisor 允许赋予进程优先级,可以使用supervisorctl 的“start all”, and “restart all”,按照优先级顺序启动。并且进程可以分组,相关的进程可以作为一个单元启动。

3. supervisor特点

  • 简单 :supervisor通过一个 INI-style的文件配置,简单易学。提供了许多诸如重启失败进程、自动日子归档的功能
  • 中心化: 可以在在同一个地方启动 停止 监控子进程,进程可以单独控制,也可以分组控制,并提供命令行和web接口配置supervisor
  • 高效: 通过 fork/exec启动子进程
  • 可扩展: 提供了simple event notification protocol和XML-RPC interface,方便通过各种语言进行配置管理
  • 兼容性强: 类Unix都支持,不支持windows,基于Python
  • 作为一款已经被使用了十多年的软件,可用性已经被广泛证明

4. Supervisor 组成

  1. supervisord:supervisord是supervisor的服务端程序。负责启动子程序,应答客户端命令,重启crash进程,子程序日志记录,对进程变化发送事件通知等
  2. supervisorctl: 客户端命令行工具,可以连接服务器端,进行进程的启动、关闭、重启、状态查看等。重要的一点是,supervisorctl不仅可以连接到本机上的supervisord,还可以连接到远程的supervisord,当然在本机上面是通过UNIX socket连接的,远程是通过TCP socket连接的。supervisorctl和supervisord之间的通信,是通过xml_rpc完成的。 相应的配置在[supervisorctl]块里面
  3. Web Server 可以在界面上管理进程的WEB UI, 通过[inet_http_server] section配置,默认http://localhost:9001/`
  4. XML-RPC Interface XML-RPC接口,提供XML-RPC服务来对子进程进行管理,监控,参照 XML-RPC API Documentation.

5 安装

5.1 yum 安装(推荐)

1
yum install supervisor

会自动安装成服务形式,可以使用systemctl进行管理

5.2 使用Setuptools安装

1
2
3
wget -q http://peak.telecommunity.com/dist/ez_setup.py
python ez_setup.py
easy_install supervisor

或者

1
2
yum install python-setuptools
easy_install supervisor

5.3 安装方式3

1
2
3
4
wget https://pypi.python.org/packages/80/37/964c0d53cbd328796b1aeb7abea4c0f7b0e8c7197ea9b0b9967b7d004def/supervisor-3.3.1.tar.gz
tar -zxvf supervisor-3.3.1.tar.gz
cd supervisor-3.3.1
python setup.py install

5.4生成配置文件

yum 安装方式不需要此步骤,因为已经自动生产了supervisord.conf 和supervisord.d文件夹

安装完 supervisor 之后,可以运行echo_supervisord_conf 命令输出默认的配置项,也可以重定向到一个配置文件里:

1
echo_supervisord_conf > /etc/supervisord.conf

5.5启动

1
supervisord -c /etc/supervisord.conf

6. 配置文件/etc/supervisord.conf

上面我们已经把 supervisrod 运行起来了,现在可以添加我们要管理的进程的配置文件。可以把所有配置项都写到 supervisord.conf 文件里,但并不推荐这样做,而是通过 include 的方式把不同的程序(组)写到不同的配置文件里。yum方式安装,会自动配置。

1
2
[include]
files = supervisord.d/*.ini ; 可以是 *.conf 或 *.ini

/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 = /etc/supervisord.d/*.ini ; 可以是 *.conf 或 *.ini

7. 添加一个被管理的进程

我们假如有一个hello.py

1
2
3
4
5
6
7
8
9
import web
urls = ( '/(.*)','hello' )
app = web.application(urls, globals())
class hello:
def GET(self, name):
return 'hello: ' + name
if __name__ == '__main__':
app.run()

所以直接在命令行启动的方式可能是这样的:(需要先安装web.py easy_install web.py)

1
python /opt/hello.py

现在编写一份配置文件/etc/supervisord.d/hello.ini来管理这个进程

1
2
3
4
5
6
7
8
9
10
11
12
13
[program:hello]
directory = /opt ; 程序的启动目录
command = python /opt/hello.py ; 启动命令,可以看出与手动在命令行启动的命令是一样的
autostart = true ; 在 supervisord 启动的时候也自动启动
startsecs = 5 ; 启动 5 秒后没有异常退出,就当作已经正常启动了
autorestart = true ; 程序异常退出后自动重启
startretries = 3 ; 启动失败自动重试次数,默认是 3
user = xqzt ; 用哪个用户启动
redirect_stderr = true ; 把 stderr 重定向到 stdout,默认 false
stdout_logfile_maxbytes = 20MB ; stdout 日志文件大小,默认 50MB
stdout_logfile_backups = 20 ; stdout 日志文件备份数
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile = /var/log/supervisor/hello.log

一份配置文件至少需要一个 [program:x] 部分的配置,来告诉 supervisord 需要管理那个进程。[program:x] 语法中的 x 表示 program name,会在客户端(supervisorctl 或 web 界面)显示,在 supervisorctl 中通过这个值来对程序进行 start、restart、stop 等操作。

1
2
supervisor> status
hello RUNNING pid 2809, uptime 0:00:06

8. 使用 supervisorctl

Supervisorctl 是 supervisord 的一个命令行客户端工具,启动时需要指定与 supervisord 使用同一份配置文件,否则与 supervisord 一样按照顺序查找配置文件。supervisorctl 这个命令会进入 supervisorctl 的 shell 界面,然后可以执行不同的命令了,也可以直接在 bash 终端运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# supervisorctl --help
supervisorctl -- control applications run by supervisord from the cmd line.
Usage: /usr/bin/supervisorctl [options] [action [arguments]]
Options:
-c/--configuration -- configuration file path (default /etc/supervisord.conf)
-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 to use for authentication with server
-p/--password -- password to use for authentication with server
-r/--history-file -- keep a readline history (if readline is available)

输入help,可以查看支持的命令及用法

1
2
3
4
5
6
7
8
9
10
11
12
supervisor> help
default commands (type help <topic>):
=====================================
add clear fg open quit remove restart start stop update
avail exit maintail pid reload reread shutdown status tail version
supervisor> help start
start <name> Start a process
start <gname>:* Start all processes in a group
start <name> <name> Start multiple processes or groups
start all Start all processes

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 停止某一个进程,program_name 为 [program:x] 里的 x
supervisorctl stop program_name
# 启动某个进程
supervisorctl start program_name
# 重启某个进程
supervisorctl restart program_name
# 结束所有属于名为 groupworker 这个分组的进程 (start,restart 同理)
supervisorctl stop groupworker:
# 结束 groupworker:name1 这个进程 (start,restart 同理)
supervisorctl stop groupworker:name1
# 停止全部进程,注:start、restart、stop 都不会载入最新的配置文件
supervisorctl stop all
# 载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程
supervisorctl reload
# 根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启
supervisorctl update

9. supervisor Web UI

除了 supervisorctl 之外,还可以配置 supervisrod 启动 web 管理界面,这个 web 后台使用 Basic Auth 的方式进行身份认证。将supervisord.conf中[inet_http_server]部分做相应配置,在supervisorctl中reload即可启动web管理界面

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

在浏览器中输入http://127.0.0.1:9001,可进入web管理界面

10. 将多个进程按组管理

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

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

当添加了上述配置后,progname1progname2 的进程名就会变成 thegroupname:progname1thegroupname:progname2 以后就要用这个名字来管理进程了,而不是之前的 progname1

以后执行 supervisorctl stop thegroupname: 就能同时结束 progname1progname2,执行 supervisorctl stop thegroupname:progname1 就能结束 progname1。如下所示

/etc/supervisord.d/hello.ini文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[group:group1]
programs=hello
[program:hello]
directory = /opt ; 程序的启动目录
command = python /opt/hello.py ; 启动命令,可以看出与手动在命令行启动的命令是一样的
autostart = true ; 在 supervisord 启动的时候也自动启动
startsecs = 5 ; 启动 5 秒后没有异常退出,就当作已经正常启动了
autorestart = true ; 程序异常退出后自动重启
startretries = 3 ; 启动失败自动重试次数,默认是 3
user = xqzt ; 用哪个用户启动
redirect_stderr = true ; 把 stderr 重定向到 stdout,默认 false
stdout_logfile_maxbytes = 20MB ; stdout 日志文件大小,默认 50MB
stdout_logfile_backups = 20 ; stdout 日志文件备份数
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
; stdout_logfile = /var/log/supervisor/hello.log

进程状态

1
2
[root@centos7 etc]# supervisorctl
group1:hello RUNNING pid 2842, uptime 0:02:53

11. Subprocesses进程状态变化

http://supervisord.org/_images/subprocess-transitions.png

参考

官方文档

好记性不如烂笔头,生命不息,学习不止!

分享