Dockerfile 中 CMD 和 ENTRYPOINT 有什么区别?
ENTRYPOINT 定义容器的固定主程序,CMD 提供默认参数(可被 docker run 覆盖);二者常搭配使用:ENTRYPOINT 定命令、CMD 定默认参数。本文用实例讲透。
一句话区别:ENTRYPOINT 指定容器启动时执行的主程序**(不易被覆盖),CMD 指定默认命令或默认参数——docker run 时追加的参数会整个替换掉 CMD,但只会作为参数追加到 ENTRYPOINT 后面。两者组合的标准模式:ENTRYPOINT 定可执行文件,CMD 定它的默认参数。**
先理解默认机制
FROM ubuntu
CMD sleep 10
容器启动时实际执行的是 /bin/sh -c "sleep 10"——因为基础镜像默认 ENTRYPOINT 是 shell,CMD 只是传进去的参数。docker run myimg sleep 20 会整体覆盖 CMD,变成 sleep 20。
ENTRYPOINT 的行为
FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]
docker run myimg→ 执行sleep 10(ENTRYPOINT + CMD 默认参数)docker run myimg 30→ 执行sleep 30(CMD 被替换,ENTRYPOINT 不变)
对比表
| 场景 | CMD | ENTRYPOINT |
|---|---|---|
docker run img 新命令 的效果 |
新命令替换 CMD | 新命令作为 ENTRYPOINT 的参数 |
| 用途 | 提供默认值 | 固定容器用途 |
| 覆盖方式 | 命令行直接覆盖 | 需 --entrypoint 显式覆盖 |
| 推荐形式 | exec 数组形式 | exec 数组形式 |
实用模式
模式一:可执行文件 + 默认参数(上文 sleep 例子),适合工具型镜像。
模式二:包装脚本
ENTRYPOINT ["/entrypoint.sh"] # 脚本里做初始化,最后 exec "$@"
CMD ["nginx", "-g", "daemon off;"]
官方 nginx/mysql 镜像都是这个套路:entrypoint 脚本处理环境变量、初始化数据目录,最后 exec "$@" 把 CMD 跑起来。
只用 CMD:适合"容器即应用"的简单场景,用户 run 时传什么就执行什么。
常见问题(FAQ)
Q:两者都用 shell 形式(不带方括号)有什么问题?
A:shell 形式会以 /bin/sh -c 包裹,主进程 PID 不是 1,接收不到 docker stop 的 SIGTERM,优雅停机失效。生产镜像一律用 exec 数组形式。
Q:想进容器调试而不启动主程序?
A:docker run -it --entrypoint /bin/sh myimg,显式覆盖 ENTRYPOINT。
Q:K8s 里对应哪个字段?
A:command 覆盖 ENTRYPOINT,args 覆盖 CMD。