如何在docker run命令中使用--init参数

78

docker run--init--init-path选项,但是它们的使用方法不太清楚。

起初,我以为这是类似于dumb-init,但包含在docker核心中(有点像“本地”)。 但是,--init键要求同时设置--init-path,指向docker-init二进制文件,并且没有提示在哪里获取它。关于docker-init,谷歌是沉默的。

好吧,也许我应该使用yelp/dumb-init或'phusion/baseimage-docker',但是这些解决方案似乎没有使用docker run--init选项。

那么,我想知道我应该在哪里获取这个“docker-init二进制文件”,并将其设置为--init-path


你使用的是哪个版本?我在最新版本中没有遇到这个问题。 - Ricardo Branco
Docker 版本 17.03.1-ce,构建 c6d412e。 - Mikhail Vasin
1
本讨论的读者可能会发现有关 docker run--init 的文档很有用:https://docs.docker.com/engine/reference/run/#specify-an-init-process - blong
2个回答

105

在运行命令中指定新的docker --init选项,基本上将ENTRYPOINT设置为tini并将CMD传递给它,或者将命令行上指定的任何内容传递给它。

例如,没有init,CMD变成pid 1。在这种情况下,/bin/bash。

docker run -ti --rm ubuntu:16.04 /bin/bash
root@d740f7360840:/# ps -fA
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  1 03:30 ?        00:00:00 /bin/bash
root        11     1  0 03:30 ?        00:00:00 ps -fA

使用 --init 参数后,tini (/dev/init) 将成为 PID 1。

docker run -ti --init --rm ubuntu:16.04 /bin/bash
root@5b5fe6ee71b5:/# ps -fA
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  1 03:30 ?        00:00:00 /dev/init -- /bin/bash
root         7     1  0 03:30 ?        00:00:00 /bin/bash
root        12     7  0 03:30 ?        00:00:00 ps -fA

tini是一个一流的init进程,可以正确地作为pid 1运行。一个pid 1进程必须正确地回收fork的子进程,否则会发生糟糕的事情,比如资源泄漏和僵尸进程出现。

对于那些分叉而又没有考虑回收子进程的应用程序,这正是你所需要的,因为通常它们会把这个责任留给init系统。Java Jenkins应用程序就是一个典型的例子。


9
这里提出了非常好的观点!我也建议每个人都去看一下关于tini的这篇文章 - ira
所以我有一个安装了多个命令和进程的Python应用程序的图像,包括Web服务器、监视器、工作程序等。我创建了一个入口点脚本,为每个命令进行一些设置,这样我就可以运行3个版本的图像,并仅传递Web服务器、监视器或工作程序作为命令。入口点处理与其他命令不同的Web服务器的一些初始化。如果gunicorn工作程序死掉,我确实会得到一些僵尸进程;我一直在想是否可以加入--init并保持入口点和命令不变。 - dlamblin
1
@dlamblin 看起来是可能的;请参阅此处 Tini 的文档:https://github.com/krallin/tini#existing-entrypoint - Apteryx
@Apteryx; 我其实想知道使用docker的--init是否会更改入口点,以便像tini文档建议的那样添加tini前缀,或者它是否保留入口点但然后使用tini运行它(实际上是相同的事情但镜像上的元数据不同),或者它是否替换入口点为tini(这是docker文档似乎在说的)。 - dlamblin
1
@dlamblin 看了一下 --init 功能的 PR(https://github.com/moby/moby/pull/26061/commits#diff-ea22bb26655e758dc94c291dbaee0e76R596),在 oci_linux.go 模块的 populateCommonSpecs 过程中,实现的是:给即将被执行的任何程序和参数添加前缀 "/dev/init",然后与 Tini 的二进制文件进行绑定挂载。我猜测元数据没有受到影响,因为这个 populateCommonSpecs 命令的目的似乎是初始化容器的基本文件系统。 - Apteryx
5
这个回答中有一个误导性的地方,就是使用 --init 实际上并没有在容器元数据中设置入口点(即如果 Dockerfile 中没有 ENTRYPOINT,并使用 --init,则 docker inspect 中的入口点字段仍将为空)。它所做的是设置键 HostConfig.Inittrue。指定了二进制文件路径的 docker-init(通过 init-path),作为 /dev/init 在容器中绑定挂载。当设置了该键时,/dev/init 将被添加到用户的命令参数之前。在 Docker 18.06 上进行了测试。 - init_js

10
我在文档中找到了以下内容:

您可以使用 --init 标志指示在容器中使用 init 进程作为 PID 1。指定 init 进程可确保在创建的容器内执行 init 系统的常规职责,例如清理僵尸进程。使用的默认 init 进程是 Docker 守护进程系统路径中找到的第一个 docker-init 可执行文件。这个 docker-init 二进制文件包含在默认安装中,由tini支持。

我在 macOS 上的 Docker 安装中找不到 docker-init,但在 Linux 上可以在此处找到:

/usr/bin/docker-init


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接