RUN仅构建时执行并生成镜像层;CMD定义可被docker run命令覆盖的默认启动命令;ENTRYPOINT设定不可替代的主程序,docker run参数作为其追加参数。三者共存时,ENTRYPOINT指定执行程序,CMD提供默认参数,用户参数直接传给ENTRYPOINT。

RUN、CMD 和 ENTRYPOINT 是 Dockerfile 中三个最易混淆的指令,它们作用阶段不同、执行时机不同、覆盖规则也不同。理解它们的关键,在于分清“构建时”还是“运行时”,以及“谁可以被覆盖”。
RUN:只在构建镜像时执行
RUN 指令在 docker build 阶段 运行,用于安装软件、修改文件系统、编译代码等。每条 RUN 会生成一个新的镜像层,结果永久写入镜像中。
- 它不会出现在容器启动过程中,容器运行时完全感知不到 RUN 做了什么
- 常见用法包括:
RUN apt-get update && apt-get install -y curl或RUN pip install flask - 推荐使用 exec 格式(
RUN ["apt-get", "install", "-y", "nginx"])避免 shell 解析歧义
CMD:定义容器默认启动命令,但容易被替换
CMD 是容器 启动时默认执行的命令,但它非常“温柔”——只要你在 docker run 后面加了命令,CMD 就立刻让位。
- 例如 Dockerfile 中写
CMD ["python", "app.py"],运行docker run myimg会启动 app.py;但运行docker run myimg bash,就只会启动 bash,python app.py 被彻底忽略 - 一个 Dockerfile 中可写多个 CMD,但只有最后一个生效
- 适合提供友好默认行为,比如开发镜像默认进 shell,Web 镜像默认启服务
ENTRYPOINT:设定容器的“主程序”,参数可追加不可替代
ENTRYPOINT 定义容器的“核心入口”,它像一个牢不可破的外壳,docker run 后的参数不会替换它,而是作为它的附加参数。
- 比如
ENTRYPOINT ["ls"]+CMD ["-a"],运行docker run myimg -l,最终执行的是ls -l(CMD 的-a被忽略,-l被追加) - 如果只写
ENTRYPOINT ["ls"],没写 CMD,运行docker run myimg -la,就是ls -la - 想彻底换掉 ENTRYPOINT?必须显式加
--entrypoint bash - 典型用途:封装 CLI 工具镜像(如
docker run jq '.name' file.json)、确保始终运行某个启动脚本
三者组合逻辑(重点)
当 CMD 和 ENTRYPOINT 同时存在,且都用 exec 格式时:
- ENTRYPOINT 提供可执行程序(如
["/bin/sh", "-c"]或["myapp"]) - CMD 提供它的默认参数(如
["--port=8080"]) -
docker run myimg --port=9000 --debug→ 实际执行myapp --port=9000 --debug(CMD 被忽略,用户参数直接传给 ENTRYPOINT)
这种设计让镜像既保持行为稳定,又支持灵活传参,是生产环境推荐的用法。

















