Shell form (CMD npm start) được bọc thành /bin/sh -c "npm start" → shell là PID 1, app là process con. Exec form (CMD ["npm", "start"]) chạy binary trực tiếp → app là PID 1.
Khác biệt quan trọng:
- Tín hiệu:
sh -ckhông forwardSIGTERMcho process con →docker stopkhông tới được app, container bị kill cứng sau timeout. Exec form nhận tín hiệu trực tiếp. - Biến môi trường: shell form có shell expansion (
$PORT,&&, pipe); exec form thì không —["echo", "$HOME"]in ra chuỗi$HOME. - Kết hợp với
ENTRYPOINT: chỉ khi cả hai đều ở exec form,CMDmới trở thành tham số mặc định nối vào sauENTRYPOINT. NếuENTRYPOINTở shell form,CMDbị bỏ qua hoàn toàn.
dockerfile
ENTRYPOINT ["node", "server.js"]
CMD ["--port=3000"] # docker run img --port=8080 overrides just the argumentQuy tắc: luôn dùng exec form cho CMD/ENTRYPOINT.
Cần shell expansion thì gọi shell tường minh và exec để giữ PID 1: ENTRYPOINT ["sh", "-c", "exec node server.js --port=$PORT"].