更多内容请点击 我的博客 查看,欢迎来访。
前言
对于大部分程序员来说,主要工作都是进行编码以及一些简单的中间件安装,这就导致了很多人对于“运维”相关的工作会比较生疏。例如当我们拥有一台自己的服务器以后,可能会在上面跑一跑自己blog程序,mysql,nginx等等。当程序越来越多了没有一个统一的入口管理启停,也可能会遇到一些特殊的原因导致程序被kill掉了,这时候又没装相关的监控程序或者脚本(太麻烦了懒得装,机器配置差不想装),所以只能当我们访问自己程序发现异常的时候才会登上服务器查找原因。
Supervisor 介绍
Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。它是通过fork/exec的方式把这些被管理的进程当作supervisor的子进程来启动,这样只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去即可。也实现当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,可以选择是否自己启动和报警。
官网
http://supervisord.org/installing.html
终于在Python3下可以正常使用pip安装了。
由于Supervisor是用Python开发的程序,在安装前,请确保系统已安装Python
安装
虚拟环境不讲了,看你~
pip安装
pip install supervisor
upervisor安装完成后,会生成三个执行程序:supervisortd
、supervisorctl
、echo_supervisord_conf
,分别是supervisor的守护进程服务(用于接收进程管理命令)、客户端(用于和守护进程通信,发送管理进程的指令)、生成初始配置文件程序。
生成配置文件
(ITNest) root@PxeCtrlSys:/home/user/ITNest# mkdir Supervisor
(ITNest) root@PxeCtrlSys:/home/user/ITNest# cd Supervisor/
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# echo_supervisord_conf > supervisord.conf
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# ls
supervisord.conf
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# cat supervisord.conf
注:以分号(;)开头,表示该行已被注释
[unix_http_server]
file=/tmp/supervisor.sock ;UNIX socket 文件,supervisorctl会使用其与supervisord通信
;chmod=0700 ;socket文件的mode,默认是0700
;chown=nobody:nogroup ;socket文件的owner,格式:uid:gid
;[inet_http_server] ;HTTP服务器,提供web管理界面
;port=127.0.0.1:9001 ;Web管理后台运行的IP和端口,如果开放到公网,需要注意安全性
;username=user ;登录管理后台的用户名
;password=123 ;登录管理后台的密码
[supervisord]
logfile=/tmp/supervisord.log ;日志文件,默认是 $CWD/supervisord.log
logfile_maxbytes=50MB ;日志文件大小,超出会rotate,默认 50MB。如果设成0,表示不限制大小
logfile_backups=10 ;日志文件保留备份数量默认10,设为0表示不备份
loglevel=info ;日志级别,默认info,其它: debug,warn,trace
pidfile=/tmp/supervisord.pid ;pid 文件
nodaemon=false ;是否在前台启动,默认是false,即以 daemon 的方式启动
minfds=1024 ;可以打开的文件描述符的最小值,默认 1024
minprocs=200 ;可以打开的进程数的最小值,默认 200
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ;通过UNIX socket连接supervisord,路径与unix_http_server部分的file一致
;serverurl=http://127.0.0.1:9001 ; 通过HTTP的方式连接supervisord
; [program:xx]是被管理的进程配置参数,xx是进程的名称
[program:xx]
command=/opt/apache-tomcat-8.0.35/bin/catalina.sh run ; 程序启动命令
autostart=true ; 在supervisord启动的时候也自动启动
startsecs=10 ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
autorestart=true ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启
startretries=3 ; 启动失败自动重试次数,默认是3
user=tomcat ; 用哪个用户启动进程,默认是root
priority=999 ; 进程启动优先级,默认999,值小的优先启动
redirect_stderr=true ; 把stderr重定向到stdout,默认false
stdout_logfile_maxbytes=20MB ; stdout 日志文件大小,默认50MB
stdout_logfile_backups = 20 ; stdout 日志文件备份数,默认是10
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out
stopasgroup=false ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程
killasgroup=false ;默认为false,向进程组发送kill信号,包括子进程
;包含其它配置文件
;[include]
;files = relative/directory/*.ini ;可以指定一个或多个以.ini结束的配置文件
配置管理进程
进程管理配置参数,不建议全都写在s upervisord.conf 文件中,建议每个进程写一个配置文件,并放在include
配置块中files
指定的目录下,通过include
包含进 supervisord.conf 文件中。
daphne启动Channels
例如下方是用来管理Django Channels的启动配置,参考 https://channels.readthedocs.io/en/latest/deploying.html
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# vim daphne.ini
# 加入下面的内容
[program:daphne]
directory=/home/user/ITNest
command=daphne -b 127.0.0.1 -p 8001 --proxy-headers ITNest.asgi:application
autostart=true
autorestart=true
stdout_logfile=/tmp/websocket.log
redirect_stderr=true
celery启动Django异步任务
# 配置内容
[program:celery]
# celery命令的绝对路径
command=/root/.pyenv/versions/StarMeow/bin/celery -A StarMeow worker -B -l info
# 项目路径
directory=/root/django-web/StarMeow
# 日志文件路径
stdout_logfile=/var/log/myweb/celery.log
# 自动重启
autorestart=true
# 如果设置为true,进程则会把标准错误输出到supervisord后台的标准输出文件描述符
redirect_stderr=true
修改supervisor配置文件
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# vim supervisord.conf
# 最后加上
[include]
;files = relative/directory/*.ini
files = /home/user/ITNest/Supervisor/*.ini
启动Supervisor服务
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# supervisord -c supervisord.conf
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# tail /tmp/websocket.log
管理用户进程
交互终端
supervisord启动成功后,通过supervisorctl客户端来管理用户进程:启动、停止、重启。运行supervisorctl命令,会进入supervisor客户端的交互终端,并会列出当前所管理的所有进程。
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# supervisorctl -c supervisord.conf
daphne RUNNING pid 17657, uptime 0:35:51
上面就是创建的配置文件[program:daphne]
指定的名字
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# supervisorctl
http://localhost:9001 refused connection
supervisor> help
default commands (type help ):
=====================================
add exit open reload restart start tail
avail fg pid remove shutdown status update
clear maintail quit reread signal stop version
# 可以直接在交互命令中操作
supervisor> stop daphne
daphne: stopped
supervisor> start daphne
daphne: started
输入help
,可以查看命令列表。如果想看某个命令的作用,运行“help 命令名称”,如:help stop
。stop daphne
表示停止daphne
进程,stop all
表示停止所有进
supervisorctl动作
命令 | 说明 | |
---|---|---|
help |
打印可用操作的列表 | |
help |
打印帮助 |
|
add |
激活进程/组配置中的任何更新 | |
remove |
从活动配置中删除进程/组 | |
update |
重新加载配置和添加/删除必要的,并将重新启动受影响的程序 | |
update all |
重新加载配置和添加/删除必要的,并将重新启动受影响的程序 | |
update |
更新特定的组,并将重新启动受影响的程序 | |
clear |
清除进程的日志文件 | |
clear |
清除多个进程的日志文件 | |
clear all |
清除所有进程的日志文件 | |
fg |
连接到前台模式下的进程,按Ctrl+C退出前台 | |
pid |
得到主控制器的PID | |
pid |
按名称获取单个子进程的PID | |
pid all |
获取每个子进程的PID,每行一个 | |
reload |
重新启动远程监控程序 | |
reread |
重新加载守护进程的配置文件,无需添加/删除(无需重新启动) | |
restart |
重启进程,注意:Restart不会重新读取配置文件。对此,请参阅reread和update | |
restart |
重启组内所有进程,注意:Restart不会重新读取配置文件。对此,请参阅reread和update | |
restart |
重新启动多个进程或组,注意:Restart不会重新读取配置文件。对此,请参阅reread和update | |
restart all |
重启所有进程,注意:Restart不会重新读取配置文件。对此,请参阅reread和update | |
signal |
||
start |
启动进程 | |
start |
在一个组中启动所有进程 | |
start |
启动多个进程或组 | |
start all |
开始所有进程 | |
status |
获取所有进程状态信息 | |
status |
按名称获取单个进程的状态 | |
status |
获取多个已命名进程的状态 | |
stop |
停止一个进程 | |
stop |
停止组中的所有进程 | |
stop |
停止多个进程或组 | |
stop all |
停止所有进程 | |
`tail [-f] |
stderr] (default stdout)` | 输出进程日志的最后一部分,例如: tail -f 按 Ctrl-C退出。tail -100 最后100个字节的进程 |
非交互命令下操作
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# supervisorctl -c supervisord.conf restart
Error: restart requires a process name
restart Restart a process
restart :* Restart all processes in a group
restart Restart multiple processes or groups
restart all Restart all processes
Note: restart does not reread config files. For that, see reread and update.
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# supervisorctl -c Supervisor/supervisord.conf restart all
daphne: stopped
daphne: started
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# supervisorctl -c supervisord.conf stop
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# supervisorctl -c supervisord.conf start
Web管理界面
出于安全考虑,默认配置没有开启web管理界面,需要修改 supervisord.conf 配置文件,以打开http访权限。
修改配置
将下面的配置
;[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)
修改为
[inet_http_server] ; inet (TCP) server disabled by default
port=0.0.0.0:9001 ; ip_address:port specifier, *:port for all iface
username=user ; default is no username (open server)
[email protected] ; default is no password (open server)
浏览器访问 IP:90001 输入帐密就可看到下面界面了
[图片上传失败...(image-4177aa-1564296135364)]
重启Supervisor服务
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# supervisorctl shutdown
Shut down
(ITNest) root@PxeCtrlSys:/home/user/ITNest/Supervisor# supervisord -c supervisord.conf
Nginx代理域名访问端口
root@StarMeow-Svr:/etc/nginx/conf.d# vim 6.supervisor.9001.conf
添加
server {
listen 80;
server_name supervisor.mydomain.cn;
#return 403; # 测试用
#rewrite (.*) https://www.baidu.com;
location / {
proxy_pass http://127.0.0.1:9001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 60s;
}
# access_log logs/www_access.log;
}
开机启动Supervisor服务
配置systemctl服务
进入/lib/systemd/system
目录,并创建supervisor.service
文件,该文件内容如下所示。
# 先查看程序的路径
root@PxeCtrlSys:/lib/systemd/system# whereis supervisord
supervisord: /root/.pyenv/shims/supervisord
root@PxeCtrlSys:/lib/systemd/system# whereis supervisorctl
supervisorctl: /root/.pyenv/shims/supervisorctl
# 创建文件
root@PxeCtrlSys:/lib/systemd/system# vim supervisor.service
[Unit]
Description=supervisor
After=network.target
[Service]
Type=forking
ExecStart=/root/.pyenv/shims/supervisord -c /home/user/ITNest/Supervisor/supervisord.conf
ExecStop=/root/.pyenv/shims/supervisorctl $OPTIONS shutdown
ExecReload=/root/.pyenv/shims/supervisorctl $OPTIONS reload
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target
设置开机启动
root@PxeCtrlSys:/lib/systemd/system# systemctl enable supervisor.service
Created symlink from /etc/systemd/system/multi-user.target.wants/supervisor.service to /lib/systemd/system/supervisor.service.
root@PxeCtrlSys:/lib/systemd/system# systemctl daemon-reload
修改文件权限为766
root@PxeCtrlSys:/lib/systemd/system# chmod 766 supervisor.service
配置service类型服务
参考 https://blog.csdn.net/chinawangfei/article/details/81912372
Linux发行版开机启动脚本:https://github.com/Supervisor/initscripts
Debian的脚本
#! /bin/sh
### BEGIN INIT INFO
# Provides: supervisord
# Required-Start: $local_fs $remote_fs $networking
# Required-Stop: $local_fs $remote_fs $networking
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Starts supervisord - see http://supervisord.org
# Description: Starts and stops supervisord as needed - see http://supervisord.org
### END INIT INFO
# Author: Leonard Norrgard
# Version 1.0-alpha
# Based on the /etc/init.d/skeleton script in Debian.
# Please note: This script is not yet well tested. What little testing
# that actually was done was only on supervisor 2.2b1.
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Run a set of applications as daemons."
NAME=supervisord
DAEMON=/usr/bin/$NAME # Supervisord is installed in /usr/bin by default, but /usr/sbin would make more sense.
SUPERVISORCTL=/usr/bin/supervisorctl
PIDFILE=/var/run/$NAME.pid
DAEMON_ARGS="--pidfile ${PIDFILE}"
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
[ -e $PIDFILE ] && return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
[ -e $PIDFILE ] || return 1
# Stop all processes under supervisord control.
$SUPERVISORCTL stop all
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 3
;;
esac
:
注意:Supervisor只能管理非daemon的进程,不能管理守护进程。 否则,会提示Exited too quickly (process log may have details)异常。