优雅的终止docker容器
版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://vearne.cc
起因:
本文受到参考资料1的启发
我们线上的服务有不少都是部署在docker中,部署涉及的机器多大几十台,
服务发布时,要求前一个版本的容器必须优雅的退出。
docker容器中的进程是一个任务消费者。不断得从任务队列中取任务,然后进行执行(执行时间较长)
假定docker容器的name为test_v1
docker容器中的进程名为atm
也就是说不能简单的
docker rm -vf test_v1
docker run -d --name test_v1 test:v1
解决方案
1)方案1
首先,我想到的办法是在docker容器外部使用
ps -ef| grep atm |grep -v grep |awk '{print $2}'|xargs kill -15
容器中的进程捕获 SIGTERM 信号,优雅的退出,发现所有容器中的进程都退出后再执行发布逻辑
缺点:
这个方案肯定是没有问题的,但是如果进程同名,很有可能会导致误杀,而且从docker容器外部,传信号给容器内部的进程,感觉有点奇怪
2)方案2
幸运的看到了参考资料1
root@xxxx:~/test/docker/test_dk$ docker stop --help
Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
Stop a running container by sending SIGTERM and then SIGKILL after a
grace period
--help=false Print usage
-t, --time=10 Seconds to wait for stop before killing it
在docker stop命令执行的时候,会先向容器中PID为1的进程发送系统信号SIGTERM,然后等待容器中的应用程序终止执行,如果等待时间达到设定的超时时间,或者默认的10秒,会继续发送SIGKILL的系统信号强行kill掉进程。在容器中的应用程序,可以选择忽略和不处理SIGTERM信号,不过一旦达到超时时间,程序就会被系统强行kill掉,因为SIGKILL信号是直接发往系统内核的,应用程序没有机会去处理它。在使用docker stop命令的时候,我们唯一能控制的是超时时间,比如设置为20秒超时:
docker stop --time=20 container_name
既然docker 提供了stop命令,那完全可以利用stop命令来实现整个服务的优雅退出
整个demo
https://github.com/vearne/graceful_docker
1. 构建测试docker image
docker pull ubuntu:14.04
sh build.sh
2. 程序入口文件
#!/bin/sh
# 实际运行的工作程序
# my test program
nohup python /data/atm.py &
prog_exit()
{
ps -ef| grep atm |grep -v grep |awk '{print $2}'|xargs kill -15
}
# 注册中断处理函数
trap "prog_exit" 15
flag=1
while [ $flag -ne 0 ];do
sleep 3;
flag=`ps -ef| grep atm |grep -v grep | wc -l`
done;
3. 启动容器
sh deploy.sh
4. 测试是否优雅退出
root@xxx:~/test/docker/test_dk$ time docker stop -t 1000 test_v1
test_v1
real 0m15.567s
user 0m0.012s
sys 0m0.013s
test_v1正常停止
后记
这里的shell脚本也可以使用supervisor来代替
supervisor收到SIGTERM信号 后
也会向它管理的进程发送SIGTERM信号,我们可以借此来达到优雅退出的目的