ENTRYPOINT定义主程序,CMD提供默认参数;必须用exec形式(数组写法),ENTRYPOINT调用固定可执行文件或入口脚本并用exec "$@"转发参数,CMD仅作默认补充,二者配合实现确定入口与灵活传参。

在 Dockerfile 中设置启动命令,核心是搞清 CMD 和 ENTRYPOINT 的分工:ENTRYPOINT 定义“主程序”,CMD 提供“默认参数”。两者配合才能既保证容器有确定入口,又支持灵活传参。
ENTRYPOINT 写什么?固定执行的可执行文件或脚本
ENTRYPOINT 应该是你不希望被意外绕过的主命令。比如 Web 服务必须启动 nginx,Python 应用必须运行某个入口脚本。
- 必须用 exec 形式(数组写法),例如:ENTRYPOINT ["nginx"] 或 ENTRYPOINT ["python3", "/app/main.py"]
- 避免 shell 形式(如 ENTRYPOINT nginx -g "daemon off;"),否则无法正确接收 CMD 或 run 时传入的参数
- 如果需要复杂逻辑(如环境检查、配置生成),推荐写一个入口脚本,再用 ENTRYPOINT 调用它,最后用 exec "$@" 转发参数
CMD 写什么?给 ENTRYPOINT 补充默认参数
CMD 是 ENTRYPOINT 的“默认参数列表”,只在没额外指定命令时生效。它本身不能单独运行,除非镜像没设 ENTRYPOINT。
- 同样推荐 exec 形式,例如:CMD ["-g", "daemon off;"] 或 CMD ["--mode", "prod"]
- 如果 docker run 后面跟了新命令(如 docker run myimg sh),CMD 会被完全忽略,新命令变成 ENTRYPOINT 的参数
- 多个 CMD 指令只认最后一个;不要混用 shell 和 exec 形式,否则参数传递可能出错
组合使用示例:清晰又可控
典型搭配能兼顾默认行为和调试能力:
- Dockerfile 片段:
ENTRYPOINT ["python3", "/app/start.py"]
CMD ["--port", "8000"] - 效果:
• 直接 docker run myapp → 执行 python3 /app/start.py --port 8000
• 加参数 docker run myapp --port 9000 --debug → 执行 python3 /app/start.py --port 9000 --debug
• 覆盖入口 docker run --entrypoint sh myapp → 进入 shell 调试
常见误区提醒
几个容易踩坑的地方:
- ENTRYPOINT 和 CMD 都用 shell 形式(带 $ 变量或管道)→ 参数无法透传,建议全用 exec 形式
- 只写 CMD 不写 ENTRYPOINT → 容器启动命令容易被 run 时的参数意外覆盖,缺乏主程序约束
- ENTRYPOINT 写成完整命令加参数(如 ENTRYPOINT ["sh", "-c", "nginx -g 'daemon off;'"])→ 失去参数可替换性,失去灵活性
- 想让容器启动后一直运行却忘了前台模式 → 确保主进程不后台化(如 nginx 要加 -g "daemon off;",Python 要避免 &)


















