当我尝试在运行时通过 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
我相信差异可能是因为第二个命令执行 shell 处理,而第一个命令没有。根据官方文档,有
exec
和shell
表格。您的第一个命令是一个exec
表单。exec
表单不会扩展环境变量,而表单shell
会。exec
由于它依赖于 shell 处理,通过使用该命令可能会失败。您可以通过运行检查这一点docker logs CONTAINERID
你的第二个命令,shell 形式,相当于 -
CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm
文档摘录 -
不要让自己难受。只需创建一个 bash 文件“start.sh”:
在你的 Dockerfile 中做:
CMD
(andRUN
and )的 json 语法ENTRYPOINT
将参数作为 exec 系统调用直接传递给内核。在 exec 系统调用中,没有通过空格、转义引号、IO 重定向、变量替换、命令之间的管道、运行多个命令等将命令与参数分开。系统调用只需要运行可执行文件和传递给该可执行文件的参数列表,然后运行它。字符喜欢
$
扩展变量、;
分隔命令、(空格)分隔参数、
&&
链接||
命令、>
输出重定向、|
命令之间的管道等,这些都是 shell 的特性,需要类似/bin/sh
or的东西/bin/bash
来解释和实现它们。如果您切换到 的字符串语法
CMD
,docker 将使用 shell 运行您的命令:否则,您的第二种语法会执行完全相同的操作:
请注意,我不建议在容器内以这种方式运行多个命令,因为如果您的第一个命令失败,则不会进行错误处理,尤其是在它在后台运行时。您还在容器内留下一个以 pid 1 运行的 shell,这将中断信号处理,导致 10 秒延迟和 docker 不正常地杀死您的容器。可以使用 shell
exec
命令减轻信号处理:但是,在后台静默处理进程失败需要您切换到某种多进程管理器,例如 supervisord,或者最好将您的应用程序分解为多个容器并使用 docker-compose 之类的东西部署它们。
我猜第一个命令失败是因为在 DOCKER CMD 形式中,只有第一个参数被执行,其余的被输入到这个命令中。
第二种形式有效,因为所有命令都用“;”分隔 被输入到执行它们的 sh 命令中。
例如,假设您有两个要运行的 python 命令
python init_reset.py
和python app.py
. 然后使用CMD,你可以将两个命令与单个命令结合起来在 Docker compose 中,这可以通过以下示例完成:
会将主可执行文件的
exec
上下文切换到 apache2-forground。我认为您不应该在“开始”之后加上半逗号
而不是使用
尝试
由于 docker 使用“sh -c”,上面的命令将如下执行