Docker CMD 指令中的多个命令

Vla*_*dan 73 docker

当我尝试在运行时通过 Dockerfile 中的 CMD 指令执行两个命令时,不明白发生了什么。我认为这应该有效:

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]
Run Code Online (Sandbox Code Playgroud)

但它不起作用。容器尚未启动。所以我不得不这样做:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]
Run Code Online (Sandbox Code Playgroud)

我不明白。这是为什么?为什么第一行不是正确的方法?有人可以向我解释这些“CMD shell 格式与 JSON 格式等”的内容。用简单的话来说。

请注意 -正如预期的那样,command:指令 indocker-compose.yml也是如此。

Dan*_* t. 57

我相信差异可能是因为第二个命令执行 shell 处理而第一个命令没有。根据官方文档,有execshell表格。您的第一个命令是一个exec表单。的exec同时,形式不展开环境变量shell的形式一样。通过使用该exec表单,该命令可能会因依赖于 shell 处理而失败。您可以通过运行来检查这一点docker logs CONTAINERID

你的第二个命令,shell 形式,相当于 -

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

文档摘录 -

注意:与 shell 形式不同,exec 形式不调用命令 shell。这意味着不会发生正常的 shell 处理。例如,CMD [ "echo", "$HOME" ]不会对 进行变量替换$HOME。如果你想要 shell 处理,那么要么使用 shell 形式,要么直接执行 shell,例如:CMD [ "sh", "-c", "echo", "$HOME" ].

  • 我仍然不明白为什么你需要执行 `CMD [ "sh", "-c", "echo", "$HOME"]`。为什么不使用`CMD ["sh", "-c", "echo $HOME"]`或者`CMD ["sh -c echo $HOME"]`? (3认同)

小智 46

不要为难自己。只需创建一个 bash 文件“start.sh”: 

#!/bin/bash

/usr/bin/command2 param1
/usr/bin/command1
Run Code Online (Sandbox Code Playgroud)

在您的 Dockerfile 中执行以下操作:

ADD start.sh /
RUN chmod +x /start.sh

CMD ["/start.sh"]
Run Code Online (Sandbox Code Playgroud)

  • 虽然我完全同意 KISS,但不幸的是,这可能会影响旧版本 docker 的性能和/或不必要地增加构建镜像的大小。这是因为您正在使用“ADD”和“RUN”创建两个层,请查看[最佳实践,最小化层数](https://docs.docker.com/develop/develop-images/ dockerfile_best-practices/#minimize-the-number-of-layers)。 (2认同)
  • 我的理解是,这将在 shell 中运行脚本,导致任何生成的进程(例如 webserver)成为 shell 的子进程,并且不会被转发 SIGTERM,从而阻止这些进程正常退出 (2认同)

BMi*_*tch 8

CMD(andRUNENTRYPOINT)的 json 语法将参数作为 exec 系统调用直接传递给内核。在 exec 系统调用中,没有通过空格、引号转义、IO 重定向、变量替换、命令之间的管道、运行多个命令等将命令与参数分开。系统调用只需要运行可执行文件和传递给该可执行文件的参数列表,然后运行它。

字符,如$扩大变量,;以单独的命令,(空间)分开的争论,&&||以链的命令,>输出重定向,|以命令之间的管道等,都是壳和需要像所有功能/bin/sh/bin/bash解释并加以实施。


如果您切换到 的字符串语法CMD,docker 将使用 shell 运行您的命令:

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm
Run Code Online (Sandbox Code Playgroud)

否则,你的第二个语法做同样的事情:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]
Run Code Online (Sandbox Code Playgroud)

请注意,我不建议在容器内以这种方式运行多个命令,因为如果您的第一个命令失败,则没有错误处理,尤其是在后台运行时。您还将在容器内以 pid 1 的身份运行 shell,这将中断信号处理,从而导致 10 秒延迟和 docker 对您的容器的不当终止。信号处理可以通过使用 shellexec命令来缓解:

CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm
Run Code Online (Sandbox Code Playgroud)

但是,在后台静默处理失败的进程需要您切换到某种多进程管理器,例如 supervisord,或者最好将您的应用程序分解为多个容器并使用诸如 docker-compose 之类的工具部署它们。