JSONArgs推荐

输出

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

描述

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

  • Shell 形式:CMD my-cmd start
  • 执行形式:CMD ["my-cmd", "start"]

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

示例

❌ 错误:ENTRYPOINT 命令无法接收操作系统信号。

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

为了确保可执行文件能够接收操作系统信号,请使用CMDENTRYPOINT的exec形式,这允许您在容器中将可执行文件作为主进程(PID 1)运行,从而避免使用shell父进程。

✅ 好:ENTRYPOINT 接收操作系统信号。

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

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

解决方法

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

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

创建一个包装脚本

你可以创建一个入口点脚本,该脚本封装了你的启动命令,并使用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"