根据Docker文档:Dockerfile中只能有一条CMD指令。如果您列出多个CMD,则只有最后一个CMD才会生效。
我希望在CMD命令(本例中为init)之前执行一个简单的bash脚本(处理docker环境变量)。
有什么办法吗?
创建一个可以执行所需操作的自定义入口点,然后最后执行您的CMD。
注意 :如果您的映像已经定义了一个自定义入口点,则可能需要扩展它而不是替换它,或者您可以更改所需的行为。
entrypoint.sh :
#!/bin/sh ## Do whatever you need with env vars here ... # Hand off to the CMD exec "$@"
Dockerfile的 :
COPY entrypoint.sh /entrypoint.sh RUN chmod 755 /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]
Docker将使用CMD作为参数来运行您的入口点。如果您的CMD为init,则:
init
/entrypoint.sh init
exec入口点脚本末尾的at负责在入口点完成需要执行的操作时移交给CMD。
exec
ENTRYPOINT和CMD的使用经常使Docker新手感到困惑。在评论中,您对此表示困惑。这是它的工作原理以及原因。
ENTRYPOINT是在容器内运行的初始对象。它以CMD作为参数列表。因此,在此示例中,在容器中运行的是此参数列表:
# ENTRYPOINT = /entrypoint.sh # CMD = init ["/entrypoint.sh", "init"] # or shown in a simpler form: /entrypoint.sh init
不需要图像具有ENTRYPOINT。如果未定义,则Docker具有默认值:/bin/sh -c。
/bin/sh -c
因此,按照您的原始情况,没有ENTRYPOINT,并且使用CMD为init,Docker将会运行以下命令:
/bin/sh -c 'init' ^--------^ ^--^ | \------- CMD \--------------- ENTRYPOINT
最初,Docker只提供CMD,并且/bin/sh -c被硬编码为ENTRYPOINT(您无法更改)。在此过程中的某些时候,人们用例中他们不得不做更多的自定义事情,而Docker公开了ENTRYPOINT,因此您可以将其更改为所需的任何内容。
在上面显示的示例中,ENTRYPOINT被替换为自定义脚本。(尽管它最终仍在运行sh,因为它始于#!/bin/sh。)
sh
#!/bin/sh
ENTRYPOINT将CMD作为参数。在entrypoint.sh脚本的末尾是exec "$@"。由于$@扩展到为脚本提供的参数列表,因此将其转换为
exec "$@"
$@
exec "init"
因此,脚本完成后,它消失了,并被替换init为PID1。(这样做exec是-它 用 另一个命令 替换 了当前进程。)
在评论中,您询问了如何在Dockerfile中添加CMD。是的,你可以这么做。
CMD ["init"]
或者,如果您的命令还有更多内容,例如参数init -a -b,则将如下所示:
init -a -b
CMD ["init", "-a", "-b"]