docker中Supervisor的使用
Posted
技术标签:
【中文标题】docker中Supervisor的使用【英文标题】:Use of Supervisor in docker 【发布时间】:2016-01-12 01:17:35 【问题描述】:我不是在询问是否在码头工人中使用主管,而只是想验证我的理解。
我了解 docker 在运行时会运行一个进程。另外,当我们需要在容器内运行多个进程时,使用supervisor。
我见过几个例子,其中一个容器从基础镜像启动并安装了几个服务,并且容器承诺形成一个新的镜像,所有这些都没有主管。
所以,我的基本疑问是这两种方法有什么区别。
我的理解是,当 docker 容器停止时,它会向 PID 1 的进程发送终止信号,PID 1 管理子进程并停止所有子进程,这正是主管所做的,而我们可以安装多个进程而无需当发出docker run
时,supervisor只能运行一个进程,当容器停止时,只会发送PID 1信号,其他正在运行的进程不会被优雅地停止。
请确认我对使用supervisord
的理解在多大程度上是正确的。
【问题讨论】:
2016 年 9 月更新:请参阅下面的 my new answer:docker 守护进程可以在 docker 1.12 中为您处理那些僵尸进程。 【参考方案1】:虽然我们可以在没有supervisor的情况下安装多个进程,但发出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——有一个特殊的任务。它的任务是“采用”孤立的子进程。
操作系统希望 init 进程也能获得收养的孩子。
Docker 的问题:
我们看到很多人在他们的容器中只运行一个进程,他们认为当他们运行这个单一进程时,他们就完成了。但很可能,这个进程并没有写入表现得像一个适当的初始化进程。 也就是说,它可能期望另一个
init
进程来完成这项工作,而不是正确地收获采用的流程,这是正确的。
使用像phusion/baseimage-docker
这样的图像有助于管理一个(或多个)进程,同时保持主进程的初始化兼容。
它使用runit
instead of supervisord
,用于多进程管理:
Runit 不是用来解决收割问题的。相反,它是为了支持多个进程。为安全起见,鼓励使用多个进程(通过进程和用户隔离)。 Runit 使用的内存比 Supervisord 少,因为 Runit 是用 C 编写的,而 Supervisord 是用 Python 编写的。 在某些用例中,容器中的进程重启比整个容器重启更可取。
该图片包含一个my_init
script,它负责处理“收割”问题。
在 baseimage-docker 中,我们鼓励在单个容器中运行多个进程。但不一定是多种服务。 一个逻辑服务可以由多个操作系统进程组成,我们提供了可以轻松做到这一点的工具。
【讨论】:
感谢您的详尽回答。我正在尝试 phusion 图像,据我所知,每当容器启动时,它都会运行 /etc/init.d 中的任何内容。但是,我在 init.d 中有一项服务没有在容器启动时启动。你能帮忙吗? 当然:您能提出一个新问题,并提供新设置的详细信息吗?这样,我(可能还有其他人)可以看看。 哦..我的错误是 /etc/my_init.d 这里的关键点是phusion/baseimage-docker【参考方案2】:2016 年 9 月更新 docker 1.12(2016 年第四季度/2017 年第一季度)
Arnaud Porterie 只是twitted:
[?] 刚刚合并:与
docker run --init
,Rick Grimes 将照顾你所有的僵尸。
(commit eabae09)
参见PR 26061:“为僵尸战斗和信号处理添加初始化进程”(和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
在容器内运行一个 init 来转发信号和获取进程
【讨论】:
【参考方案3】:Docker 文档中的这篇文章展示了一个运行多个进程并同时使用 supervisord 的示例。
https://docs.docker.com/config/containers/multi-service_container/
我的工作正常,但我们可能会简单地将工作进程卸载到另一个容器中,并且每个容器中只处理一个进程。 在这一点上感觉像是一种更简单的方法。
【讨论】:
以上是关于docker中Supervisor的使用的主要内容,如果未能解决你的问题,请参考以下文章