Supervisor 可以在 Linux/Mac OSX/FreeBSD 这类系统下,监控一个进程的运行状态,在进程挂掉之后自动重启它。于是一个普通的应用程序不用做任何修改就可以像是一个系统服务那样运行了,在维护服务器的时候十分方便。

简单使用可以参考一些软件提及的、关于如何利用 Supervisor 把它服务化运行的说明,例如 用 Supervisor 运行 Shadowsocks

1.  基本安装

几乎所有的 Linux 发行版都自带了 Supervisor,例如在 Debian 下可以直接这样:

apt-get install supervisor

2.  被监控的服务配置

配置文件一般都放在 /etc/supervisor/conf.d/ 这个目录下,每个服务使用一个独立的文件,例如会为 frp 服务建立一个配置文件 /etc/supervisor/conf.d/frps.conf,内容写成这样:

[program:frps]
command=/opt/frp/frps -c /opt/frp/frps.ini
autorestart=true
user=nobody

配置文件中如果在行首加英文 ; 号,可以把所在行注释掉。

2.1  其他一些常用的配置参数

  • directory 参数:用于指定服务程序的执行目录,例如:
    directory=/var/www/something/
  • environment 参数:用于指定服务程序能读到的环境变量,例如:
    environment = HOME="/home/appuser", USER="appuser"
  • 如果要禁止一个服务自动启动,那么需要把 autorestart 和 autostart 两个参数都设成 false

2.2  有时需要额外配置的性能调优

  • 可以在 /etc/default/supervisor 最后加一行:
    ulimit -n 51200

3.  常用服务管理指令

这里所有的“服务名”,指的都是配置文件里 program: 后面写的名字。

  • 服务的启动、停止、重启,可以这样:
    supervisorctl start 服务名
    supervisorctl stop 服务名
    supervisorctl restart 服务名
  • 更新配置文件内容后,让 Supervisor 重新载入设置:
    service supervisor start
    supervisorctl reload
  • 如果遇到问题,可以检查服务的运行日志:
    supervisorctl tail -f 服务名 stderr

4.  常见使用技巧

4.1  怎样执行 virtualenv 环境中的 Python 程序?

只要在 Supervisor 配置中使用 venv 环境下的完整命令路径就行,比如:

command=/var/www/venv_mypy/bin/gunicorn -t 120 -w 2 --threads 4 -b 0.0.0.0:5050 app:app

当然,有时候 Python 脚本对当前运行目录也会有要求,这时候就得在 Supervisor 配置中把 directory 参数也设定好。

4.2  执行一个非持续运行的 Shell 脚本,应该怎么配置?

详细参照 how to set supervisor to run a shell script

比如这样写 conf 配置文件:

[program:my-program-name]
command = /bin/bash /path/to/my/command.sh
startsecs = 0
autorestart = false
startretries = 1

这个方法也可以用于启动 Tomcat 这类依靠 start.sh 脚本来运行的服务。

在启动一个服务时,如果需要串行执行多条指令,也可以用这个办法都编写进同一个 Shell 脚本里。如果指令比较简单,也可以不用专门创建 .sh 文件,而是可以利用 -c 参数类似这样写:

command=/bin/sh -c "touch ~a.c && tail -f /dev/null"

4.3  怎样避免 Supervisor 管理下的大量服务同时启动以至于互相拖垮资源?

原始讨论在 supervisord Starts All Processes at the Same Time #122

目前应该还没有功能或者插件级的解决办法,上文讨论链接中提到了一个名为 start_rate_limit.sh 的脚本,可以用来手工添加互斥等待,变相实现多个服务间的串行启动。

4.4  如果多个服务之间有依赖关系怎么办,比如要先运行数据库再运行应用?

比较舒服的方法应该是利用 supervisord-dependent-startup 这个插件来实现。

4.5  怎样让 Supervisor 管理下的服务根据不同情形做不同的启动动作?

原始讨论在 Run a supervisord program conditionally

大体思路就是用一个 Shell 脚本去读取环境变量的变化,来做一些 if-else 判断。

4.6  怎样实现 Supervisor 自动启动服务的时候发出邮件通知?

可以用插件 Superlance 来实现,很简单。

GlossyBlue theme adapted by David Gilbert
Powered by PmWiki