JSONArgs推荐

输出

JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals

描述

ENTRYPOINTCMDinstructions 都支持 参数:

  • 壳型:CMD my-cmd start
  • 执行表单:CMD ["my-cmd", "start"]

当您使用 shell 形式时,可执行文件将作为 shell 的子进程运行, 它不会传递信号。这意味着在 容器无法检测到 OS 信号,例如SIGTERMSIGKILL并响应 他们正确地。

例子

❌ 差:的ENTRYPOINTcommand 未接收 OS 信号。

FROM alpine
ENTRYPOINT my-program start
# entrypoint becomes: /bin/sh -c my-program start

要确保可执行文件可以接收作系统信号,请使用 exec 表单CMDENTRYPOINT,它允许您将可执行文件作为主进程 (PID 1),避免 shell 父进程。

✅ Good: 的ENTRYPOINT接收 OS 信号。

FROM alpine
ENTRYPOINT ["my-program", "start"]
# entrypoint becomes: my-program start

请注意,以 PID 1 运行程序意味着程序现在具有特殊的 与 Linux 中的 PID 1 相关的职责和行为,例如收割 子进程。

解决方法

可能在某些情况下,您希望在 shell 下运行容器。 使用 exec 表单时,shell 功能(如变量扩展、管道 (|) 和命令链接 (,&&||、 ) 不可用。要使用这样的 功能,您需要使用 shell 形式。;

以下是您可以实现这一目标的一些方法。请注意,这仍然意味着 可执行文件作为 shell 的子进程运行。

创建包装脚本

您可以创建一个 entrypoint 脚本来包装您的启动命令,并且 使用 JSON 格式执行该脚本ENTRYPOINT命令。

✅ Good: 的ENTRYPOINT使用 JSON 格式。

FROM alpine
RUN apk add bash
COPY --chmod=755 <<EOT /entrypoint.sh
#!/usr/bin/env bash
set -e
my-background-process &
my-program start
EOT
ENTRYPOINT ["/entrypoint.sh"]

显式指定 shell

您可以使用SHELLDockerfile 指令显式指定要使用的 shell。这将抑制 自将SHELL指令指示使用 shell 形式是一个有意识的决定。

✅ Good:shell 已显式定义。

FROM alpine
RUN apk add bash
SHELL ["/bin/bash", "-c"]
ENTRYPOINT echo "hello world"