用supervisordpipe理docker容器的最佳方法
我必须在同一台服务器(客户端的要求)上设置“dockerized”环境(集成,qa和生产)。 每个环境的组成如下:
- 的RabbitMQ
- 芹菜
- 花
- 基于python 3的应用程序称为“A”(每个环境的特定分支)
在他们身上,jenkins将会根据CI来处理部署。
每个环境使用一组容器听起来像是最好的方法。
但是现在我需要stream程经理来运行和监督他们:
- 3只兔子容器,
- 3个芹菜/鲜花容器,
- 3个“A”容器,
- 1jenkins容器。
Supervisord似乎是最好的select,但是在我的testing中,我无法“正常地”重启一个容器。 这里是supervisord.conf的一个片段
[program:docker-rabbit] command=/usr/bin/docker run -p 5672:5672 -p 15672:15672 tutum/rabbitmq startsecs=20 autorestart=unexpected exitcodes=0,1 stopsignal=KILL
所以我想知道什么是分离每个环境的最佳方式,并且能够pipe理和监督每个服务(一个容器)。
[编辑我的解决scheme,由托马斯响应启发]
每个容器都由一个看起来像.sh的脚本运行
rabbit-integration.py
#!/bin/bash #set -x SERVICE="rabbitmq" SH_S = "/path/to_shs" export MY_ENV="integration" . $SH_S/env_.sh . $SH_S/utils.sh SERVICE_ENV=$SERVICE-$MY_ENV ID_FILE=/tmp/$SERVICE_ENV.name # pid file trap stop SIGHUP SIGINT SIGTERM # trap signal for calling the stop function run_rabbitmq
$ SH_S / env_.sh看起来像:
# set env variable ... case $MONARCH_ENV in $INTEGRATION) AMQP_PORT="5672" AMQP_IP="172.17.42.1" ... ;; $PREPRODUCTION) AMQP_PORT="5673" AMQP_IP="172.17.42.1" ... ;; $PRODUCTION) AMQP_PORT="5674" REDIS_IP="172.17.42.1" ... esac
$ SH_S / utils.sh看起来像:
#!/bin/bash function random_name(){ echo "$SERVICE_ENV-$(cat /proc/sys/kernel/random/uuid)" } function stop (){ echo "stopping docker container..." /usr/bin/docker stop `cat $ID_FILE` } function run_rabbitmq (){ # do no daemonize and use stdout NAME="$(random_name)" echo $NAME > $ID_FILE /usr/bin/docker run -i --name "$NAME" -p $AMQP_IP:$AMQP_PORT:5672 -p $AMQP_ADMIN_PORT:15672 -e RABBITMQ_PASS="$AMQP_PASSWORD" myimage-rabbitmq & PID=$! wait $PID }
至lessmyconfig.intergration.conf看起来像这样:
[program:rabbit-integration] command=/path/sh_s/rabbit-integration.sh startsecs=20 priority=90 autorestart=unexpected exitcodes=0,1 stopsignal=TERM
在这种情况下,我想使用相同的容器启动function是这样的:
function _run_my_container () { NAME="my_container" /usr/bin/docker start -i $NAME & PID=$! wait $PID rc=$? if [[ $rc != 0 ]]; then _run_my_container fi }
哪里
function _run_my_container (){ /usr/bin/docker run -p{} -v{} --name "$NAME" myimage & PID=$! wait $PID }
主pipe要求它所pipe理的进程不要守护进程,正如它的文档一样 :
在监督下运行的程序不应该为自己辩护。 相反,他们应该在前台运行。 他们不应该从他们开始的terminal脱离。
这在很大程度上与Docker不兼容,其中容器是Docker进程本身的子进程 (即,因此不是Supervisor的子进程 )。
为了能够在Supervisor中使用Docker,可以编写一个与Docker配合使用的pidproxy
程序 。
但是,真的,这两个工具并不是真正的架构在一起工作,所以你应该考虑改变一个或另一个:
- 考虑用Docker ComposereplaceSupervisor(这是devise与Docker一起工作的)
- 考虑用RocketreplaceDocker(它没有“主”进程)
你可以让Docker不分离,然后事情工作正常。 我们通过主pipe以这种方式pipe理我们的Docker容器。 Docker组合是非常棒的,但是如果你已经使用Supervisor来pipe理非docker的东西,那么继续使用它来把所有的pipe理集中到一个地方是很好的。 我们将我们的docker运行包装在一个bash脚本中,如下所示,并有主pipe跟踪,并且一切正常。
#!/bin/bash¬ TO_STOP=docker ps | grep $SERVICE_NAME | awk '{ print $1 }'¬ if [$TO_STOP != '']; then¬ docker stop $SERVICE_NAME¬ fi¬ TO_REMOVE=docker ps -a | grep $SERVICE_NAME | awk '{ print $1 }'¬ if [$TO_REMOVE != '']; then¬ docker rm $SERVICE_NAME¬ fi¬ ¬ docker run -a stdout -a stderr --name="$SERVICE_NAME" \ --rm $DOCKER_IMAGE:$DOCKER_TAG
你需要确保在你的主pipeconfiguration中使用stopsignal = INT,然后exec docker run
正常docker run
。
[program:foo] stopsignal=INT command=docker -rm run whatever
至less,这似乎与docker版本1.9.1我的工作。
如果在shell脚本中运行docker窗体,那么在docker run命令前面exec
是非常重要的,这样docker run
replaceshell进程,从而直接从supervisord接收到SIGINT。