在CMD之前执行一个脚本
根据Docker文档 :Dockerfile中只能有一个CMD指令。 如果列出多个CMD,则只有最后一个CMD才会生效。
我希望执行一个简单的bash脚本(处理docker环境variables)之前的CMD命令(这是我的情况下初始化)。
有没有办法做到这一点?
使用自定义入口点
创build一个自定义的入口点,然后exec你的CMD。
注意 :如果你的图像已经定义了一个自定义的入口点,你可能需要扩展它而不是replace它,或者你可以改变你需要的行为。
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
,那么:
/entrypoint.sh init
入口点脚本结束时的exec
在入口点完成它所需要做的事情时,负责交给CMD。
为什么这个工作
入口点和CMD的使用经常使新来的人困惑于Docker。 在评论中,你对此表示困惑。 这是如何工作,为什么。
入口点是在容器内运行的第一个东西。 它将CMD作为参数列表。 因此,在这个例子中,容器中运行的是这个参数列表:
# ENTRYPOINT = /entrypoint.sh # CMD = init ["/entrypoint.sh", "init"] # or shown in a simpler form: /entrypoint.sh init
不需要图像具有入口点。 如果你不定义一个,Docker有一个默认的: /bin/sh -c
。
所以在你原来的情况下,没有ENTRYPOINT,并且使用CMD的init
,Docker会运行这个:
/bin/sh -c 'init' ^--------^ ^--^ | \------- CMD \--------------- ENTRYPOINT
一开始,Docker只提供了CMD,而/bin/sh -c
则被硬编码为ENTRYPOINT(你不能改变它)。 在这个过程中的某个时刻,人们已经在使用案例,他们必须做更多的自定义事情,Docker暴露了入口点,所以您可以将其更改为任何您想要的东西。
在上面的示例中,ENTRYPOINT被replace为一个自定义脚本。 (尽pipe它最终仍然由sh
运行,因为它以#!/bin/sh
开头。)
入口点将CMD作为参数。 在entrypoint.sh脚本的末尾是exec "$@"
。 由于$@
展开给脚本的参数列表,所以变成了
exec "init"
因此,当脚本完成时,它会消失,被init
replace为PID 1.(这就是exec
所做的 – 它用一个不同的命令replace当前进程)。
如何包含CMD
在评论中,您问到在Dockerfile中添加CMD。 是的,你可以这么做。
Dockerfile :
CMD ["init"]
或者如果你的命令有更多的话,比如像init -a -b
这样的参数,看起来像这样:
CMD ["init", "-a", "-b"]
丹的回答是正确的,但我觉得实施起来相当混乱。 对于那些在相同的情况下,这里是代码示例我如何实现他的解释使用入口点,而不是CMD。
这里是我的Dockerfile中的最后几行:
#change directory where the mergeandlaunch script is located. WORKDIR /home/connextcms ENTRYPOINT ["./mergeandlaunch", "node", "keystone.js"]
这里是合并和启动bash shell脚本的内容:
#!/bin/bash #This script should be edited to execute any merge scripts needed to #merge plugins and theme files before starting ConnextCMS/KeystoneJS. echo Running mergeandlaunch script #Execute merge scripts. Put in path to each merge script you want to run here. cd ~/theme/rtb4/ ./merge-plugin #Launch KeystoneJS and ConnextCMS cd ~/myCMS exec "$@"
这里是如何执行代码:
- ENTRYPOINT命令启动
mergeandlaunch
shell脚本 - 两个参数'node'和'keystone.js'被传递给shell脚本。
- 在脚本的末尾,参数被传递给
exec
命令。 - exec命令然后像Docker命令CMD一样启动我的节点程序。