Dockerfile 中 RUN 和 CMD 有什么区别?

RUN 在构建镜像时执行(装包、建目录,结果固化进镜像层),CMD 指定容器启动时的默认命令(可被 docker run 覆盖)。构建期用 RUN,运行期用 CMD。

最佳实践
Dockerfile 中 RUN 和 CMD 有什么区别?封面

一句话区别:RUN 在构建镜像时执行,命令结果(装的包、建的目录)作为新的镜像层永久固化;CMD 在容器启动时才生效,指定默认运行的命令,且可被 docker run 后面跟的参数整个覆盖。时机不同:RUN 属于 build,CMD 属于 run。

RUN:构建期执行

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y curl
RUN mkdir -p /app/logs

构建所选阶段中未命中缓存的RUN会执行,缓存命中或未使用阶段可能不执行;文件系统结果可存为层,进程状态不会保留。典型用途:装依赖、写配置、建目录、赋权限。

优化要点:多个关联命令用 && 合并成一条 RUN,减少层数;apt-get 装完顺手 rm -rf /var/lib/apt/lists/* 清理缓存,镜像更小。

CMD:运行期默认命令

CMD ["python", "app.py"]

docker run myimg 时执行;docker run myimg python debug.py 则 CMD 被替换。一个 Dockerfile 里写多条 CMD,只有最后一条生效。

对照记忆

RUN CMD
执行时机 docker build docker run(容器启动)
生效次数 按阶段和缓存决定是否执行 镜像配置中最后一个默认CMD
结果去向 文件系统结果可进入层 命令保存为镜像元数据,启动时使用
能否被覆盖 不能 run 参数整体覆盖

组合示例

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN python -m pip install --no-cache-dir -r requirements.txt
COPY . /app
# requirements.txt需包含经验证的Flask/Gunicorn版本,app.py需暴露app对象
CMD ["gunicorn", "-w", "4", "app:app"]   # 启动期默认命令

常见问题(FAQ)

Q:CMD 用 shell 形式还是 exec 形式?
A:推荐 exec 数组形式(CMD ["python","app.py"]),可避免额外shell层;最终PID1和SIGTERM处理还取决于ENTRYPOINT/init与应用,不能保证自动优雅停机;shell 形式会裹一层 sh,信号传递有问题。

Q:ENTRYPOINT 和 CMD 又是什么关系?
A:ENTRYPOINT 定主程序、CMD 提供默认参数,详见本系列《Dockerfile 中 CMD 和 ENTRYPOINT 的区别》。

Q:RUN 执行失败会怎样?
A:构建立即中止报错;排查时可把复杂 RUN 拆小定位,或用 docker build --progress=plain 看完整输出。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台