cmd的exec格式(json数组)是推荐做法,因其使程序成为pid 1进程,可直接接收sigterm等系统信号,避免shell中间层导致的信号丢失和优雅退出失败。
直接用 cmd ["可执行程序", "参数"] 这种 exec 格式就能指定默认可执行程序,这是最稳妥、推荐的做法。
为什么必须用数组格式(exec 形式)
因为只有这种写法能让程序成为容器的 1 号进程(PID 1),从而正确接收系统信号(比如 docker stop 发出的 SIGTERM)。如果写成 CMD python app.py(shell 形式),实际启动的是 /bin/sh -c "python app.py",sh 成了 PID 1,而 python 是它的子进程——这时发 stop 命令,sh 可能不转发信号,导致容器无法优雅退出。
CMD 的三种写法对比
-
✅ 推荐:exec 格式(JSON 数组)
CMD ["node", "server.js"]
直接执行 node,无 shell 中间层,信号通、进程干净、适合生产环境 -
⚠️ 不推荐:shell 格式
CMD node server.js
隐式调用 /bin/sh,主进程是 sh,容易引发信号丢失和进程僵死 -
? 特殊用法:为 ENTRYPOINT 提供默认参数
当 Dockerfile 同时有 ENTRYPOINT 和 CMD 时,CMD 内容会作为参数传给 ENTRYPOINT。
例如:ENTRYPOINT ["nginx"]+CMD ["-g", "daemon off;"]→ 启动时运行nginx -g "daemon off;"
几个关键注意事项
- 一个 Dockerfile 中可以写多个 CMD,但只有最后一个生效
- CMD 定义的是“默认命令”,只要在
docker run末尾加了新命令,就会完全替换掉 CMD,比如:docker run my-image bash→ 不执行 CMD,而是直接运行 bash - 如果想让某个程序强制作为入口、不可被轻易替换,应该用 ENTRYPOINT;CMD 更适合做“可选默认行为”
常见错误示例与修正
-
错:
CMD npm start
对:CMD ["npm", "start"]或更优:CMD ["node", "app.js"](绕过 npm 启动层,减少进程嵌套) -
错:
CMD ./start.sh(脚本没加执行权限或路径不对)
对:先RUN chmod +x ./start.sh,再CMD ["./start.sh"] -
错:CMD 放在 FROM 之前,或写在注释行里
对:CMD 必须是有效的指令行,且通常放在 Dockerfile 尾部附近











