扫一扫微信二维码

【容器化实践分享】Docker init 进程 发布时间:2016-11-14


本文由OpenStack社区Kolla项目Core张雷根据在实际操作中遇到的问题整理编撰

应用容器化后,重启容器的时候,经常会很慢,而且 docker daemon 日志中经常会抛出以下错误
dockerd[559]: msg="Container 5054f failed to exit within 10 seconds of
signal 15 - using the force"

默认的的 signal 15 根本就没有使其退出,最后还是 10 秒超时后强制退出 (kill) 的。而且有时还会出现大量僵尸进程。这可不是一个好现象。本文解释其原因及解决方法。

背景知识
信号
这个是 Linux 最常见一个概念,一般杀死进程时都会用到 kill 。 不同的信号有不同的默认行为。用户可以注册自己的信号处理函数,来覆盖掉默认行为。

僵尸进程
僵尸进程是终止运行的进程,为什么它们是有害的 ?
虽然应用申请的内存已经释放了,但是你依然能通过 ps 看到它。这是因为有一些内核资源没有释放。下面是 Linux waitpid 的 man page:

As long as a zombie is not removed from the system via a wait, it willconsume a slot in the kernel process table, and if this table fills, itwill not be
possible to create further processes."

容器化后的问题
容器化后,由于单容器单进程,已经没有传统意义上的 init 进程了。应用进程直接占用了 pid 1 的进程号。从而导致以下两个问题。

进程不能正常终止
Linux 内核中会对 pid 1 进程发送特殊的信号量。

一般情况下,当给一个进程发送信号时,内核会先检查是否有用户定义的处理函数,如果没有,就会回退到默认行为。例如使用 SIGTERM 直接杀死进程。然而,如果进程的 PID是 1, 内核会特殊对待它。如果没有没有注册用户处理函数,内核不会回退到默认行为,什么也不做。换句话说,如果你的进程没有处理信号的函数,给他发送 SIGTERM 会一点效果也没有。

常见的使用是 docker run my-container script. 给 docker run 进程发送SIGTERM 信号会杀掉 docker run 进程,但是容器还在后台运行。

孤儿僵尸进程不能正常回收
当进程退出时,它会变成僵尸进程,直到它的父进程调用 wait() ( 或其变种 ) 的系统调用。process table 里面会把它的标记为 defunct 状态。一般情况下,父进程应该立即调用 wait(), 以防僵尸进程时间过长。

如果父进程在子进程之前退出,子进程会变成孤儿进程 , 它的父进程会变成 PID 1。因此,init 进程就要对这些进程负责,并在适当的时候调用 wait() 方法。

但是,通常情况下,大部分进程不会处理偶然依附在自己进程上的随机子进程,所以在容器中,会出现许多僵尸进程。

解决方案
让所有的应用能正确的处理以上的情况,不太现实。好在现在有很多解决方案,例如dumb-init [0] 。他像是一个小型 init 服务,他启动一个子进程并转发所有接收到的信号量给子进程。而且不需要修改应用代码。

此时你的应用进程已经不是 pid 1 了,所以已经没有上面提到的问题。而且 dumb-init也会转发所有的信号给子进程,应用的形为和在没有 dumb-init 时是一样的。如果应用进程死掉了,dumb-init 进程也会死掉,并会清理所有其它的子进程。

使用方法如下 , 在 Dockerfile 里面加上:

# install dumb-init
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64
RUN chmod +x /usr/local/bin/dumb-init

# Runs "/usr/bin/dumb-init -- /my/script --with --args"
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/my/script", "--with", "--args"]

类似的方案 tini [1], pidunu[3]

Kolla 相关
Kolla 最近已经发布了 newton 版本的 release 。 已经加上了 dumb-init 的解决方案。

参考资料
【0】https://github.com/Yelp/dumb-init
【1】https://github.com/krallin/tini
【2】https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem
【3】https://github.com/rciorba/pidunu

© 2012-2017 九州云信息科技有限公司 99Cloud 版权所有 咨询热线:400 006 0472 售后服务热线:400 670 7810 培训咨询热线:400 826 0070   ICP证:浙ICP备12032350号-1

网站建设:信达互联

北京网站建设公司