CMD 與 ENTRYPOINT 的差別與 exec form 的 SIGTERM 陷阱

兩個都是「容器啟動時執行什麼」,差別在能不能被 docker run 後面的參數覆寫

差別

CMDENTRYPOINT
遇到 run 的參數整個取代不會被取代,參數接在後面
定位「預設」指令,可換「固定」的執行檔
CMD ["node", "server.js"]
  docker run my-app           → node server.js
  docker run my-app ls -la    → ls -la(CMD 被整個換掉)
 
ENTRYPOINT ["node"]
  docker run my-app --version → node --version(接在後面)

最實用的是組合技——ENTRYPOINT 定固定執行檔,CMD 提供可覆寫的預設參數:

ENTRYPOINT ["node"]
CMD ["server.js"]
# docker run my-app            → node server.js
# docker run my-app worker.js  → node worker.js

⚠️ 一律用 JSON 陣列(exec form)

寫成字串的 shell form CMD node server.js 會多包一層 /bin/sh -c訊號被 sh 吃掉沒傳給你的程式,於是:

  • docker stop 時程式收不到 SIGTERM、不會優雅關閉
  • Docker 等 10 秒沒反應才 SIGKILL 硬砍(這就是「docker stop 要等 10 秒」的元兇)

解法是 exec form CMD ["node","server.js"],並在程式裡監聽 SIGTERM 做優雅關閉 → 容器設計原則:單一職責、無狀態、設定走環境變數