Docker CMD指令中的多个命令


39

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

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

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

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

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

只需注意-与预期的command:in指令相同docker-compose.yml

Answers:


33

我相信可能与差异有关,第二条命令执行shell处理,而第一条命令则没有。根据官方文档,有execshell表单,您的第一个命令是exec表单,例如,它不会扩展环境变量,而第二个命令是。因此,通过使用exec表单,该命令可能由于其对shell处理的依赖而失败。您可以通过运行检查docker logs CONTAINERID

您的第二个命令(shell形式)等效于-

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

文档摘录-

注意:与shell窗体不同,exec窗体不会调用命令shell。这意味着正常的外壳处理不会发生。例如,CMD [ "echo", "$HOME" ]将不会对进行变量替换$HOME。如果要进行shell处理,则可以使用shell形式或直接执行shell,例如:CMD [ "sh", "-c", "echo", "$HOME" ]


由于环境变量,命令可能失败。我仍应使用此exec表格,因为它是首选表格吗?为什么首选它?还是应该使用更简单的shell形式?
弗拉丹2015年

之所以失败,是因为执行一个命令是一个外壳函数。环境变量是一个红鲱鱼。
布赖恩

如果您在Docker中运行多个服务,我建议您使用类似Supervisor的流程管理器。这样,您仅启动CMD部分下的主管,它将负责启动服务。您可以在此处查看详细信息-docs.docker.com/articles/using_supervisord
Daniel t。

这是我刚读的一篇文章:)谢谢。
Vladan

我仍然不明白你为什么需要这样做CMD [ "sh", "-c", "echo", "$HOME"]。为什么不CMD ["sh", "-c", "echo $HOME"]这样CMD ["sh -c echo $HOME"]呢?
sixty4bit

4

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

#!/bin/bash

/usr/bin/command2 param1
/usr/bin/commnad1

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

ADD start.sh /

CMD ["/start.sh"]

2

CMD(和RUNENTRYPOINT)的json语法将参数直接作为exec syscall传递给内核。在exec syscall中,命令与参数之间没有空格,引号转义,IO重定向,变量替换,命令之间的管道传递,运行多个命令等之间的分隔。syscall仅使可执行文件运行,并将参数列表传递给该可执行文件,然后运行它。

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


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

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

否则,您的第二种语法会执行完全相同的操作:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

请注意,我不建议您在容器内部以这种方式运行多个命令,因为如果您的第一个命令失败(特别是在后台运行),则不会进行错误处理。您还将在容器内留下一个以pid 1运行的外壳,这将中断信号处理,从而导致10秒的延迟,并被docker恶意破坏您的容器。使用shell exec命令可以减轻信号处理:

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

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


1

我猜第一个命令失败了,因为在DOCKER CMD格式中,仅第一个参数被执行,其余的则馈入该命令。

第二种形式有效,因为所有命令都用“;”分隔 被送入sh命令,然后执行它们。


1

我认为您不应该在“开始”之后加上半逗号

而不是使用

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

尝试

CMD ["/etc/init.d/nullmailer", "start", "/usr/sbin/php5-fpm"]

因为码头工人使用“ sh -c”,所以上面的命令将如下执行

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

json语法不使用shell运行命令,sh -c在这种情况下没有。
BMitch
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.