建议使用JSON参数
目录
输出
JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals描述
ENTRYPOINT 和 CMD 指令都支持两种不同的参数语法:
- Shell 形式:
CMD my-cmd start - Exec 形式:
CMD ["my-cmd", "start"]
当您使用 shell 形式时,可执行文件作为 shell 的子进程运行,这不会传递信号。这意味着在容器中运行的程序无法检测到像 SIGTERM 和 SIGKILL 这样的操作系统信号并正确响应它们。
示例
❌ 错误:ENTRYPOINT 命令无法接收操作系统信号。
FROM alpine
ENTRYPOINT my-program start
# entrypoint becomes: /bin/sh -c my-program start为了确保可执行文件能够接收操作系统信号,请对 CMD 和 ENTRYPOINT 使用 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"