关键词:服务管理 容器内启动多个进程 多进程管理 Supervisor Docker
需求分析:平常我们管理服务,最方便的就系统工具直接安装,比如yum
安装,systemctl
管理,但有些脚本或服务是我们自己写,在额外配上xx.service
管理脚本还有点麻烦,并且要要想让容器支持systemd
功能就不太方便
解决方案:引入supervisor管理工具帮我们解决此类问题
快速体验
以CentOS7为例
开启EPEL仓库
参考 https://blog.csdn.net/xys2015/article/details/109378741
安装
yum info supervisor
yum install supervisor
配置
cat << 'EOF' > /etc/supervisord.d/p1.ini
[program:p1]
command=/bin/cat
EOF
cat << 'EOF' > /etc/supervisord.d/p2.ini
[program:p2]
command=/bin/cat
EOF
cat << 'EOF' > /etc/supervisord.d/p3.ini
[program:p3]
command=/bin/cat
EOF
p1、p2、p3 是自定义的程序名
command填写启动命令,这里用 /bin/cat 纯粹是测试用
启动
systemctl restart supervisord.service
查看
# supervisorctl status
p1 RUNNING pid 1150, uptime 0:04:21
p2 RUNNING pid 1148, uptime 0:04:21
p3 RUNNING pid 1149, uptime 0:04:21
# supervisorctl stop p1
# supervisorctl status p1
# supervisorctl start p1
开机自启(可选)
systemctl enable supervisord.service
supervisord 启动之后,其管理的服务会自动起来,除非额外配置 (见下文)
启用图形界面
配置改动如下图:
配置改动diff对比
[root@10-222-32-10 ~]# cp /etc/supervisord.conf /etc/supervisord.conf.bak
[root@10-222-32-10 ~]# diff /etc/supervisord.conf /etc/supervisord.conf.bak
10,11c10,11
< [inet_http_server] ; inet (TCP) server disabled by default
< port=0.0.0.0:9001 ; (ip_address:port specifier, *:port for all iface)
---
> ;[inet_http_server] ; inet (TCP) server disabled by default
> ;port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface)
40,41c40,41
< ;serverurl=unix:///var/run/supervisor/supervisor.sock ; use a unix:// URL for a unix socket
< serverurl=http://0.0.0.0:9001 ; use an http:// url to specify an inet socket
---
> 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
重启 supervisord
systemctl restart supervisord.service
netstat -lntup | grep 9001
访问 9001 端口
http://10.222.32.10:9001/
启动顺序的控制 (常用配置文件介绍)
如果我们的服务是几个程序配套提供服务,并且它们之间有先后启动顺序(比如MySQL先启动,PHP后启动),那么我们可能需要控制启动顺序
最好能把服务启动顺序交给程序自行管理,比如设计PHP先启动自己去尝试重连MySQL若干次等等
此时,我们可以自己写脚本控制启动顺序,或者利用supervisor自己的配置文件来控制
[program:myname]
command=sh /tmp/echo_time.sh
priority=999
numprocs=1
autostart=true
autorestart=true
startsecs=10
startretries=3
exitcodes=0,2
stopsignal=QUIT
stopwaitsecs=10
user=root
log_stdout=true
log_stderr=true
logfile=/tmp/echo_time.log
logfile_maxbytes=1MB
logfile_backups=10
stdout_logfile_maxbytes=20MB
stdout_logfile_backups=20
stdout_logfile=/tmp/echo_time.stdout.log
command:要执行的命令
priority:执行优先级,值越高就越晚启动,越早关闭
autostart:是否与 supervisord 一起启动
autorestart: 程序发生未知错误时自动重启
startsecs:延时启动时间,默认为 10 秒
startretries:启动重试次数,默认为 3 次
user:以哪个用户执行
更多配置细节介绍,参见官网 http://supervisord.org/configuration.html
yum 安装好后默认的配置
[root@10-222-32-10 ~]# cat /etc/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
注意事项
- 启动命令不能把程序放在后台,否则supervisor无法管理,会出现被管理的进程反复自动重启的情况
- 启动命令最好全部是绝对路径,否则有可能报错
实战-容器内使用supervisord
下面以CentOS7容器为例,演示在容器中安装ssh、nginx服务,并通过supervisor管理
安装docker
参见拙文 https://blog.csdn.net/xys2015/article/details/109370082
启动容器
docker run --name stest -d \
-p 30022:22 -p 30080:80 -p 39001:9001 \
--env TZ='Asia/Shanghai' \
--env LANG="en_US.UTF-8" \
--env LC_ALL="en_US.UTF-8" \
daocloud.io/library/centos:7.8.2003 tail -F /tmp/tmp.txt
docker exec -it stest bash
更换阿里云基础仓库
参见拙文 https://blog.csdn.net/xys2015/article/details/109378741
配置ssh
yum install passwd openssl openssh-server openssh-clients net-tools -y
mkdir -p /var/run/ssh
ssh-keygen -q -t rsa -b 2048 -f /etc/ssh/ssh_host_rsa_key -N ''
ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N ''
ssh-keygen -t dsa -f /etc/ssh/ssh_host_ed25519_key -N ''
sed -i "s/#UsePrivilegeSeparation.*/UsePrivilegeSeparation no/g" /etc/ssh/sshd_config
sed -i "s/UsePAM.*/UsePAM no/g" /etc/ssh/sshd_config
echo 123456 | passwd --stdin root
配置nginx
yum install nginx -y
rpm -ql nginx | grep service
放一个busybox小工具进去 (可选)
cd /usr/bin
curl -O http://as4k.top:7000/chfs/shared/linux-pkg/busybox
chmod +x busybox
busybox netstat -lntup
配置supervisor
[root@a573002bdf05 bin]# rpm -ql supervisor | grep service
/usr/lib/systemd/system/supervisord.service
cat << 'EOF' > /etc/supervisord.d/nginx.ini
[program:nginx]
command=/usr/sbin/nginx -c /etc/nginx/nginx.conf -g 'daemon off;'
EOF
cat << 'EOF' > /etc/supervisord.d/sshd.ini
[program:sshd]
command=/usr/sbin/sshd -D
EOF
#容器内默认没有文档那块内容,我们手动创建个测试
mkdir -p /usr/share/nginx/html
rm -f /usr/share/nginx/html/index.html
echo "hello nginx" > /usr/share/nginx/html/index.html
yum install vim -y (可选)
vimdiff /etc/supervisord.conf /etc/supervisord.conf.bak (可选)
supervisor 配置文件修改参见下图,更多配置文件细节含义,参见上文和官网
启动supervisor
/usr/bin/supervisord -c /etc/supervisord.conf
验证测试
[root@a573002bdf05 /]# supervisorctl status
nginx RUNNING pid 38, uptime 0:00:21
sshd RUNNING pid 39, uptime 0:00:21
[root@a573002bdf05 /]# curl localhost:80
hello nginx
[root@a573002bdf05 /]# curl 10.222.32.10:30080 #这是物理机内网IP,一开始启动容器我们映射了端口
hello nginx
封装镜像
此时我们的镜像已经制作完毕,可以把容器固化成新的镜像供以后使用
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]`
[root@10-222-32-10 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a573002bdf05 daocloud.io/library/centos:7.8.2003 "tail -F /tmp/tmp.txt" 27 hours ago Up 7 minutes 0.0.0.0:30022->22/tcp, 0.0.0.0:30080->80/tcp, 0.0.0.0:39001->9001/tcp stest
[root@10-222-32-10 ~]# yum clean all #该步骤可减小容器尺寸
[root@10-222-32-10 ~]# docker commit --author "xingyongsheng.top" --message "first commit" stest stest:v2
[root@10-222-32-10 ~]# docker images | grep stest
stest v2 7fab7987bfca 11 seconds ago 722MB
直接启动容器,手动执行命令做镜像,比较方便但是难以维护,适合测试环境,生产环境一般使用Dockfile来制作镜像
正常使用
docker rm -fv stest
docker run --name stest -d \
-p 30022:22 -p 30080:80 -p 39001:9001 \
--env TZ='Asia/Shanghai' \
--env LANG="en_US.UTF-8" \
--env LC_ALL="en_US.UTF-8" \
stest:v2 bash -c '/usr/bin/supervisord --nodaemon -c /etc/supervisord.conf'
docker logs -f stest
ssh、nginx、supervisor ui 都可以正常访问,这里我就不贴截图了,注意docker的启动命令一定要能够挂起在前台,对于supervisor来说,即加上--nodaemon
,或者修改其配置文件
启动报错排查
有时候被supervisor管理的服务启动报错,或者无法停止,我们可以使用
supervisorctl tail programname stdout
来查看其详细输出信息
相关冗余信息
echo_supervisord_conf #这个命令可以直接在终端打印处默认配置
[root@node9 yum.repos.d]# rpm -ql supervisor | grep -v 'site-packages'
/etc/logrotate.d/supervisor
/etc/supervisord.conf
/etc/supervisord.d
/etc/tmpfiles.d/supervisor.conf
/usr/bin/echo_supervisord_conf
/usr/bin/pidproxy
/usr/bin/supervisorctl
/usr/bin/supervisord
/usr/lib/systemd/system/supervisord.service
/usr/share/doc/supervisor-3.4.0
/usr/share/doc/supervisor-3.4.0/CHANGES.txt
/usr/share/doc/supervisor-3.4.0/COPYRIGHT.txt
/usr/share/doc/supervisor-3.4.0/LICENSES.txt
/usr/share/doc/supervisor-3.4.0/README.rst
/var/log/supervisor
/var/run/supervisor
cp /etc/supervisord.conf /etc/supervisord.conf.bak
[root@10-222-32-10 ~]# cat /usr/lib/systemd/system/supervisord.service | grep ExecStart
ExecStart=/usr/bin/supervisord -c /etc/supervisord.conf
[root@10-222-32-10 ~]# systemctl status supervisord.service
● supervisord.service - Process Monitoring and Control Daemon
Loaded: loaded (/usr/lib/systemd/system/supervisord.service; disabled; vendor preset: disabled)
Active: active (running) since Thu 2020-10-29 10:01:53 CST; 10h ago
Process: 1432 ExecStart=/usr/bin/supervisord -c /etc/supervisord.conf (code=exited, status=0/SUCCESS)
Main PID: 1435 (supervisord)
CGroup: /system.slice/supervisord.service
├─1435 /usr/bin/python /usr/bin/supervisord -c /etc/supervisord.conf
├─1436 /bin/cat
├─1437 /bin/cat
└─1469 /bin/cat
Oct 29 10:01:53 10-222-32-10 systemd[1]: Stopped Process Monitoring and Control Daemon.
Oct 29 10:01:53 10-222-32-10 systemd[1]: Starting Process Monitoring and Control Daemon...
Oct 29 10:01:53 10-222-32-10 systemd[1]: Started Process Monitoring and Control Daemon.
[root@10-222-32-10 ~]# cat /usr/lib/systemd/system/supervisord.service
[Unit]
Description=Process Monitoring and Control Daemon
After=rc-local.service nss-user-lookup.target
[Service]
Type=forking
ExecStart=/usr/bin/supervisord -c /etc/supervisord.conf
[Install]
WantedBy=multi-user.target
[root@a573002bdf05 /]# /usr/sbin/nginx -h
nginx version: nginx/1.16.1
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: /usr/share/nginx/)
-c filename : set configuration file (default: /etc/nginx/nginx.conf)
-g directives : set global directives out of configuration file
[root@a573002bdf05 /]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 7808 688 ? Ss 23:24 0:00 tail -F /tmp/tmp.txt
root 6 0.0 0.2 15396 2104 pts/0 Ss 23:24 0:00 bash
root 37 0.0 1.2 142892 12820 ? Ss 23:25 0:00 /usr/bin/python /usr/bin/supervisord -c /etc/supervisord.conf
root 38 0.0 0.7 120900 7448 ? S 23:25 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf -g daemon off;
root 39 0.0 0.4 112924 4324 ? S 23:25 0:00 /usr/sbin/sshd -D
nginx 40 0.0 0.3 121296 3488 ? S 23:25 0:00 nginx: worker process
root 49 0.0 0.1 55192 1868 pts/0 R+ 23:27 0:00 ps aux
[root@10-222-32-10 ~]# docker logs -f stest
2020-10-31 23:57:15,631 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
2020-10-31 23:57:15,631 INFO Included extra file "/etc/supervisord.d/nginx.ini" during parsing
2020-10-31 23:57:15,631 INFO Included extra file "/etc/supervisord.d/sshd.ini" during parsing
2020-10-31 23:57:15,652 INFO RPC interface 'supervisor' initialized
2020-10-31 23:57:15,652 CRIT Server 'inet_http_server' running without any HTTP authentication checking
2020-10-31 23:57:15,652 INFO RPC interface 'supervisor' initialized
2020-10-31 23:57:15,652 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2020-10-31 23:57:15,652 INFO supervisord started with pid 1
2020-10-31 23:57:16,658 INFO spawned: 'nginx' with pid 8
2020-10-31 23:57:16,661 INFO spawned: 'sshd' with pid 9
2020-10-31 23:57:17,786 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2020-10-31 23:57:17,787 INFO success: sshd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
[root@a9c44d4f249c /]# busybox netstat -lntup
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:9001 0.0.0.0:* LISTEN 1/python
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 8/nginx.conf -g dae
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 9/sshd
tcp 0 0 :::80 :::* LISTEN 8/nginx.conf -g dae
tcp 0 0 :::22 :::* LISTEN 9/sshd
参考资料
https://github.com/Supervisor/supervisor
http://supervisord.org/
http://supervisord.org/configuration.html
https://www.cnblogs.com/pingyeaa/p/12782404.html#gen_conf
https://blog.csdn.net/genglei1022/article/details/81239900 supervisor配置 nginx
本文地址:https://blog.csdn.net/xys2015/article/details/109410032