【问题标题】:Can docker entrypoint in shell form use runtime command args?shell形式的docker入口点可以使用运行时命令args吗?
【发布时间】:2020-11-06 17:30:16
【问题描述】:

这是一个带有 shell 形式入口点的示例 dockerfile:

FROM ubuntu
ENTRYPOINT /bin/echo "(shell) ENTRYPOINT@image ($0)"

下面是我从各种运行中看到的一些输出:

$ docker run -it sc-test:v4
(shell) ENTRYPOINT@image (/bin/sh)
$ docker run -it sc-test:v4 /bin/echo
(shell) ENTRYPOINT@image (/bin/echo)
$ docker run -it sc-test:v4 /bin/cat
(shell) ENTRYPOINT@image (/bin/cat)
$ docker run -it sc-test:v4 /bin/dog
(shell) ENTRYPOINT@image (/bin/dog)
$ docker run -it sc-test:v4 "/bin/dog ($0)"
(shell) ENTRYPOINT@image (/bin/dog (-bash))

根据 docker 文档here,我们可以看到命令 args 被忽略了。

但是,$0 的值会随着提供的参数而变化。有人可以解释为什么会这样吗?谢谢!

【问题讨论】:

  • 看起来文档是错误的。来自CMD 的参数在我的测试中绝对不会被忽略。

标签: linux bash docker shell kubernetes


【解决方案1】:

Docker 文档的该部分中的表格在技术上并不正确:当存在 shell 形式的入口点时,Docker 实际上并没有删除或忽略命令部分。这里实际发生的(您的示例演示)是:

  1. 如果ENTRYPOINTCMD(或两者都是)是shell 形式,则它被包裹在["/bin/sh", "-c", "..."] 中。
  2. ENTRYPOINTCMD 列表连接起来形成一个命令列表。

让我们举第三个例子。这是,在 Dockerfile 语法中,

ENTRYPOINT /bin/echo "(shell) ENTRYPOINT@image ($0)"
CMD ["/bin/cat"]

生成的组合命令是(在 JSON 数组语法中,为清楚起见进行了扩展)

[
  "/bin/sh",
  "-c",
  "/bin/echo \"(shell) ENTRYPOINT@image ($0)\"",
  "/bin/cat"
]

那么,如果你给sh -c 提供多个参数,它会做什么呢? POSIX spec for the sh command 将语法记录为

sh -c command_string [command_name [argument...]]

和其他文件

-c:从 command_string 操作数中读取命令。从 command_name 操作数的值中设置特殊参数 0 [...] 的值,从剩余的 参数 中依次设置位置参数($1、$2 等) em> 操作数。不得从标准输入中读取任何命令。

这就是您在示例中看到的。如果ENTRYPOINT是一个裸字符串,CMD是一个JSON数组,那么在ENTRYPOINT字符串命令中,CMD中的参数可以用作$0$1等等。如果两者都是裸字符串,则都被包裹在 sh -c 中,你会得到类似的东西:

ENTRYPOINT /bin/echo "$0 is /bin/sh, $1 is -c, and then $2"
CMD the rest of the line

在您的第一个示例中,命令部分是空的,在这种情况下(仍然来自 POSIX sh 文档)

如果 command_name 没有指定,特殊参数 0 应设置为 [...] 通常是用于执行 sh 实用程序的路径名。

你的最后一个例子更微妙:

docker run -it sc-test:v4 "/bin/dog ($0)"

由于字符串是双引号,你的 local shell 扩展了其中的 $0 引用,这就是 bash 进入那里的方式;那么由于它是一个(引用的)单词,它成为sh -c 的单个 command_name 参数。


ENTRYPOINTCMD 一起使用还有另外两种正常模式。我更喜欢的模式是CMD 是一个完整的shell 命令,ENTRYPOINT 进行一些首次设置,然后运行类似exec "$@" 的命令来运行该命令。还有一个“容器即命令”模式,其中ENTRYPOINT 有一个完整的命令(可能涉及JVM 参数)和CMD 附加选项。在这些情况下,ENTRYPOINT 必须是 JSON 数组语法:

ENTRYPOINT ["/script-that-exec-dollar-at.sh"]
CMD ["the_command", "--option"]

由于ENTRYPOINT 字符串不直接引用$0$1等。CMD 参数有效 em> 被 sh -c 包装器忽略。如果您有ENTRYPOINT script.sh,它将被sh -c 作为没有参数的子进程调用,并且CMD 会丢失。

Docker 文档中说“如果 ENTRYPOINT 是一个字符串,则 CMD 被忽略”可能比试图解释其中的微妙之处更清楚。

【讨论】:

  • (因为你用 kubernetes 标记了它:在 pod 规范中,command: 是入口点,args: 是命令。)
猜你喜欢
  • 1970-01-01
  • 2016-05-28
  • 2013-02-11
  • 2011-07-08
  • 2016-06-19
  • 2021-10-11
  • 1970-01-01
  • 2018-02-05
  • 2018-11-05
相关资源
最近更新 更多