Linux命令(3)supervisord

supervisord类似systemd,帮助用户管理应用程序,不需要再使用nohup这样的命令去启动并且托管。

同时supervisord还有系统保活、自动拉起等功能,如果因为意外操作系统重启或者进程遇到意外自动退出了,supervisord都会自动重新启动被管理的程序。

安装

Centos 7.9

1
2
$ sudo yum install epel-release
$ sudo yum install -y supervisor

启动supervisor

1
2
3
4
$ sudo systemctl enable supervisord # 开机自启动
$ sudo systemctl start supervisord # 启动supervisord服务
$ sudo systemctl status supervisord # 查看supervisord服务状态
$ ps -ef|grep supervisord # 查看是否存在supervisord进程

对于Centos系统,主配置文件在/etc/supervisord.conf,被管理的程序的配置文件放在/etc/supervisord.d内。

1
2
$ ls /etc/supervisord.
supervisord.conf supervisord.d/

打开/etc/supervisord.conf配置文件,可以看到最后一行引用了supervisord.d文件夹内以ini为文件后缀的文件。

1
2
[include]
files = supervisord.d/*.ini

有的Linux系统默认是.conf结尾的配置文件,需要根据具体系统定义配置文件后缀。

使用

查看安装版本

1
2
$ supervisord -v
3.3.1

添加程序

这里用一个简单的输出日期时间的程序来演示。

1
2
3
$ mkdir -p /home/shuyi/echo-time
$ cd /home/shuyi/echo-time
$ touch echo_time

写一个定时输出时间的shell命令。

1
2
3
4
5
$ cat echo_time
while true; do
echo `date '+%Y-%m-%d %H:%m:%S'`
sleep 1
done

可以直接执行这个脚本,每隔1秒钟就会输出一次当前时间。

1
2
3
4
5
$ sh echo_time
2023-07-08 14:07:53
2023-07-08 14:07:54
2023-07-08 14:07:55
...

现在进行配置文件创建。

1
$ sudo touch /etc/supervisord.d/echo-time.ini

先写一个简单的配置,里面只有一个启动命令,后面会有比较详细的介绍。

1
2
3
4
$ cat /etc/supervisord.d/echo-time.ini
[program:echo_time]
command=sh /home/shuyi/echo-time/echo_time
stdout_logfile=/home/shuyi/echo-time/echo.log

添加完成之后重新读取配置。

1
2
$ sudo supervisorctl reread
echo_time: available

更新进程。

1
2
$ sudo supervisorctl update
echo_time: added process group

这样刚才添加程序的就运行起来了,通过ps命令可以看到运行的进程(启动用户为root)。

1
2
3
$ ps -aux | grep echo
root 1973 0.0 0.0 115408 1484 ? S 15:22 0:00 sh /home/shuyi/echo-time/echo_time
shuyi 2214 0.0 0.0 112780 704 pts/0 S+ 15:24 0:00 grep --color=auto echo

查看输出日志,可以看到进程在往文件里面打印内容了。

1
2
3
4
5
6
$ tail -f echo.log
2023-07-08 15:07:16
2023-07-08 15:07:17
2023-07-08 15:07:18
2023-07-08 15:07:19
...

查看进程运行状态

1
2
$ sudo supervisorctl status
echo_time RUNNING pid 3871, uptime 0:06:49

Web管理

为了方便管理,可以开启自带的web控制台。

修改/etc/supervisord.conf配置文件。

1
2
3
4
[inet_http_server]         ; web界面配置
port=*:9001 ; web监听端口和ip地址
username=user ; 默认是没有username
password=123 ; 默认没有密码

重启supervisord。

1
$ sudo systemctl restart supervisord

打开http://192.168.0.112:9001页面就可以看到所有管理中的应用程序的状态。

如果出现无法访问的问题,应该是防火墙没有开,可以通过下面的命令在centos打开9001端口。

1
2
$ sudo firewall-cmd --permanent --add-port=9001/tcp
$ sudo firewall-cmd --reload

再次访问就可以看到页面了。

p1

在这个页面用户可以选择重启(restart)、停止(stop)、清除日志(clear log)或者查看日志(Tail -f),非常方便。

常用配置

配置样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[program: x]               ; x为程序名称,supervisord会根据这个名字管理进程
command=sh echo_time.sh ; 启动命令
directory=/path/to/dir ; 命令执行的目录
autorestart=true ; 程序意外退出是否自动重启
autostart=true ; 是否自动启动,如果是true,则supervisord启动的时候,会自动启动这个程序
startsecs=1 ; 自动重启间隔,只有程序在保持了1秒钟的running状态之后,supervisord才认为是启动成功的
startretries=3 ; 尝试重启次数
redirect_stderr=true ; 配置stderr日志,如果是true,则err日志也会保存到stdout_logfile目录内,类似于2>&1
stopsignal=INT ; 用于终止进程的信号,可以使用TERM/HUP/INT/QUIT/KILL/USR1/USR2
stopwaitsecs=10 ; 等待进程最后终止的时间,如果使用stopsignal结束进程,在10秒钟内进程还没有结束,就使用SIGKILL去结束进程
loglevel=debug ; supervisord日志的日志级别
stderr_logfile=/path/to/error-sup.log ; supervisor错误日志文件,如果redirect_stderr是true,则无效
stdout_logfile=/path/to/info-sup.log ; supervisor输出日志文件
environment=ASPNETCORE_ENVIRONMENT=Production ; 进程环境变量
user=ubuntu ; 进程执行的用户身份

重启次数控制

在上面的常用配置中可以看到,有autorestartstartsecsstartretries控制程序的重启。

当启动程序的时候,程序在等待startsecs秒之后才进入RUNNING,supervisor认为程序启动成功,然后程序从RUNNING状态EXIT的情况下,supervisor才会尝试无限次数重启。

如果在startsecs秒之后没有进入RUNNING状态,说明程序启动失败,此时启动失败次数+1。

当启动失败次数超过startretries之后,supervisor才会停止尝试重启。

我们使用一个新的echo_failed脚本,这个脚本在原来的echo_time做了一些修改,去掉了while循环,在等待2秒之后直接退出程序。

1
2
3
4
5
$ cat echo_failed
echo 'start date'
echo `date '+%Y-%m-%d %H:%m:%S'`
sleep 2
echo 'exit date'

修改这个程序的supervisord配置文件。

1
2
3
4
5
6
7
$ cat /etc/supervisord.d/echo-time.ini
[program:echo_time]
command=sh /home/shuyi/echo-time/echo_failed
stdout_logfile=/home/shuyi/echo-time/echo.log
autorestart=true
startsecs=10
startretries=3

重新读取配置文件,更新程序。

1
2
3
4
5
$ sudo supervisorctl reread
echo_time: changed
$ sudo supervisorctl update
echo_time: stopped
echo_time: updated process group

然后启动程序发现系统在重试了三次之后就不再尝试,这个进程进入了FATAL状态。

1
2
$ sudo supervisorctl start echo_time
echo_time: ERROR (spawn error)

查看日志。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ tail -200f echo.log
start date
2023-07-08 17:07:59
exit date
start date
2023-07-08 17:07:02
exit date
start date
2023-07-08 17:07:06
exit date
start date
2023-07-08 17:07:11
exit date

检查状态,发现是FATAL状态,supervisord并没有坚持重启。

1
2
$ sudo supervisorctl status echo_time
echo_time FATAL Exited too quickly (process log may have details)

当我们把配置文件里面的startsecs设置成1秒。

1
2
3
4
$ cat /etc/supervisord.d/echo-time.ini
...
startsecs=1
...

每次启动echo_time脚本之后1秒之内程序都是在运行的,supervisor认为程序是RUNNING状态,当2秒之后supervisor尝试重新拉起echo_time程序,重试失败次数会重新从0开始,并不会超过startretries阈值。

注意

如果使用supervisor监控shell脚本,不能在脚本中完全使用nohup、setsid等后台运行的命令,不然supervisor会认为程序自动退出从而不断重启脚本。

参考

Supervisor: A Process Control System
Supervisor使用教程
Supervisor (进程管理利器) 使用说明 - 运维笔记