1. 应用场景

当在命令行中运行某些持续任务时,所运行的程序会占用住当前会话的交互,无法进行其它操作(例如,用dotnet myweb.dll命令启动一个.NET web项目后,终端会被一直占用,直到任务结束或ctrl+c强制中断),解决办法是在命令后面加一个&,使命令工作在后台,交出控制台会话,并在需要时用fg调出。

这样做,虽然用户会重新夺回了会话的交互权利,但有一个致命的缺点:一旦当前会话结束(关闭 ssh窗口),任务就随着会话的注销而烟消云散。

最简陋的解决办法是使用nohup运行任务,这样可以忽略会话注销信号,一直将任务保持住,也可以通过输出重定向将所有输出保存到指定文件。

nohup command &
# 添加&符号,使命令在后台运行

类似地,screen命令也能实现相同效果,但是它们只解决了后台运行、任务保持的问题;如果想以值守方式运行任务,希望错误/中断后自动重试运行,就需要借助Supervisor来实现。

2. supervisor安装

只需要apt install supervisor / yum install supervisor 即可。

3. 配置文件

安装完成后,在supervisor的值守文件目录下(默认情况下,ubuntu的位置在 /etc/supervisor/conf.d/,CentOS的位置在 /etc/supervisord.d/)为需要守护的实例创建配置文件(ubuntu版本默认要求配置文件以.conf结尾,CentOS默认要求配置文件以.ini结尾,此项要求取决于主配置文件supervisor.conf中的配置项,可自行修改)。

# 在supervisor.conf中指定了配置文件保存目录
# 值守文件配置可以直接写到supervisor.conf,
# 也可以放 conf.d 目录(推荐后者)

# Ubuntu /etc/supervisor/upervisor.conf
[include]
files = /etc/supervisor/conf.d/*.conf

# CentOS /etc/supervisor.conf
[include]
files = supervisord.d/*.ini

虽然两个系统配置文件位置不一样,并且对文件名后缀默认要求也不一样,但是配置文件的写法完全一致。

# /etc/supervisor/conf.d/ddns.conf
[program:dotnet]
command=/usr/local/dotnet/dotnet /var/www/ddns/DDNS.dll
directory=/var/www/ddns
autostart=true
autorestart=true
stderr_logfile=/var/www/daemon-ddns.err
stdout_logfile=/var/www/daemon-ddns.log
# 这儿只是记录了控制台标准输出和错误输出,如果应用配置
# 了自己的日志,查看日志的时候还是按照应用的配置为准
log_stderr=true
log_stdout=true
user=root
# /etc/supervisord.d/redis.ini
[program:sys-redis]
command=/usr/local/bin/redis-server /etc/redis.conf
directory=/usr/local/bin
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/redis-server.log
stderr_logfile=/var/log/supervisor/redis-server.err
log_stderr=true
user=root
# /etc/supervisor/conf.d/java.conf
[program:apisvc]
command=java -Xms128m -Xmx1g -jar apisvc.jar --spring.config.location=application.properties --spring.profiles.active=Q
directory=/data/main
autostart=true
autorestart=true
stderr_logfile=/data/main/logs/daemon-apisvc.err
stdout_logfile=/data/main/logs/daemon-apisvc.log
log_stderr=true
log_stdout=true
user=root

4. 常用操作

# 查看指定任务或者所有任务的状态
supervisorctl status [name]

# 运行/停止/重启指定任务或者所有任务
supervisorctl  start|stop|restart  name|all

# 更新配置文件以后,重新加载配置文件
supervisorctl  update

# 加入新的配置文件后,将其添加到任务列表
supervisorctl  add  name

# 以tail -f持续输出的模式查看标准输出日志文件
supervisorctl tail -f <name>
# 查看标准输出日志文件结尾100字节内容(默认查看标准输出)
supervisorctl tail -n 100 <name>
# 查看错误输出日志文件结尾1600字节内容(-n默认值1600)
supervisorctl tail <name> stderr

# 添加服务
supervisorctl add newsvc
supervisorctl start newsvc

# 修改服务
supervisorctl update newsvc
supervisorctl restart newsvc

5. 一些细节

5.1 supervisor的完整配置是主配置文件+include目录所有实例配置文件的合集,类似nginx/apache的vhosts配置,以这种插入式的结构进行配置,将实例文件剥离出主配置文件,并且以单独的文件进行配置,可以更清晰便捷地管理所有服务;

5.2 添加/修改服务均可在不影响其它服务的情况下进行,只需要在执行supervisorctl命令的时候指定具体项目名即可,而一些管理性质的命令(stop/start/update/restart) 也建议在命令里指定具体的项目名,否则命令将对所有服务生效,可能造成正常服务的重启;

5.3 supervisor日志并非所有情况下都有用处,它只是简单地将控制台输出(标准输出/错误输出)全部保存下来,如果项目本身有自己的日志系统,可以直接忽略supervisor日志。

分类: articles