Docker CMD指令中的多个命令

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

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

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

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

我不明白 这是为什么? 为什么第一行不是正确的方式? 有人可以解释我这些"CMD shell格式vs JSON格式等"的东西。 用简单的话来说。

只是要注意-同样是与 command: 指示 docker-compose.yml,正如预期的那样。

我相信区别可能是因为第二个命令做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" ].

别让自己为难。 只需创建一个bash文件"start.sh":

#!/bin/bash/usr/bin/command2 param1/usr/bin/command1

在你的Dockerfile do:

ADD start.sh /RUN chmod +x /start.shCMD ["/start.sh"]

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

人物喜欢 $ 展开变量, ; 分离命令, (空格)分隔参数, &&|| 链式命令, > 用于输出重定向, | 命令之间的管道等,都是shell的功能,需要类似的东西 /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"]

请注意,我不建议在容器内以这种方式运行多个命令,因为如果第一个命令失败,特别是在后台运行,则没有错误处理。 您还会在容器内留下一个运行为pid1的shell,这将破坏信号处理,导致10秒的延迟和码头工人忘恩负义地杀死您的容器。 信号处理可以通过使用外壳来减轻 exec 命令:

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

但是,处理在后台静默失败的进程需要您切换到像supervisord这样的多进程管理器,或者最好将您的应用程序分解为多个容器并使用docker-compose之类的东西进行部署。

我猜first命令失败,因为在DOCKER CMD形式中,只执行第一个参数,其余部分被送入此命令。

第二种形式是有效的,因为所有与";"分开的命令都输入到sh命令中,由sh命令执行它们。

例如,假设你有两个python命令要运行 python init_reset.pypython app.py. 然后使用CMD,您可以将两个命令与单个命令合并

CMD python init_reset.py ; python app.py

在Docker compose中,这可以通过以下示例完成:

command: ["sh", "-c", "    apt update && apt install -y libldap-common;    cp /ca.crt /usr/local/share/ca-certificates/;    update-ca-certificates;    exec apache2-foreground  "]

exec 将主可执行文件的上下文切换到apache2-forground。

我不认为你应该在"开始"之后加上半逗号"

而不是使用

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