在CMD之前执行脚本 [英] Execute a script before CMD
问题描述
根据 Docker文档:
只能作为Docker文件中的一个CMD指令。如果列出多个CMD,那么只有最后一个CMD才会生效。
我希望在CMD命令之前执行一个简单的bash脚本(它处理docker环境变量) (在我的情况下是init)。
有没有办法做到这一点?
使用自定义入口点
创建一个自定义entrypoint,执行你想要的,然后exec的你的CMD结束。
注意:如果您的图像已经定义了自定义入口点,则可能需要扩展它而不是替换它,或者您可以更改
entrypoint.sh :
#!/ bin / sh
##做任何你需要的env vars这里...
#交给CMD
exec$ @
Dockerfile :
运行chmod 755 /entrypoint.shENTRYPOINT [/entrypoint.sh]
Docker将运行您的entrypoint,使用CMD作为参数。如果你的CMD是 init
,那么:
/entrypoint.sh init
exec
在entrypoint脚本的末尾,当entrypoint完成需要做的事情时,将负责处理CMD。
为什么这样工作
使用ENTRYPOINT和CMD经常让人们对Docker感到陌生。在评论中,你对此表示混淆。这是它的工作原理以及为什么。
ENTRYPOINT是容器内运行的初始操作。它将CMD作为参数列表。因此,在这个例子中,容器中运行的是这个参数列表:
#ENTRYPOINT = /entrypoint.sh
#CMD = init
[/entrypoint.sh,init]
#或以更简单的形式显示:
/ entrypoint.sh init
图像不需要ENTRYPOINT。如果您没有定义一个,Docker有一个默认值: / 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
开头。) / p>
ENTRYPOINT以CMD为参数。在entrypoint.sh脚本的末尾是 exec$ @
。由于 $ @
扩展到给脚本的参数列表,所以转换为
execinit
因此,当脚本已经完成,它消失,并被 init
替换为PID 1.(这就是 exec
em 替换当前进程使用不同的命令。)
如何包含CMD
在评论中,您询问了在Docker文件中添加CMD。是的,你可以这样做。
Dockerfile :
CMD [init]
或者如果有更多的是你的命令,例如
init -a -b > CMD [init,-a,-b]
As per Docker documentation: There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the last CMD will take effect.
I wish to execute a simple bash script(which processes docker environment variable) before the CMD command(which is init in my case).
Is there any way to do this?
Use a custom entrypoint
Make a custom entrypoint which does what you want, and then exec's your CMD at the end.
NOTE: if your image already defines a custom entrypoint, you may need to extend it rather than replace it, or you may change behavior you need.
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 will run your entrypoint, using CMD as arguments. If your CMD is init
, then:
/entrypoint.sh init
The exec
at the end of the entrypoint script takes care of handing off to CMD when the entrypoint is done with what it needed to do.
Why this works
The use of ENTRYPOINT and CMD frequently confuses people new to Docker. In comments, you expressed confusion about it. Here is how it works and why.
The ENTRYPOINT is the initial thing run inside the container. It takes the CMD as an argument list. Therefore, in this example, what is run in the container is this argument list:
# ENTRYPOINT = /entrypoint.sh
# CMD = init
["/entrypoint.sh", "init"]
# or shown in a simpler form:
/entrypoint.sh init
It is not required that an image have an ENTRYPOINT. If you don't define one, Docker has a default: /bin/sh -c
.
So with your original situation, no ENTRYPOINT, and using a CMD of init
, Docker would have run this:
/bin/sh -c 'init'
^--------^ ^--^
| \------- CMD
\--------------- ENTRYPOINT
In the beginning, Docker offered only CMD, and /bin/sh -c
was hard-coded as the ENTRYPOINT (you could not change it). At some point along the way, people had use cases where they had to do more custom things, and Docker exposed ENTRYPOINT so you could change it to anything you want.
In the example I show above, the ENTRYPOINT is replaced with a custom script. (Though it is still ultimately being run by sh
, because it starts with #!/bin/sh
.)
That ENTRYPOINT takes the CMD as is argument. At the end of the entrypoint.sh script is exec "$@"
. Since $@
expands to the list of arguments given to the script, this is turned into
exec "init"
And therefore, when the script is finished, it goes away and is replaced by init
as PID 1. (That's what exec
does - it replaces the current process with a different command.)
How to include CMD
In the comments, you asked about adding CMD in the Dockerfile. Yes, you can do that.
Dockerfile:
CMD ["init"]
Or if there is more to your command, e.g. arguments like init -a -b
, would look like this:
CMD ["init", "-a", "-b"]
这篇关于在CMD之前执行脚本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!