在CMD之前执行脚本

kum*_*mar 17 environment-variables docker

根据Docker文档:Dockerfile中只能有一条CMD指令.如果列出多个CMD,则只有最后一个CMD才会生效.

我希望在CMD命令(在我的情况下是init)之前执行一个简单的bash脚本(处理docker环境变量).

有没有办法做到这一点?

Dan*_*owe 37

使用自定义入口点

制作一个自定义入口点,它可以满足您的需要,然后在最后执行您的CMD.

注意:如果您的图像已经定义了自定义入口点,则可能需要对其进行扩展而不是替换它,或者您可以更改所需的行为.

entrypoint.sh:

#!/bin/sh

## Do whatever you need with env vars here ...

# Hand off to the CMD
exec "$@"
Run Code Online (Sandbox Code Playgroud)

Dockerfile:

COPY entrypoint.sh /entrypoint.sh
RUN chmod 755 /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
Run Code Online (Sandbox Code Playgroud)

Docker将使用CMD作为参数运行您的入口点.如果你的CMD是init,那么:

/entrypoint.sh init
Run Code Online (Sandbox Code Playgroud)

exec在入口点脚本的末尾需要移交给CMD,当入口点与它所需要做的做的照顾.

为什么会这样

使用ENTRYPOINT和CMD经常会让人们对Docker的新用户感到困惑.在评论中,你表达了对它的困惑.这是它的工作原理和原因.

ENTRYPOINT是在容器内运行的最初事物.它将CMD作为参数列表.因此,在此示例中,容器中运行的是此参数列表:

# ENTRYPOINT = /entrypoint.sh
# CMD        = init
["/entrypoint.sh", "init"]

# or shown in a simpler form:
/entrypoint.sh init
Run Code Online (Sandbox Code Playgroud)

图像不需要具有ENTRYPOINT.如果你没有定义一个,Docker有一个默认值:/bin/sh -c.

因此,对于您的原始情况,没有ENTRYPOINT,并使用CMD init,Docker将运行此:

/bin/sh -c 'init'
^--------^  ^--^
    |         \------- CMD
    \--------------- ENTRYPOINT
Run Code Online (Sandbox Code Playgroud)

最初,Docker只提供CMD,并且/bin/sh -c被硬编码为ENTRYPOINT(你无法改变它).在这个过程中的某些时候,人们有必须做更多自定义事情的用例,而Docker公开了ENTRYPOINT,因此您可以将其更改为您想要的任何内容.

在上面显示的示例中,ENTRYPOINT被替换为自定义脚本.(虽然它仍然最终被运行sh,因为它始于#!/bin/sh.)

ENTRYPOINT以CMD为参数.在entrypoint.sh脚本的末尾是exec "$@".由于$@扩展到给予脚本的参数列表,因此将其转换为

exec "init"
Run Code Online (Sandbox Code Playgroud)

因此,当脚本完成后,它就会消失并被initPID 1 替换.(这就是exec它 - 它不同的命令替换当前进程.)

如何包含CMD

在评论中,您询问了如何在Dockerfile中添加CMD.是的,你可以这样做.

Dockerfile:

CMD ["init"]
Run Code Online (Sandbox Code Playgroud)

或者,如果你的命令有更多,例如像这样的参数init -a -b,看起来像这样:

CMD ["init", "-a", "-b"]
Run Code Online (Sandbox Code Playgroud)


Chr*_*ner 5

丹的回答是正确的,但我发现实施起来相当混乱。对于那些处于相同情况的人,这里是我如何实现他对使用 ENTRYPOINT 而不是 CMD 的解释的代码示例。

这是我的 Dockerfile 中的最后几行:

#change directory where the mergeandlaunch script is located.
WORKDIR /home/connextcms
ENTRYPOINT ["./mergeandlaunch", "node", "keystone.js"]
Run Code Online (Sandbox Code Playgroud)

以下是 mergeandlaunch 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 "$@"
Run Code Online (Sandbox Code Playgroud)

下面是代码的执行方式:

  1. ENTRYPOINT 命令启动mergeandlaunchshell 脚本
  2. 'node' 和 'keystone.js' 这两个参数被传递给 shell 脚本。
  3. 在脚本结束时,参数被传递给exec命令。
  4. 然后 exec 命令以与 Docker 命令 CMD 相同的方式启动我的节点程序。