2015-10-14 71 views
23

我不是在询问有关码头工使用主管,而只是想让我的理解得到验证。在码头使用主管

我知道docker在运行时运行一个进程。另外,当我们需要在容器中运行多个进程时使用主管。

我已经看到几个例子,其中一个容器是从基础镜像启动的,并且安装了几个服务,并且容器承诺形成一个新的镜像,全部没有主管。

所以,我的基本疑问是两种方法之间有什么区别。

我的理解是,当docker容器停止时,它向PID 1的进程发送一个kill信号,PID 1管理子进程并停止所有的子进程,而这正是supervisor完成的任务,而我们可以安装多进程没有管理员只有一个进程可以运行,当码头运行发出,当容器停止时,只有PID 1将被发送信号,其他运行进程将不会正常停止。

请确认我对使用supervisord的理解是否正确。

感谢

+0

更新2016年9月:参见[我的新答案](http://stackoverflow.com/a/39593409/6309):docker守护进程可以在Docker 1.12中为你处理这些僵尸进程。 – VonC

回答

38

,而我们可以在没有监督员安装多个过程中,当搬运工运行时发出,当容器只能停在PID 1将发送信号和其他正在运行的进程只有一个进程可以运行不会优雅地停下来。

是的,虽然它取决于你的主进程如何运行(前台或后台)以及它如何收集子进程。

即什么是“Trapping signals in Docker containers

docker stop详述通过发送SIGTERM信号停止运行的容器,让主工艺处理并使用SIGKILL在宽限期后终止应用程序。

发送到容器的信号由正在运行的主进程(PID 1)处理。

如果应用程序在前台,意味着应用程序是容器中的主进程(PID1),它可以直接处理信号。

但是:

以信号可能是一个背景,你不能直接发送任何信号的过程。在这种情况下,一种解决方案是设置一个shell脚本作为入口点并编排该脚本中的所有信号处理。

的问题是“Docker and the PID 1 zombie reaping problem

的Unix的设计是这样一种方式,父进程必须明确地“等待”子进程终止,以收集其退出状态进一步详述。僵尸进程一直存在,直到父进程执行此操作,并使用系统调用系列调用的waitpid()系列调用。

为了消除其僵尸而在子进程上调用waitpid()的操作称为“收割”。

init进程 - PID 1 - 有一个特殊的任务。其任务是“采用”孤儿过程。

https://blog.phusion.nl/wp-content/uploads/2015/01/adoption.png

操作系统预计init进程谋取收养的孩子了。

问题与码头工人:

我们看到,很多人只能运行一个进程在它们的容器,他们认为,当他们运行此单过程中,他们就完成了。
但最有可能的是,这个过程没有被写成像一个正确的init过程那样工作。
也就是说,它可能期望另一个init流程来完成这项工作,而不是正确收获采用的流程,并且是正确的。

使用像phusion/baseimage-docker这样的图像帮助管理一个(或多个)进程,同时保持主进程符合init。

它使用runit instead of supervisord,多进程管理:

Runit是不是有解决收割问题。相反,它支持多个进程。鼓励多个流程的安全性(通过流程和用户隔离)。
Runit使用的内存少于Supervisord,因为Runit是用Python编写的C和Supervisord。
并且在一些使用情况下,容器中的进程重新启动优于整个容器重新启动。

该图片包括一个my_init script,它负责照顾“收获”问题。

在baseimage-docker中,我们鼓励在单个容器中运行多个进程。虽然不一定是多个服务。
逻辑服务可以由多个操作系统进程组成,我们提供的设施可以轻松实现。

+0

感谢您的精心解答。我正在尝试phusion映像,据我所知每当容器启动时它会运行/etc/init.d中的任何内容。但是,我在init.d中有一个不在容器启动时启动的服务。你能帮忙吗? – user3275095

+0

当然:你可以问一个新的问题,你的新安装的细节?这样,我(和其他人)可以看看。 – VonC

+0

噢..我的错误是/etc/my_init.d – user3275095

10

更新2016年9月的泊坞窗1.12(Q4 2016/Q1 2017)

Arnaud Porterie只是twitted

[]刚刚合并:与docker run --initRick Grimes将采取所有的僵尸照顾。

commit eabae09

PR 26061: “添加init进程的僵尸战斗和信号处理”(和PR 26736

这增加了打击僵尸小C的二进制文件。它安装在 /dev/init下,并且被用户指定的参数前置。您通过守护进程标记dockerd --init启用它,因为它被 禁用,因为它是向后兼容的默认值。

您也可以覆盖守护进程选项,或者在容器基础上用docker run --init=true|false指定此选项。

你可以通过运行一个像这样的进程来测试这个过程,作为 容器中的pid 1,并看到容器中出现的额外的僵尸,因为它运行的是 。

int main(int argc, char ** argv) { 
    pid_t pid = fork(); 
    if (pid == 0) { 
     pid = fork(); 
     if (pid == 0) { 
      exit(0); 
     } 
     sleep(3); 
     exit(0); 
    } 
    printf("got pid %d and exited\n", pid); 
    sleep(20); 
} 

docker daemon现在有选项

--init 

运行容器内的初始化转发信号和收获过程

+0

感谢您的更新。 – user3275095