环境依赖

# python2.7版本
# supervisord支持include功能

安装

# 建议最新版本
pip install supervisor==4.1.0

配置

# /root/.virtualenvs/test/bin/echo_supervisord_conf
# 如果是virtualenv环境需要软连接用于管理脚本调用
[ -f /usr/bin/supervisord ] || ln -s `which supervisord` /usr/bin/supervisord
[ -f /usr/bin/echo_supervisord_conf ] || ln -s `which echo_supervisord_conf` /usr/bin/echo_supervisord_conf
[ -f /usr/bin/supervisorctl ] || ln -s `which supervisorctl` /usr/bin/supervisorctl

# 建议使用系统环境的,因为supervisord基于系统层面
[ -f /usr/bin/supervisord ] || ln -s /usr/local/python3/bin/supervisord /usr/bin/supervisord
[ -f /usr/bin/echo_supervisord_conf ] || ln -s /usr/local/python3/bin/echo_supervisord_conf /usr/bin/echo_supervisord_conf
[ -f /usr/bin/supervisorctl ] || ln -s /usr/local/python3/bin/supervisorctl /usr/bin/supervisorctl
# 生成supervisord配置文件模板
# echo_supervisord_conf > /etc/supervisord.conf 	# 默认配置文件
vim /etc/supervisord.conf

##################################################################
[unix_http_server]
file=/var/run/supervisor.sock   ; supervisorctl通讯用

[supervisord]
logfile=/var/log/supervisor/supervisord.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=info
pidfile=/var/run/supervisord.pid
nodaemon=false
# 注意:进程没有通过login流程,导致ulimit为系统默认,建议最好在管理脚本里面填写ulimit的限制
minfds=65535
minprocs=200

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; supervisorctl的连接路径

[include]
files = /etc/supervisord.d/*.conf
##################################################################
# centos6管理脚本

[ -f /etc/init.d/supervisord ] || ( curl -o /etc/init.d/supervisord https://raw.githubusercontent.com/Supervisor/initscripts/master/redhat-init-jkoppe && chmod 755 /etc/init.d/supervisord)

# 不注释的话ansible启动会失败 
vim /etc/init.d/supervisord
set -o nounset
改成
# set -o nounset

# 生成基础配置文件
[ -f /etc/sysconfig/supervisord ] || cat > /etc/sysconfig/supervisord << EOF
PIDFILE=/var/run/supervisord.pid
OPTIONS="-c /etc/supervisord.conf"
WAIT_FOR_SUBPROCESSES=yes
sleep=1
total_sleep=120
EOF

启动

mkdir /var/log/supervisor
/etc/init.d/supervisord start

# 抓取的是项目进程,没有项目进程,显示(supervisord is stopped),实际上supervisord进程存在
/etc/init.d/supervisord status
ps aux|grep supervisord

管理进程示例

mkdir /var/log/supervisor

# 支持include功能
vim /etc/supervisord.conf
[include]
files = /etc/supervisord.d/*.conf

# 增加项目
mkdir /etc/supervisord.d
vim /etc/supervisord.d/test.conf

##################################################################
# 程序名称,在 supervisorctl 中通过这个值来对程序进行一系列的操作
[program:test]
# 用哪个用户启动
user=root
# 在 supervisord 启动的时候也自动启动
autostart=True
# 优先级
priority=1
# 程序名称,在 supervisorctl 中通过这个值来对程序进行一系列的操作
process_name=%(program_name)s_%(process_num)02d
# 启动进程数量,程序运行的副本个数,默认为1,如果值大于1,则`process_name` 必须包含 `%(process_num)s`
numprocs=1
# 程序异常退出后自动重启
autorestart=True
# 异常退出重试次数,默认3
startretries=3
# stopasgroup=true #  默认为false,不要开启(比如test重启了数据库,关闭了test,数据库也会被关闭)
stopsignal=TERM
#  stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile=/var/log/supervisor/%(program_name)s_%(process_num)02d.log
#  stdout 日志文件大小,默认50MB
stdout_logfile_maxbytes=20MB
#  stdout 日志文件备份数,默认是10
stdout_logfile_backups = 20
# 把 stderr 重定向到 stdout,默认 false
redirect_stderr=True
# 程序的启动目录(pwdx可以查看到这个目录)
directory=/tmp/
# 可以通过 environment 来添加需要的环境变量,一种常见的用法是使用指定的 virtualenv 环境
# environment=PATH="/home/app_env/bin"
# 启动命令,与手动在命令行启动的命令是一样的
command=sleep 3600
##################################################################

常见操作

update  # 修改、新增、者删除的相关项目:只会重启相关变化项目
Reload config and add/remove as necessary, and will restart affected programs

reload  # 直接重新加载supervisord配置文件(supervisord进程id不变),管理的项目进程会被重启(项目进程id变了)、新增的配置文件也会加载
Restarts the remote supervisord 
# Supervisor是用Python开发的一套client/server架构的进程管理程序,能做到开机启动,以daemon进程的方式运行程序,并可以监控进程状态等等。
# client支持rpc,web,supervisorctl
# 配置变化用下面命令生效(所有配置变化的进程都会重启)
supervisorctl update

# 常见命令
supervisorctl stop program_name  # 停止某一个进程,program_name 为 [program:x] 里的 x
supervisorctl start program_name  # 启动某个进程
supervisorctl restart program_name  # 重启某个进程
supervisorctl stop groupworker:  # 结束所有属于名为 groupworker 这个分组的进程 (start,restart 同理)
supervisorctl stop groupworker:name1  # 结束 groupworker:name1 这个进程 (start,restart 同理)
supervisorctl stop all  # 停止全部进程,注:start、restartUnlinking stale socket /tmp/supervisor.sock
、stop 都不会载入最新的配置文件
supervisorctl reload  # 载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程
supervisorctl update  # 根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启
supervisorctl status  # 查看管理进程的状态

常见的坑

重启管理进程导致数据库被关闭

stopasgroup=trued导致的

# 出现的场景:
# Supervisord的服务A重启另外一个服务B,Supervisord重启A的时候,B也被关闭了
# 现实中的坑
# 更新脚本客户端(rabbitmq接收消息)-发起重启数据库,Supervisord重启更新脚本进程的时候,数据库也异常关闭了

# 1、检测stopasgroup
egrep -r '^\s*stopasgroup\s*=\s*true' /etc/supervisord.*

# 2、检测配置文件变更(以防止手动修改)
# 老版本2.1没有reread参数
# 2.1 确认版本
supervisorctl reread|grep 'Unknown syntax'
# 2.2 检测配置文件
supervisorctl reread | grep changed

开机自启动ulimit没有生效

应用程序未产生core原因定位

ulimit使用原理: 用户登录 -> 调用pam_limits.so -> pam_limits.so初始化ulimit配置,管理其它程序就会依赖此环境 开机自启动:程序会导致ulimit环境获取失败,各个应用程序会使用自己的默认值,supervisord的配置参数为: minfds(默认值1024) 对应句柄数nofile minprocs(默认值200) 对应进程数nproc 注意:其它的ulimit无法配置,比如core

# ulimit的其它参数将无法生效
[supervisord]
minfds=1024 ; (min. avail startup file descriptors;default 1024) # 最小对应的句柄数? 建议改成:65535
minprocs=200 ; (min. avail process descriptors;default 200) # 最小对应的进程数? 这个理论上够用

# 建议:在启动脚本声明ulimit,防止被任何环境污染
ulimit -SH -c unlimited;ulimit -SH -s 65535;ulimit -SH -n 65535;ulimit -SH -u 65535

# # 堆栈大小
# stack:-s
# # 句柄数
# nofile: -n: file descriptors
# # 可以开启的子进程数量
# nproc: -u: processes/threads