注:本文基于CentOS 6.6
背景
Docker容器的设计并不推荐容器内运行多个进程,它希望的是一个进程一个容器,走微服务方向。然而实际生产过程中并没有这么理想,总是会有需要多个进程运行在同一容器的需要。因此,我们今天来介绍一下容器内的多进程管理——supervisor,还有另一个工具——monit,同样可以用于容器内多进程管理,不过我们后面再介绍它。
安装
1、使用yum方式
yum install -y epel-release && yum install -y supervisor
CentOS 6.5自带的yum repo没有supervisor,需要安装epel repo。但是6系列中supervisor的版本是2.x,有些功能没有,比如需要将所有进程配置放到主配置中,无法按进程独立出配置文件,然后一把include。
因此我们可以使用pip的方式安装supervisor。
2、使用pip方式
yum install -y epel-release && yum install -y python-pip && pip install supervisor setuptools==36.7.0
同样需要先安装epel repo,然后安装pip工具,之后就是使用pip安装supervisor了。不过这里有个坑,如果安装supervisor不升级setuptools组件,则执行命令时会有以下报错:
[root@6-6 /]# supervisord -h
Traceback (most recent call last):
File "/usr/bin/supervisord", line 5, in <module>
from pkg_resources import load_entry_point
File "/usr/lib/python2.6/site-packages/pkg_resources.py", line 2655, in <module>
working_set.require(__requires__)
File "/usr/lib/python2.6/site-packages/pkg_resources.py", line 648, in require
needed = self.resolve(parse_requirements(requirements))
File "/usr/lib/python2.6/site-packages/pkg_resources.py", line 546, in resolve
raise DistributionNotFound(req)
pkg_resources.DistributionNotFound: meld3>=0.6.5
但是你如果直接升级又不行。如果你使用以下命令升级到最新版本,
pip install setuptools --upgrade
恭喜你,这下子pip命令报错了,原因就是setuptools在37版本之后就不再支持python 2.6了。。。
因此上面我们指定了升级setuptools组件的版本。
配置
安装好supervisor之后,我们就可以开始配置了。首先,我们说一下我们的需求,期望容器启动的时候sshd进程和crond进程也一并启动。
1、生成supervisor默认配置
supervisor并没有给我们提供现成的配置,需要我们自己执行命令生成模板。
echo_supervisord_conf > supervisord.conf
执行命令后在当前目录下生成了一份默认的supervisor配置。其实大部分都可以沿用默认配置,只要加入需要管理程序的配置就可以了。我们将配置文件注释部分剔除,做个简单介绍。
[unix_http_server]
file=/tmp/supervisor.sock ; the path to the socket file
[supervisord]
logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log
logfile_maxbytes=50MB ; max main logfile bytes b4 rotation; default 50MB
logfile_backups=10 ; # of main logfile backups; 0 means none, default 10
loglevel=info ; log level; default info; others: debug,warn,trace
pidfile=/tmp/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
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
;[program:theprogramname]
;command=/bin/cat ; the program (relative uses PATH, can take args)
;autostart=true ; start at supervisord start (default: true)
;startsecs=1 ; # of secs prog must stay up to be running (def. 1)
;startretries=3 ; max # of serial start failures when starting (default 3)
;autorestart=unexpected ; when to restart if exited after running (def: unexpected)
[include]
files = supervisord_sshd.conf supervisord_crond.conf
其中,
[unix_http_server]:用于配置http服务监听的socket,因为supervisor实际上是一个C/S服务架构,因此该配置让客户端supervisorctl能连接服务端supervisord的http server获取进程状态信息。
[supervisord]:用于配置supervisord进程的行为,包括日志存放及其转储等。
[supervisorctl]:客户端程序supervisorctl的相关配置,基于进程间通信,使用UNIX domain socket。
[program:x]:用于定于用户需要管理的进程信息,一般不在主配置里配置,而是每个进程一个配置文件,使用include包含,便于管理,其中x为唯一进程名。
[include]:用于指明用户进程配置文件路径,这也就是我们需要修改的地方。
关于配置有几点要注意的,
- 配置注释符号使用的是分号";"
- 如果需要使用模块配置,需要先把配置块开头的分号删除,否则整个块的配置不会生效;
- include字段的配置即为我们添加的管理服务的配置,配置文件使用空格分隔,也可以使用绝对路径和通配符,但是切记不要重复包含主配置文件——supervisord.conf。
supervisor的详细配置可以参考官网手册:[http://www.supervisord.org/index.html]。
docker镜像打包
创建Dockerfile,将supervisor和sshd及crond的相关配置文件都放在与Dockerfile同级目录中,打包时一同提交给docker daemon进程。
#使用CentOS 6.6官方镜像
FROM centos:6.6
#安装epel repo,以及pip命令,之后安装supervisor和升级setuptools
RUN yum install -y epel-release && yum install -y python-pip && pip install supervisor setuptools==36.7.0
#安装openssh组件和cron组件
RUN yum install -y openssh-server openssh-clients openssh cronie
#暴露22号端口用于ssh连接
EXPOSE 22
#设置机器密码
RUN echo "root:root" | chpasswd
#拷贝supervisor、sshd、crond配置到相关目录
COPY supervisord.conf /etc/supervisor/
COPY supervisord_sshd.conf /etc/supervisor/
COPY supervisord_crond.conf /etc/supervisor/
#设置容器启动时执行的命令
ENTRYPOINT ["/usr/bin/supervisord", "-nc", "/etc/supervisor/supervisord.conf"]
需要注意的是supervisord默认是以后台方式启动的,因此使用docker方式管理时需要设定为前台执行,否则容器一启动就退出了,这也是最后启动supervisord时使用"-n"的用意。
supervisord_sshd.conf和supervisord_crond.conf的配置比较简单,只配置了最基本的参数,同时这两个进程也必须设置为前台运行。
supervisord_sshd.conf 配置如下:
[program:sshd]
command=/usr/sbin/sshd -D ; the program (relative uses PATH, can take args)
autostart=true ; start at supervisord start (default: true)
startretries=3 ; max # of serial start failures when starting (default 3)
autorestart=unexpected ; when to restart if exited after running (def: unexpected)
supervisord_crond.conf 配置如下:
[program:crond]
command=/usr/sbin/crond -n ; the program (relative uses PATH, can take args)
autostart=true ; start at supervisord start (default: true)
startretries=3 ; max # of serial start failures when starting (default 3)
autorestart=unexpected ; when to restart if exited after running (def: unexpected
简单定义了进程名,以及设置进程前台运行的参数,并指定自动启动等配置。
效果
使用docker build构建镜像后,就可以运行起来了,使用本地8000号端口映射容器的22号端口,
docker run -d --name eee -h eee -p 8000:22 1ed4256823b6
运行后查看容器状态,以及容器内进程信息,
[root@localhost 6.6]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4798c2b9ea39 1ed4256823b6 "/usr/bin/supervisor 4 seconds ago Up 3 seconds 0.0.0.0:8000->22/tcp eee
[root@localhost 6.6]# docker top eee
UID PID PPID C STIME TTY TIME CMD
root 31783 2015 2 17:21 ? 00:00:00 /usr/bin/python /usr/bin/supervisord -nc /etc/supervisor/supervisord.conf
root 32149 31783 0 17:21 ? 00:00:00 /usr/sbin/sshd -D
root 32150 31783 0 17:21 ? 00:00:00 /usr/sbin/crond -n
可见,此时容器内sshd和crond进程已经在位,在其他机器通过宿主机ip及8000端口,ssh登录也正常。