如何将Docker容器变成僵尸

时间:2018-07-04 18:48:11

标签: docker zombie-process

几年前。当我刚开始玩docker时。我记得,如果您对pid(1)的处理不好,就会提到一些博客文章。您将创建一个僵尸docker容器。那时候。我选择按照建议开始使用名为dumb-init的初始化工具。而且我从来没有真正看到过创建僵尸容器。

但是我仍然很好奇为什么这是一个问题。如果我没记错的话,默认情况下,docker stop xxx会将SIGTERM发送到容器pid(1)进程。如果该过程不能在10秒内正常停止(默认)。 Docker将通过发送SIGKILL到pid(1)进程来强制杀死它。而且我也知道pid(1)进程在Linux系统中很特殊。它可以忽略SIGKILL信号(link)。但我认为,即使docker容器中进程的PID为1,也仅仅是因为它使用命名空间来限定进程的范围。在主机上,您应该看到该进程是另一个PID。可以被内核杀死。

所以我的问题是:

  1. 为什么docker引擎不能只在主机内核级别杀死该容器?所以无论如何。用户可以确保正确杀死该容器。
  2. 如何在docker容器中创建僵尸进程? (如果某人可以共享一个Gist,那就太好了!)

1 个答案:

答案 0 :(得分:0)

不是僵尸容器,而是僵尸进程。写下这个zombie.py

#!/usr/bin/env python3
import subprocess
import time

p = subprocess.Popen(['/bin/sleep', '1'])
time.sleep(2)

subprocess.run(['/bin/ps', '-ewl'])

写这个Dockerfile

FROM python:3
COPY zombie.py /
CMD ["/zombie.py"]

构建并运行它:

chmod +x zombie.py
docker build -t zombie .
docker run --rm zombie

这里发生的是/bin/sleep命令运行执行。父进程需要使用wait进行清理,但是在运行ps时并不需要,您会看到一个“ Z”僵尸进程。

但是,等等,还有更多!说您的过程确实会仔细清除。在此特定示例中,例如,subprocess.run()包括必需的wait调用,您可以将Popen调用更改为run。如果该子进程启动另一个子进程,并且 it 退出(或崩溃)而不等待它,则pid为1的init进程将成为僵尸的新父进程。 (这种方式已经工作了40年。)但是,在Docker容器中,主容器进程使用pid 1运行,如果不期望“额外”子进程,则可以在整个生命周期中使用陈旧的僵尸进程。容器。

这导致偶尔出现一个建议,即Docker容器应始终运行某种“真实”的初始化过程,可能只有tini最小,这样僵尸进程后某些东西会捡起来,而您的实际容器工作却没有不必担心。