JSONArgsRecommended

输出

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

描述

ENTRYPOINTCMD 指令都支持两种不同的参数语法

  • Shell 格式: CMD my-cmd start
  • Exec 格式: CMD ["my-cmd", "start"]

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

示例

❌ 差: ENTRYPOINT 命令无法接收 OS 信号。

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

为了确保可执行文件可以接收 OS 信号,请对 CMDENTRYPOINT 使用 exec 格式,这样可以使可执行文件作为容器中的主进程 (PID 1) 运行,避免了 shell 父进程。

✅ 好: 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 命令执行该脚本。

✅ 好: 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

您可以使用 SHELL Dockerfile 指令来显式指定要使用的 shell。这将抑制警告,因为设置 SHELL 指令表明使用 shell 格式是经过深思熟虑的决定。

✅ 好: shell 已显式定义。

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