JSONArgsRecommended
目錄
輸出
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 的子程序執行,這不會傳遞訊號。這意味著在容器中執行的程式無法檢測到 OS 訊號,例如 SIGTERM
和 SIGKILL
,也無法正確響應它們。
示例
❌ 錯誤:ENTRYPOINT
命令無法接收 OS 訊號。
FROM alpine
ENTRYPOINT my-program start
# entrypoint becomes: /bin/sh -c my-program start
為確保可執行檔案能夠接收 OS 訊號,請對 CMD
和 ENTRYPOINT
使用 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"