2016-09-28 37 views
13

考虑以下,这在后台运行sleep 60,然后退出:当Docker容器的PID1退出时,其他进程会发生什么?

$ cat run.sh 
sleep 60& 
ps 
echo Goodbye!!! 
$ docker run --rm -v $(pwd)/run.sh:/run.sh ubuntu:16.04 bash /run.sh 
    PID TTY   TIME CMD 
    1 ?  00:00:00 bash 
    5 ?  00:00:00 sleep 
    6 ?  00:00:00 ps 
Goodbye!!! 

这将启动一个泊坞的容器中,作为bash PID1。然后它叉/执行一个sleep进程,然后bash退出。当Docker容器死亡时,sleep进程也死机。

我的问题是:什么是sleep进程被杀死的机制?我试图在子进程中捕获SIGTERM,并且看起来没有被绊倒。我的推测是,关闭容器正在使用的cgroup时,Docker或Linux内核正在发送SIGKILL,但我在任何地方都没有找到说明这一点的文档。

编辑我来解释最接近的是从baseimage-docker以下报价:

如果你的init进程是你的应用程序,那么它很可能只是关闭本身,而不是所有的容器中的其他进程。内核然后会强行终止其他进程,而不是让他们有机会正常关闭,可能导致文件损坏,临时文件过时等。您真的想要优雅地关闭所有进程。

因此,至少根据这一点,暗示当容器退出时,内核将发送一个SIGKILL到所有剩余的进程。但是我还是希望清楚它是如何决定这么做的(即它是cgroups的一个特征吗?),理想情况下更权威的来源会更好。

回答

2

好的,我似乎已经提出了一些更确凿的证据,实际上,这是Linux内核做终止。在clone(2)手册页,有这个有用的部分:

CLONE_NEWPID(因为Linux 2.6.24)

在一个新的命名空间(第一个创建的过程,即,使用CLONE_NEWPID标志 创建的过程)具有PID 1,并且是命名空间的“init”进程 。在命名空间内成为孤儿 的孩子将被重新设置为此过程而不是 init(8)。与传统的init进程不同,PID命名空间的“init”进程可以终止,如果是,则所有进程 中的命名空间终止。

不幸的是,对于名称空间中的进程究竟如何终止仍然模糊不清,但也许这是因为,与正常进程退出不同,进程表中没有任何条目。无论是哪种情况,它似乎很清楚:

  • 内核自身杀死其他进程
  • 他们不是在一个方式,让他们任何机会做清理丧生,使得它(几乎?)等同于SIGKILL
+0

这是可能的码头工人'runc'做清理,如果你[在主机PID命名空间运行(https://github.com/opencontainers/runc/blob/c4e0d94efacd6f6fb353a538cc01d10792cc3a35 /libcontainer/state_linux.go#L41-L45)。 – Matt

+0

,内核确实发送了一个'SIGKILL'来终止进程。 – Matt

+0

@Matt很高兴知道。它是否成为主机'init'进程收获这些进程的责任,还是内核将它们从进程表本身中删除? –

相关问题