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 的子程序執行,這不會傳遞訊號。這意味著在容器中執行的程式無法檢測到 OS 訊號,例如 SIGTERMSIGKILL,也無法正確響應它們。

示例

❌ 錯誤: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 的子程序執行。

建立包裝指令碼

你可以建立一個入口點指令碼來包裝你的啟動命令,並使用 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"