如何解析docker文件中的CMD和ENTRYPOINT执行表格?

时间:2020-03-17 07:45:34

标签: docker dockerfile

我正在Docker容器中运行Jupyter。以下外壳程序形式可以正常运行:

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表单。

1 个答案:

答案 0 :(得分:4)

在非常低的级别上,Linux命令作为一系列“单词”执行。通常,您的shell将使用ls -l "a directory"之类的命令行,并将其分成三个单词ls -l a directory。 (请注意“目录”中的空格:在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个单词都将被忽略。

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

相关问题