Supervisor的介绍
Supervisor (http://supervisord.org) 是一个用 Python 写的进程管理工具,可以很方便的用来启动、重启、关闭进程(不仅仅是 Python 进程)。除了对单个进程的控制,还可以同时启动、关闭多个进程,可以用来实现设置开机自启动及崩溃后自动重启的功能,还可以对进程输出的日志进行管理。
Supervisor 是一个 C/S 模型的程序,supervisord 是server 端,对应的有 client 端:supervisorctl。Supervisor 的配置文件是/etc/supervisor/supervisord.conf,通常情况下我们不需要修改它。在安装完 supervisor 之后,我们可以运行echo_supervisord_conf 命令输出默认的配置项。
一、安装
1.apt
sudo apt install supervisor
2.Ubuntu\Debian下安装
sudo apt-get install supervisor
/etc下会生成一个supervisor文件夹,里面包含supervisord.conf配置文件(Supervisor 的配置文件)和conf.d程序配置文件夹(配置各个进程)
3.easy_install工具
easy_install supervisor
4.源码安装
supervisor网址:https://pypi.org/project/supervisor/
选择需要的版本
tar -zxvf supervisor-4.0.3.tar.gz
cd supervisor-4.0.3
sudo python3 setup.py install
或直接pip install supervisor
mac安装的路径是/Library/Frameworks/Python.framework/Versions/3.6/bin
如上图,sudo echo_supervisord_conf > /etc/supervisor/supervisord.conf 会提示权限不足,可以将配置文件生成在其他目录
sudo echo_supervisord_conf > /Users/qxq/supervisord.conf
然后再sudo mv /Users/qxq/supervisord.conf /etc/supervisor/supervisord.conf
或者使用sudo su - root -c "echo_supervisord_conf > /etc/supervisord.conf"
二、配置
1.supervisor配置文件supervisord.conf
; Sample supervisor config file.
;
; For more information on the config file, please see:
; http://supervisord.org/configuration.html
;
; Notes:
; - Shell expansion ("~" or "$HOME") is not supported. Environment
; variables can be expanded using this syntax: "%(ENV_HOME)s".
; - Quotes around values are not supported, except in the case of
; the environment= options as shown below.
; - Comments must have a leading space: "a=b ;comment" not "a=b;comment".
; - Command will be truncated if it looks like a config file comment, e.g.
; "command=bash -c 'foo ; bar'" will truncate to "command=bash -c 'foo ".
[unix_http_server]
;file=/tmp/supervisor.sock ; the path to the socket file
file=/var/run/supervisor.sock ; UNIX socket文件,supervisorctl会使用, 修改为/var/run/目录,避免被系统删除
;chmod=0700 ; socket file mode (default 0700),socket文件的mode,默认是0700
;chown=nobody:nogroup ; socket file uid:gid owner,socket文件的owner,格式:uid:gid
;username=user ; default is no username (open server)
;password=123 ; default is no password (open server)
;[inet_http_server] ; inet (TCP) server disabled by default, HTTP服务器,提供web管理界面
;port=127.0.0.1:9001 ; ip_address:port specifier, *:port for all iface, Web管理后台运行的IP和端口,如果开放到公网,需要注意安全性
;username=user ; default is no username (open server), 登录管理后台的用户名
;password=123 ; default is no password (open server), 登录管理后台的密码
[supervisord]
;logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log
logfile=/var/log/supervisor/supervisord.log ; 日志文件,修改为/var/log/supervisor/目录,避免被系统删除
logfile_maxbytes=50MB ; max main logfile bytes b4 rotation; default 50MB, 日志文件大小,超出会rotate,默认50MB
logfile_backups=10 ; # of main logfile backups; 0 means none, default 10, 日志文件保留备份数量默认10
loglevel=trace ; log level; default info; others: debug,warn,trace, 日志级别,默认info,其它:debug,warn,trace
;pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid
pidfile=/var/run/supervisord.pid ; pid文件, 修改为/var/run/目录,避免被系统删除
nodaemon=false ; start in foreground if true; default false, 是否在前台启动,默认是false,即以daemon的方式启动
minfds=1024 ; min. avail startup file descriptors; default 1024, 可以打开的文件描述符的最小值,默认1024
minprocs=200 ; min. avail process descriptors;default 200, 可以打开的进程数的最小值,默认200
;umask=022 ; process file creation umask; default 022, 处理文件创建umask;默认022
;设置启动supervisord的用户,一般情况下不要轻易用root用户来启动,除非你真的确定要这么做,如果程序配置文件使用的user是root,这里也要设置为root
;user=supervisord ; setuid to this UNIX account at startup; recommended if root
;identifier=supervisor ; supervisord identifier, default is 'supervisor', supervisord标识符,默认为'supervisor'
;directory=/tmp ; default is not to cd during start
;nocleanup=true ; don't clean up tempfiles at start; default false
;childlogdir=/tmp ; 'AUTO' child log dir, default $TEMP
;environment=KEY="value" ; key value pairs to add to environment
;strip_ansi=false ; strip ansi escape codes in logs; def. false
; The rpcinterface:supervisor 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:x] sections.
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
; The supervisorctl section configures how supervisorctl will connect to
; supervisord. configure it match the settings in either the unix_http_server
; or inet_http_server section.
[supervisorctl]
;serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
serverurl=unix:///var/run/supervisor.sock ;通过 UNIX socket 连接 supervisord,路径与 unix_http_server 部分的 file 一致
;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket, 通过 HTTP 的方式连接 supervisord
;username=chris ; should be same as in [*_http_server] if set, 如果设置与[*_http_server]设置的用户名一样
;password=123 ; should be same as in [*_http_server] if set, 如果设置与[*_http_server]设置的密码一样
;prompt=mysupervisor ; cmd line prompt (default "supervisor"), 命令行提示符(默认为“supervisor”)
;history_file=~/.sc_history ; use readline history if available, 如果可用,请使用readline历史记录
; The sample program section below 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 ; 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)
;directory=/tmp ; directory to cwd to before exec (def no cwd)
;umask=022 ; umask for process (default None)
;priority=999 ; the relative start priority (default 999)
;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 ; when to restart if exited after running (def: unexpected)
;exitcodes=0 ; 'expected' exit codes used with autorestart (default 0)
;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=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 (0 means none, default 10)
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false ; emit events on stdout writes (default false)
;stdout_syslog=false ; send stdout to syslog with process name (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_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;stderr_syslog=false ; send stderr to syslog with process name (default false)
;environment=A="1",B="2" ; process environment additions (def no adds)
;serverurl=AUTO ; override serverurl computation (childutils)
; The sample eventlistener section below shows all possible eventlistener ; 下面的示例eventlistener部分显示了所有可能的eventlistener
; subsection values. Create one or more 'real' eventlistener: sections to be ; 分段的价值观。创建一个或多个“真正的”eventlistener: section to be
; able to handle event notifications sent by supervisord. ; 能够处理督导员发送的事件通知
;[eventlistener:theeventlistenername]
;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 ; 'expected' exit codes used with autorestart (default 0)
;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)
;stdout_syslog=false ; send stdout to syslog with process name (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)
;stderr_syslog=false ; send stderr to syslog with process name (default false)
;environment=A="1",B="2" ; process environment additions
;serverurl=AUTO ; override serverurl computation (childutils)
; The sample group section below shows all possible group values. Create one ; 下面的示例组部分显示了所有可能的组值。创建一个
; or more 'real' group: sections to create "heterogeneous" process groups. ; 或更多“实际”组:创建“异构”流程组的部分
;[group:thegroupname]
;programs=progname1,progname2 ; each refers to 'x' in [program:x] definitions
;priority=999 ; the relative start priority (default 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]部分可以只包含“files”设置。
;此设置可以列出多个文件(用空格或换行分隔)。
;它还可以包含通配符。文件名被解释为相对于这个文件。
;包含的文件*不能*包含文件本身。
;[include]
;files = relative/directory/*.ini
[include] ; 包含其他的配置文件
files = /etc/supervisor/conf.d/*.conf ; 可以随意指定,目录不存在请先建立。配置文件可以是 *.conf 或 *.ini
cd /
sudo mkdir supervisor
sudo chmod 777 /supervisor
cd /supervisor
sudo mkdir run
sudo mkdir log
2.程序配置文件
放在include指定的files目录中,结尾为指定的.conf或者.ini
配置可以查询supervisor的官方文档 http://supervisord.org/configuration.html
;设置进程的名称,使用 supervisorctl 来管理进程时需要使用该进程名,如果supervisor管理多个项目,需要起不同的进程名称
[program:sd]
;启动程序的命令,可以使用相对路径和参数, 不建议放入/home/user/, 对于非user用户一般情况下是不能访问 ; the program (relative uses PATH, can take args)
command=/bin/bash -c 'source venv/bin/activate && python3 manage.py runserver -h0.0.0.0 -p 8001'
;进程名称, 默认为 %(program_name)s,即 [program:x] 中的 x ; process_name expr (default %(program_name)s)
;process_name=%(program_name)s
;要启动的进程数, 默认为1 ; number of processes copies to start (def 1)
;numprocs=1
;执行 command 之前,先切换到程序所在的工作目录 ; directory to cwd to before exec (def no cwd)
directory=/Users/qxq/Desktop/ScreenDisplay/
;进程掩码, 默认无, 掩码:--- -w- -w-, 转换后rwx r-x w-x ; umask for process (default None)
;umask=022
;优先级, 值越高, 最后启动, 最先被关闭, 默认值999 ; the relative start priority (default 999)
;priority=999
;supervisor启动的时候是否随着同时启动,默认True ; start at supervisord start (default: true)
;autostart=true
;这个选项是子进程启动多少秒之后,此时状态如果是running,则我们认为启动成功了。默认值为1 ; # of secs prog must stay up to be running (def. 1)
;startsecs=1
;启动失败自动重试次数,默认是3
;startretries=3 ; max # of serial start failures when starting (default 3)
;设置子进程挂掉后自动重启的情况,有三个选项,false,unexpected和true。默认unexpected,如果为false的时候,无论什么情况下,都不会被重新启动,如果为unexpected,只有当进程的退出码不在下面的exitcodes里面定义的才会重启,如果是True会自动重启 ; when to restart if exited after running (def: unexpected)
autorestart=true
;当退出码是0时, 执行重启, 默认值0, 配合上一条使用 ; 'expected' exit codes used with autorestart (default 0)
;exitcodes=0
;进程停止信号,可以为TERM, HUP, INT, QUIT, KILL, USR1, or USR2,默认TERM
;中断:INT(类似于Ctrl+C)(kill -INT pid),退出后会将写文件或日志(推荐)
;终止:TERM(kill -TERM pid) //信号量参考文章(http://c.biancheng.net/cpp/html/2784.html)
;挂起:HUP(kill -HUP pid),注意与Ctrl+Z/kill -stop pid不同
;从容停止:QUIT(kill -QUIT pid)
;KILL, USR1, USR2其他见命令(kill -l),说明1
;stopsignal=QUIT ; signal used to kill process (default TERM)
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10) ;等待b4 SIGKILL的最大秒数(默认为10)
;stopasgroup=false ; send stop signal to the UNIX process group (default false) ; 向UNIX进程组发送停止信号(默认为false)
;killasgroup=false ; SIGKILL the UNIX process group (def false) ; SIGKILL UNIX进程组(默认为false)
;使用哪个用户来启动该进程,默认当前用户,如果是root用户需要再supervisor的配置文件中配置 ; setuid to this UNIX account to run the program,
;user=chrism
;redirect_stderr=false ; redirect proc stderr to stdout (default false), 把 stderr 重定向到 stdout,默认 false
;日志输出路径,如果输出内容不多可以指定这个并把上面的重定向打开, 需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord会自动创建日志文件)
;stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO,
;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB), 日志文件大小,默认 50MB
;stdout_logfile_backups=10 ; # of stdout logfile backups (0 means none, default 10), 日志文件备份数, 默认10个
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0), 'capturemode'中的字节数(默认为0)
;stdout_events_enabled=false ; emit events on stdout writes (default false), 在stdout写操作上发出事件(默认为false)
;stdout_syslog=false ; send stdout to syslog with process name (default false), 发送stdout到进程名为syslog的系统日志(默认为false)
;错误日志路径, 需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord会自动创建日志文件)
stderr_logfile=/Users/qxq/Desktop/ScreenDisplay/supervisor_log.log ; stderr log path, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB), 日志文件大小,默认 50MB
;stderr_logfile_backups=10 ; # of stderr logfile backups (0 means none, default 10), 日志文件备份数, 默认10个
;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0), 'capturemode'中的字节数(默认为0)
;stderr_events_enabled=false ; emit events on stderr writes (default false), 在stderr写操作上发出事件(默认为false)
;stderr_syslog=false ; send stderr to syslog with process name (default false), 使用进程名将stderr发送到syslog(默认为false)
;environment=A="1",B="2" ; process environment additions (def no adds) ; 可以通过environment来添加需要的环境变量,一种常见的用法是修改PYTHONPATH
;serverurl=AUTO ; override serverurl computation (childutils) ; 覆盖serverurl计算(childutils)
三、supervisor的使用
1.supervisord
执行 supervisord 命令,将会启动 supervisord 进程,同时我们在配置文件中设置的进程也会相应启动。
# 使用默认的配置文件 /etc/supervisord.conf
supervisord
# 明确指定配置文件
supervisord -c /etc/supervisor/supervisord.conf
# 使用 user 用户启动 supervisord
supervisord -u user
2.supervisorctl
# 查看supervisor监管的进程状态
supervisorctl status
# 载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程
supervisorctl reload
# 根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启
supervisorctl update
# 停止某一个进程,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
注意:如果我们的stopasgroup和killasgroup设置为flase,我们停止的仅仅是守护进程,不能停止他的子进程,就会发现只是守护进程(父进程停止了),而子进程(程序)还在运行,就会因为端口被占用等原因而无法启动
4.stopsignal、stopasgroup和killasgroup
;进程停止信号,可以为TERM, HUP, INT, QUIT, KILL, USR1, or USR2,默认TERM
;中断:INT(类似于Ctrl+C)(kill -INT pid),退出后会将写文件或日志(推荐)
;终止:TERM(kill -TERM pid) //信号量参考文(http://c.biancheng.net/cpp/html/2784.html)
;挂起:HUP(kill -HUP pid),注意与Ctrl+Z/kill -stop pid不同
;从容停止:QUIT(kill -QUIT pid)
;KILL, USR1, USR2其他见命令(kill -l),说明1
;stopsignal=QUIT ; signal used to kill process (default TERM)
; 默认为 false,如果设置为 true,当进程收到 stop 信号时,会自动将该信号发给该进程的子进程。
; 如果这个配置项为 true,那么也隐含 killasgroup 为 true。例如在 Debug 模式使用 Flask 时,
; Flask 不会将接收到的 stop 信号也传递给它的子进程,因此就需要设置这个配置项。
stopasgroup=false ; send stop signal to the UNIX process
; 默认为 false,如果设置为 true,当进程收到 kill 信号时,会自动将该信号发给该进程的子进程。
; 如果这个程序使用了 python 的 multiprocessing 时,就能自动停止它的子线程。
killasgroup=false ; SIGKILL the UNIX process group (def false)
另外需要注意command用bash -c 启动 python xx.py一定要设置stopasgroup和killasgroup为true,否则stop不了真正的python/java进程,因为bash命令进程和真正的python进程不是同一个。如果是command=python xx.py这样,并且程序里面没有使用多进程,则无需设置。
4. command 执行多条命令
command = /bin/bash -c "xxx && xxx"
这样运行是要注意下环境变量问题,比如用python的git包时候,读取不了git的路径居然,最后是在配置的enviroment设置GIT_PYTHON_GIT_EXECUTABLE="/usr/bin/git才解决,但单独运行又能读取git。
5.将多个进程按组管理
Supervisor 同时还提供了另外一种进程组的管理方式,通过这种方式,可以使用 supervisorctl 命令来管理一组进程。跟 [program:x] 的进程组不同的是,这里的进程是一个个的 [program:x] 。
[group:thegroupname]
programs=progname1,progname2 ; each refers to 'x' in [program:x] definitions
priority=999 ; the relative start priority (default 999)
当添加了上述配置后,progname1 和 progname2 的进程名就会变成 thegroupname:progname1 和 thegroupname:progname2 以后就要用这个名字来管理进程了,而不是之前的 progname1 和 progname2。
以后执行 supervisorctl stop thegroupname:就能同时结束 progname1 和 progname2,执行 supervisorctl stop thegroupname:progname1 就能结束 progname1。
6.权限问题和异常
设置好配置文件后,应先创建上述配置文件中新增的文件夹。如果指定了启动用户 user,这里以 oxygen 为例,那么应注意相关文件的权限问题,包括日志文件,否则会出现没有权限的错误。例如设置了启动用户 oxygen,然后启动 supervisord 出现错误
Error: Cannot open an HTTP server: socket.error reported errno.EACCES (13)
就是由于上面的配置文件中 /var/run 文件夹,没有授予启动 supervisord 的用户 oxygen 的写权限。/var/run 文件夹实际上是链接到 /run,因此我们修改 /run 的权限。
sudo chmod 777 /run
一般情况下,我们可以用 root 用户启动 supervisord 进程,然后在其所管理的进程中,再具体指定需要以那个用户启动这些进程。
报错:gave up: redis entered FATAL state, too many start retries too quickly
一般是因为进程启动太慢造成,在superisor的conf中的[program:xxxx]加入启动时间“startsecs=5”,如果还不行再加大。默认是1秒,重试3次。
一般守护进程的做法就是fork一个子进程,父进程马上退出,以致于supervisor无法得到子进程的ID。
7.使用浏览器来管理
supervisor 同时提供了通过浏览器来管理进程的方法,只需要打开如下几行就可以了。
[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))
[supervisorctl]
serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
username=user ; should be same as http_username if set
password=123 ; should be same as http_password if set
注意:实际中发现只设置inet_http_server中的3个,不设置supervisorctl中的3个也是可以的,如果都设置,注意要将ip端口和用户名密码设置的相同,不然会报错
8.设置日志级别
loglevel 指定了日志的级别,默认info,其它:debug、warn、trace,用 Python 的 print 语句输出的日志是不会被记录到日志文件中的,需要搭配 Python 的 logging 模块来输出有指定级别的日志。
9.多个进程
按照官方文档的定义,一个 [program:x] 实际上是表示一组相同特征或同类的进程组,也就是说一个 [program:x] 可以启动多个进程
。这组进程的成员是通过 numprocs
和 process_name
这两个参数来确定。
; 设置进程的名称,使用 supervisorctl 来管理进程时需要使用该进程名
[program:foo]
; 可以在 command 这里用 python 表达式传递不同的参数给每个进程
command=python server.py --port=90%(process_num)02d
directory=/home/python/tornado_server ; 执行 command 之前,先切换到工作目录
; 若 numprocs 不为1,process_name 的表达式中一定要包含 process_num 来区分不同的进程
numprocs=2
process_name=%(program_name)s_%(process_num)02d;
user=oxygen ; 使用 oxygen 用户来启动该进程
autorestart=true ; 程序崩溃时自动重启
redirect_stderr=true ; 重定向输出的日志
stdout_logfile = /var/log/supervisord/tornado_server.log
loglevel=info
上面这个例子会启动两个进程,process_name 分别为 foo:foo_01
和 foo:foo_02
。通过这样一种方式,就可以用一个 [program:x] 配置项,来启动一组非常类似的进程
10.开机自动启动 Supervisord
如果是supervisor的配置文件中指定的用户是root,supervisor就会开机自启(原因不清楚),但是我们平时使用的时候并不想用root启动。
Supervisord 默认情况下并没有被安装成服务,它本身也是一个进程。官方已经给出了脚本可以将 Supervisord 安装成服务,可以参考这里查看各种操作系统的安装脚本,但是我用官方这里给的 Ubuntu 脚本却无法运行。
安装方法可以参考 serverfault 上的回答。
Ubuntu 系统,可以这么安装,这里选择了另外一个脚本
# 下载脚本
sudo su - root -c "sudo curl https://gist.githubusercontent.com/howthebodyworks/176149/raw/d60b505a585dda836fadecca8f6b03884153196b/supervisord.sh > /etc/init.d/supervisord"
# 设置该脚本为可以执行
sudo chmod +x /etc/init.d/supervisord
# 设置为开机自动运行
sudo update-rc.d supervisord defaults
# 试一下,是否工作正常
service supervisord stop
service supervisord start
注意:这个脚本下载下来后,还需检查一下与我们的配置是否相符合,比如默认的配置文件路径,pid 文件路径等,如果存在不同则需要进行一些修改。
其实还有一个简单的方法,因为 Linux 在启动的时候会执行 /etc/rc.local
里面的脚本,所以只要在这里添加执行命令就可以
注意:在/etc/rc.local脚本下添加开机自启命令
# Ubuntu系统在/etc/rc.local中添加以下内容
# 普通用户没有/var目录的修改权限,会导致supervisord启动不起来,我们需要先修改/var文件的权限
# 不知道为什么我每次修改后一重启就会恢复,所以我把修改权限的命令也放在了这个脚本
# 上面有说到过这个权限问题,这里我比较暴力的改了var下所有文件的权限
chmod 777 /var/*
# 此处要用supervisord的绝对路径,-u指定用户,-c配置文件的绝对路径
# 使用sudo find / -name supervisord查找supervisord的绝对路径
/usr/bin/supervisord -u witcomm -c /etc/supervisor/supervisord.conf
exit 0
以上内容需要添加在 exit 命令前,而且由于在执行 rc.local 脚本时,PATH 环境变量未全部初始化,因此命令需要使用绝对路径。
注意:
此时supervisor可以以普通用户开机启动了,有的程序也可以正常启动,但是gunicorn无法启动,报错: /bin/bash: gunicorn: 未找到命令,此时我们通过sudo find / -name gunicorn命令查找gunicorn的绝对路径,在supervisor下的配置文件中使用绝对路径即可,如下图
未完待续...