在CMD之前执行脚本 [英] Execute a script before CMD

查看:167
本文介绍了在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.sh 

ENTRYPOINT [/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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆