【问题标题】:Docker CMD evaluation with ENTRYPOINT使用 ENTRYPOINT 进行 Docker CMD 评估
【发布时间】:2017-05-13 03:21:46
【问题描述】:

我有一个 Dockerfile,它属于 Understand how CMD and ENTRYPOINT interact 中的矩阵中的 exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd 类别。这种行为不是我所期望的。我期待/bin/sh -c exec_cmd p1_cmd 先评估然后传递给exec_entry p1_entry。我观察到的是,/bin/sh -c exec_cmd p1_cmd 确实被传递到了exec_entry p1_entry,我认为这很有趣。

为了提供更多上下文,我专门从 existing Dockerfile 派生了一个新的 Dockerfile,其中父级具有:

ENTRYPOINT ["/bin/registrator"]

我想从我的 Dockerfile 中传递特定的命令行参数:

FROM gliderlabs/registrator:v7
CMD echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST"

当我在容器中运行 Docker 映像时:

$ docker run --rm --name=test-registrator --volume=/var/run/docker.sock:/tmp/docker.sock -e "EXTERNAL_IP=<some-ip>" -e "CONSUL_HOST=<some-consul-hostname>:8500" my/registrator

我收到以下错误:

2016/12/28 19:20:46 Starting registrator v7 ...
Extra unparsed arguments:
  -c echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST"
Options should come before the registry URI argument.

Usage of /bin/registrator:
  /bin/registrator [options] <registry URI>

-cleanup=false: Remove dangling services
-deregister="always": Deregister exited services "always" or "on-success"
-internal=false: Use internal ports instead of published ones
-ip="": IP for ports mapped to the host
-resync=0: Frequency with which services are resynchronized
-retry-attempts=0: Max retry attempts to establish a connection with the backend. Use -1 for infinite retries
-retry-interval=2000: Interval (in millisecond) between retry-attempts.
-tags="": Append tags for all registered services
-ttl=0: TTL for services (default is no expiry)
-ttl-refresh=0: Frequency with which service TTLs are refreshed

这意味着 -c echo "-ip=$EXTERNAL_IP consul://$CONSUL_HOST" 实际上是作为参数传递给 /bin/registrator。

我是在做错什么吗?或者这是对/bin/sh -c exec_cmd p1_cmd 在传递到ENTRYPOINT 之前没有先进行评估的用例的限制?如果后者是真的,那你能不能也解释一下这个用例的用处?

【问题讨论】:

    标签: shell docker dockerfile consul registrator


    【解决方案1】:

    是的。这正是它应该如何工作的。

    CMD 的值只是作为参数传递给 ENTRYPOINT。

    CMD 和 ENTRYPOINT 的主要区别在于,CMD 只是为 ENTRYPOINT 程序提供默认命令参数,并且它通常被 run 命令的参数覆盖。另一方面,如果您希望执行不同的命令,则必须使用 --entrypoint 选项显式重新定义 ENTRYPOINT。

    另外,请注意,根据 Dockerfile 中定义 ENTRYPOINT 和 CMD 的方式,执行操作的方式会有所不同。当它们被定义为 ['arg1', 'arg2'] 形式的数组时,该数组按原样传递给 ENTRYPOINT 命令,其中 ENTRYPOINT 的第一个元素是正在执行的程序。在另一种情况下,当它们被定义为像 arg1 arg2 这样的简单字符串时,首先传递的这个字符串前面加上“/bin/sh -c”注意Docker不执行/bin/sh并返回返回评估的结果,该字符串本身被传递给 ENTRYPOINT 程序。

    所以在你的情况下,你必须使用数组方法来传递参数:

    CMD  [-ip, $EXTERNAL_IP,  consul://$CONSUL_HOST]
    

    【讨论】:

    • 那我不明白这个用例exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd的意义何在。这需要exec_entry 应用程序来处理我认为很奇怪的命令。
    • 啊,错过了那部分。当 CMD 以字符串形式定义时,实际上是退化的情况,但您的 ENTRYPOINT 不是外壳。我不认为它有任何用处。唯一使用这种语法是有意义的,当你的 ENTRYPOINT 是一个 shell(bash、sh、csh)并且你有这样的命令行“ls .c”时,globs 可以工作。否则 ls 只会获取 '.c' 作为参数,并会查找名为 '*.c' 的文件,而不是以 '.c' 结尾的文件集
    • 感谢您的意见!我想指出(虽然很好)CMD [-ip, $EXTERNAL_IP, consul://$CONSUL_HOST] 不起作用,因为环境变量无法解析。请参阅 Shell 表单 下的this article,然后查看 Exec 表单。
    • 是的,你说得对。解析 glob 和环境变量是 shell 的工作。在您的情况下,我只需在您自己的图像中重新定义 ENTRYPOINT 以指向 /bin/sh 并添加一个带有 /bin/registrator -ip=$EXTERNAL_IP consul://$CONSUL_HOST 的小型 shell 脚本,这样您将得到您想要的想要。
    猜你喜欢
    • 1970-01-01
    • 2019-05-02
    • 2017-12-20
    • 1970-01-01
    • 1970-01-01
    • 2018-08-08
    • 1970-01-01
    • 2014-05-19
    • 1970-01-01
    相关资源
    最近更新 更多