Author:rab
文章目录
前言
Supervisor
是一个进程控制系统,基于 Python
开发的一个 client/server
服务,它允许其用户监控和控制类 UNIX 操作系统上的许多进程(不支持 Windows 系统
)。能将一个普通的命令行进程变为后台 daemon
,并监控进程状态,异常退出时能自动重启。
用 Supervisor 管理的进程,当一个进程意外被杀死,Supervisort 监听到进程死后,会自动将它重新拉起,很方便的做到进程自动恢复的功能,不再需要自己写 shell 脚本来控制。
一、安装
常用三种安装方法:yum、pip、easy_install。接下来以 CentOS 7.9
为例,分别介绍安装步骤。
1.1 Yum
1、安装 Supervisor
yum install -y epel* && yum install -y supervisor
2、启动 Supervisor 并做开机自启动
systemctl start supervisord.service
systemctl enable supervisord.service
3、验证 Supervisor 版本
[root@supervisor ~]# supervisord -v
3.4.0
1.2 Pip
1、安装 Python3.x
没有 3.9 版本的 Python,想要安装更高版本的话,可通过编译安装。
但是 Python 3.6 是可以安装的,对于 Surprise 安装该版本即可。
yum install -y python36
2、安装 Supervisor
使用 pip 来安装,前提要保证 pip 版本大于 2.6
pip3.6 install supervisor
1.3 easy_install
easy_install-3.6 supervisor
二、配置
2.1 常用命令
supervisorctl status // 查看所有进程的状态
supervisorctl status es // 查看指定进程的状态
supervisorctl start|stop|restart all // 对所有进程操作
supervisorctl stop es // 停止es
supervisorctl start es // 启动es
supervisorctl restart es // 重启es
supervisorctl update // 配置文件修改后使用该命令加载新的配置
supervisorctl reload // 重新启动配置中的所有程序
2.2 配置文件
安装好后在/etc/会生成一个
supervisord.conf
文件及一个supervisord.d
文件目录。
supervisord.d
目录用来存放用户自定义的进程配置。
1、看看 supervisord.conf
配置文件内容
; Sample supervisor config file.
[unix_http_server]
file=/var/run/supervisor/supervisor.sock ; (the path to the socket file)
;chmod=0700 ; sockef file mode (default 0700)
;chown=nobody:nogroup ; socket file uid:gid owner
;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
;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))
[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=info ; (log level;default info; others: debug,warn,trace)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false ; (start in foreground if true;default false)
minfds=1024 ; (min. avail startup file descriptors;default 1024)
minprocs=200 ; (min. avail process descriptors;default 200)
;umask=022 ; (process file creation umask;default 022)
;user=chrism ; (default is current user, required if root)
;identifier=supervisor ; (supervisord identifier, default is '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 below 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: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///var/run/supervisor/supervisor.sock ; use a unix:// URL for a unix socket
;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
;username=chris ; should be same as http_username if set
;password=123 ; should be same as http_password if set
;prompt=mysupervisor ; cmd line prompt (default "supervisor")
;history_file=~/.sc_history ; use readline history if available
; The below sample program section 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)
;autorestart=true ; retstart at unexpected quit (default: true)
;startsecs=10 ; number of secs prog must stay running (def. 1)
;startretries=3 ; max # of serial start failures (default 3)
;exitcodes=0,2 ; 'expected' exit codes for process (default 0,2)
;stopsignal=QUIT ; signal used to kill process (default TERM)
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
;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 (default 10)
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false ; emit events on stdout writes (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 (default 10)
;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A=1,B=2 ; process environment additions (def no adds)
;serverurl=AUTO ; override serverurl computation (childutils)
; The below sample eventlistener section shows all possible
; eventlistener subsection values, create one or more 'real'
; eventlistener: sections to be able to handle event notifications
; sent by supervisor.
;[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)
;autorestart=unexpected ; restart at unexpected quit (default: unexpected)
;startsecs=10 ; number of secs prog must stay running (def. 1)
;startretries=3 ; max # of serial start failures (default 3)
;exitcodes=0,2 ; 'expected' exit codes for process (default 0,2)
;stopsignal=QUIT ; signal used to kill process (default TERM)
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
;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 (default 10)
;stdout_events_enabled=false ; emit events on stdout writes (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 ; # of stderr logfile backups (default 10)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A=1,B=2 ; process environment additions
;serverurl=AUTO ; override serverurl computation (childutils)
; The below sample group section 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 = supervisord.d/*.ini
2、说明
配置文件中看 [include]
部分,在该部分中,我们可以自定义应用程序管理配置,配置文件名以 *.ini
结尾,当然,你也可以根据自己的习惯来文件名,如files = supervisord.d/*.conf
。
三、实践
3.1 ES 服务
以 ES 为例进行 Supervisor
功能验证。
3.1.1 服务部署
1、安装 ES
执行安装脚本(略)
2、验证 ES
[root@supervisor elasticsearch]# lsof -i:9200
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 1698 yyds 121u IPv6 23984 0t0 TCP *:wap-wsp (LISTEN)
3.1.2 Supervisor 管理应用程序
1、新增 Supervisor 自定义配置
用于管理 ES 的生命周期
vim /etc/supervisord.d/es.ini
[program:es]
command=/data/elasticsearch/bin/elasticsearch
directory=/data/elasticsearch
user=yyds
numprocs=1
priority=1
autostart=true
startsecs=30
satrtretries=3
autorestart=true
stopasgroup=true
killasgroup=true
redirect_stderr=true
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=10
stdout_logfile=/data/elasticsearch/logs/supervisor.log
# 注意:command 后面是启动命令,不能写成后台方式启动,如:nohup java -jar xxx.jar & 否则无法启动
2、在上面 ES 安装中,已经启动 ES 了,为效果先 kill 掉
3、启动服务
supervisord -c /etc/supervisord.conf
4、看看状态
[root@supervisor ~]# supervisorctl status es
es RUNNING pid 1269, uptime 0:01:46
此时,如果你的服务器重启了,supervisor 管理的进程会随服务器的重启而重启,前提是你本身的
supervisord
做了开机自启动。
3.2 Java 应用程序
3.2.1 构建 jar 测试包
3.2.2 Supervisor 管理应用程序
1、新增配置文件
[program:java-test]
command=java -jar /root/java_code/target/springboot-test-1.0-SNAPSHOT.jar
directory=/root/java_code/target
user=root
numprocs=1
priority=1
autostart=true
startsecs=30
satrtretries=3
autorestart=true
stopasgroup=true
killasgroup=true
redirect_stderr=true
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=10
stdout_logfile=/root/java_code/logs/supervisor.log
2、重载配置文件
supervisorctl reload
3、验证
去浏览器访问:http://192.168.56.120:8080/test/
3.3 启用 web 管理
具备 Python 环境
1、打开 HTTP web 字段注释
vim /etc/supervisord.conf
# 定义IP:PORT
# 定义用户名/密码
# 重载一下配置
# 注意端口不要与系统已有端口冲突
2、重载配置
supervisorctl reload
3、web 验证
-
登录
-
看看管理界面
-
可进行相关的点击操作
刷新、停止(所有)、重启(所有)、查看日志、清理日志
-
查看日志
四、Supervisord 对比 Systemd
首先,Supervisord 是 Python 写的一个守护进程,在 Linux 中(yum安装的 Supervisord)它本身也是由 Systemd 来管理。
而且 Systemd 也可以实现后台守护进程,稳定性相对于 Supervisor 要强,但是 Supervisord 具有统一进程管理的优势,同时也具备 Web 终端管理,实现进程的一键式管理
。如果重启 Supervisord ,那 Supervisord 管理的整个进程也要被重启,对于 Systemd 来说,一个进程对应一个 Systemd 后台管理,而且是 Linux 原生的后台守护进程。
以下为 Systemd 后台管理进程的一个案例,其实现效果等同于 Supervisord。
vim /usr/lib/systemd/system/java-test.service
[Unit]
Description=java-test project service
Requires=network.target
[Service]
#User=root
#Group=root
Type=simple
WorkingDirectory=/root/java_code/target
ExecStart=/usr/bin/java -jar /root/java_code/target/springboot-test-1.0-SNAPSHOT.jar > /dev/null 2>&1
ExecStop=/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=30
StartLimitInterval=30
[Install]
WantedBy=multi-user.target graphical.target
重载 systemd
systemctl daemon-reload
启动 Java 进程
# 启动
systemctl start java-test.service
# 开机自启
systemctl enable java-test.service
五、FAQ
5.1 加载 supervisor 配置报错
1、报错现象
Error: Another program is already listening on a port that one of our HTTP servers is configured to use. Shut this program down first before starting supervisord.
For help, use /usr/bin/supervisord -h
2、解决方案
# 找到sock文件并unlink或找到PID并kill掉 pe -ef |grep supervisord
[root@supervisor logs]# find / -name supervisor.sock
/run/supervisor/supervisor.sock
# unlink 或 kill
[root@supervisor logs]# unlink /run/supervisor/supervisor.sock
# 再次加载
[root@supervisor logs]# supervisord -c /etc/supervisord.conf
# 再或者重启supervisor
systemctl restart supervisord.service
5.2 supervisor 启动太快
1、报错现象
[root@supervisor ~]# supervisorctl status
es FATAL Exited too quickly (process log may have details)
面向百度了一下,说把
startsecs
值设置为 0。
[program:es]
command=/data/elasticsearch/bin/elasticsearch
directory=/data/elasticsearch
user=yyds
numprocs=1
priority=1
autostart=true
startsecs=0
satrtretries=3
autorestart=true
stopasgroup=true
killasgroup=true
redirect_stderr=true
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=10
stdout_logfile=/data/elasticsearch/logs/supervisor.log
好,重启后,确实变为 RUNNING 了
[root@supervisor ~]# supervisorctl status
es RUNNING pid 22768, uptime 0:00:00
但是,并没什么 R 用,ES 进程并没有起来。
在看看
supervisor.log
日志。
提示:没有找到 Java 环境。
2、解决方案
为什么一开始却是执行成功的呢?而我重启服务器后就说无法找到 JAVA 环境呢?安装日志输出内容,JAVA 路径必须为
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
# 先来看看我本机的 JDK 路径
[root@supervisor elasticsearch]# which java
/opt/jdk/bin/java
# 与日志输出的路径不一致,导致supervisor找不到JDK环境,从而导致ES无法运行,因为ES依赖于JDK
重新修改一下 JDK 二进制路径
[root@supervisor elasticsearch]# rm -rf /etc/profile.d/jdk.sh
[root@supervisor elasticsearch]# source /etc/profile
做软链接,再次查看 JDK 路径
[root@supervisor elasticsearch]# ln -s /opt/jdk/bin/* /usr/bin/
重启后还报错
而我本机已经设置了最大文件打开数了啊
[root@supervisor logs]# ulimit -H -n
65536
在看看 Supervisor 默认的配置文件,因该就是配置文件默认值的问题
该值不能超过你操作系统本身的文件大小,于是将该值设置为 65536
然后再次重启 Supervisor
看看 ES 进程