运行 bash -c 和 运行 的开放形式的区别

Difference between RUN bash -c and open form of RUN

一些 Dockerfile 有

RUN bash -c "apt-get update -qq && ... \"

而其他人则没有引号,例如

RUN apt-get update -qq && ... \

这些变体之间有什么区别?其中一个比另一个更受欢迎吗?

您应该只写 RUN apt-get update ... 而无需手动插入 sh -c 包装器。

RUNCMDENTRYPOINT 指令都共享相同的语法。最好为 ENTRYPOINT 记录,但所有三个命令的工作方式相同。有两种方法可以为它们编写命令:您可以提供一组特定的命令字作为 JSON 数组 (exec form), or you can write a string and Docker will automatically wrap it sh -c (shell form)。例如:

# Create a directory with a space in its name
RUN mkdir "a directory"

# JSON-array form: each array element is a shell word
RUN ["ls", "-ld", "a directory"]

# String form: Docker provides a shell, so these two are equivalent
RUN ls -ld 'a directory'
RUN ["/bin/sh", "-c", "ls -ld 'a directory'"]

这使您的第一种形式变得多余:如果您 RUN bash -c '...',它是一个字符串,Docker 会自动将其包装在 sh -c 中。这样你就生效了

# RUN bash -c '...'
RUN ["/bin/sh", "-c", "bash -c '...'"]

GNU bash 有许多不是 POSIX-standard 语法的扩展,并且可能 运行 遇到这些问题,特别是在 Alpine-based 图像上 /bin/sh 是 BusyBox 工具集中的最小值 shell。我可以将此视为使用 bash 而不是默认 shell 将 shell 命令强制为 运行 的尝试。对于 Docker 文件中出现的大多数内容,它们通常不会复杂到无法用标准语法轻松重写的程度。

# Needs bash for the non-standard `source` syntax
RUN bash -c 'source ./venv/bin/activate && pip list'

# But you can use the standard `.` instead
RUN . ./venv/bin/activate && pip list

如果你必须有bash解释RUN行,那么我建议使用SHELL指令来改变使用的命令解释裸字符串。

Style-wise,我偶尔也会看到 JSON-array 以显式 CMD ["/bin/sh", "-c", "..."] 开头的语法。没有理由把它写出来;使用字符串形式更短,同样清晰。