docker - 如何解析 docker 文件中的 CMD 和 ENTRYPOINT exec 形式?

标签 docker dockerfile

我正在 Docker 容器中运行 Jupyter。下面的 shell 形式可以正常运行:

CMD jupyter lab --ip='0.0.0.0' --port=8888 --no-browser --allow-root /home/notebooks

但是 docker 文件上的以下内容不会:

ENTRYPOINT ["/bin/sh", "-c"]
CMD ["jupyter", "lab", "--ip='0.0.0.0'", "--port=8888", "--no-browser", "--allow-root", "/home/notebooks"]

错误是:

usage: jupyter [-h] [--version] [--config-dir] [--data-dir] [--runtime-dir] [--paths] [--json] [subcommand]
jupyter: error: one of the arguments --version subcommand --config-dir --data-dir --runtime-dir --paths is required

很明显,/bin/sh -c 看到了 jupyter 参数,但看不到以下参数。

有趣的是,

CMD ["jupyter", "lab", "--ip='0.0.0.0'", "--port=8888", "--no-browser", "--allow-root", "/home/notebooks"]

会正常运行,所以它不能是参数的数量,或者可以吗?

根据https://docs.docker.com/engine/reference/builder/#cmd ,CMD的shell形式以/bin/sh -c执行。所以从我的角度来看,我认为这两个版本没有什么区别。但原因一定是当 ENTRYPOINT 和 CMD 同时存在时如何评估 exec 形式。

最佳答案

在非常低的级别上,Linux 命令作为一系列“单词”执行。通常,您的 shell 会采用类似 ls -l "a directory" 的命令行,并将其分解为三个单词 ls -l a目录。 (注意“目录”中的空格:在shell形式中需要引用才能在同一个单词中。)

Dockerfile CMDENTRYPOINT(和 RUN)命令有两种形式。在您指定的类似于 JSON 数组的表单中,您明确指定了单词的分解方式。如果它看起来不像 JSON 数组,那么整个内容将被视为单个字符串,并包装在 sh -c 命令中。

# Explicitly spelling out the words
RUN ["ls", "-l", "a directory"]

# Asking Docker to run it via a shell
RUN ls -l 'a directory'
# The same as
RUN ["sh", "-c", "ls -l 'a directory'"]

如果您specify both ENTRYPOINT and CMD两个单词列表只是组合在一起。对于您的示例来说,重要的是 sh -c 接受下一个单词并将其作为 shell 命令运行;任何剩余的单词都可以用作该命令字符串中的 $0$1、... 位置参数。

所以在你的例子中,最后运行的东西或多或少

ENTRYPOINT+CMD ["sh", "-c", "jupyter", ...]
# If the string "jupyter" contained "$1" it would expand to the --ip option

另一个重要的推论是,实际上, ENTRYPOINT 不能是裸字符串格式:当 CMD 附加到它时,您会得到

ENTRYPOINT some command
CMD with args

ENTRYPOINT+CMD ["sh", "-c", "some command", "sh", "-c", "with args"]

按照同样的规则,所有 CMD 单词都会被忽略。

实际上,您几乎不需要在 Dockerfile 中显式放置 sh -cSHELL 声明;请改用字符串形式的命令,或将复杂的逻辑放入 shell 脚本中。

关于docker - 如何解析 docker 文件中的 CMD 和 ENTRYPOINT exec 形式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60718166/

相关文章:

ssh - kubectl : Error from server: No SSH tunnels currently open

java - 将 Maven 存储库挂载到 Docker

docker : Why the Commands from Dockerfile were not being executed?

json - 复制 package.json - Dockerfile

docker - 适用于USB设备的Docker群

Docker Swarm 错误响应

docker - 未设置失败的JAVA_HOME的CloudBuild faSTLane任务,并且在PATH中找不到 'java'命令

docker - 如何通过 SSL 实现和运行 docker 容器

docker - 在 Docker 容器中使用 VNCserver + GUI 应用程序 + 虚拟显示

linux - 公钥不可用 : NO_PUBKEY F76221572C52609D