在码头工人中使用主管

时间:2015-10-14 05:13:30

标签: docker supervisord

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

我知道docker在运行时会运行一个进程。此外,当我们需要在容器中运行多个进程时,使用超级用户。

我见过几个例子,其中从基本映像启动容器并安装了几个服务,并且容器被提交以形成新映像,所有这些都没有主管。

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

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

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

由于

3 个答案:

答案 0 :(得分:49)

  

虽然我们可以在没有主管的情况下安装多个进程,但只有一个进程可以在发布docker run时运行,当容器停止时,只有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进程能够收获被收养的孩子。

Docker问题:

  

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

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

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

  

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

该图片包含一个my_init script,负责收集"收获"问题。

  

在baseimage-docker中,我们鼓励在单个容器中运行多个进程。但不一定是多种服务   逻辑服务可以包含多个操作系统进程,我们提供了轻松实现的功能。

答案 1 :(得分:16)

2016年9月更新docker 1.12(2016年第4季度/ 2017年第1季度)

Arnaud Porterie只是twitted

  

[]刚刚合并:docker run --initRick Grimes会照顾你所有的僵尸。

commit eabae09

请参阅PR 26061:" 为僵尸战斗和信号处理添加初始化过程" (和PR 26736

这为战斗僵尸增加了一个小C二进制文件。它安装在 / dev / init并添加到用户指定的args之前。您 通过守护程序标志dockerd --init启用它,因为它被禁用 默认为向后兼并。

  

您还可以覆盖守护程序选项或在per上指定   以docker run --init=true|false为基础的容器基础。

     

你可以通过运行像这样的进程来测试它,作为a中的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
  

在容器内运行init以转发信号并收集进程

答案 2 :(得分:0)

Docker文档中的这篇文章展示了一个示例,该示例运行多个进程并同时使用supervisor。

https://docs.docker.com/config/containers/multi-service_container/

我的工作很好,但是我们很可能会简单地将工作进程卸载到另一个容器中,而每个容器只处理一个进程。 此时感觉很简单。