首页/云/Docker 容器速查/RUN 执行构建命令
镜像与构建107 条

RUN 执行构建命令

构建期执行命令并产出层:shell 形式(默认 /bin/sh -c)便于用管道与变量,exec 形式不经过 shell、更可控。

Docker 容器速查云更新于 2026-10-13

RUN 是什么

RUN 在构建阶段执行命令并把结果固化成一层文件系统。安装依赖、编译代码、调整目录属主都靠它。它有两种书写形式:一种经过命令解释器,便于使用管道与变量;另一种直接调用可执行文件,更可控、不需要解释器参与。

基本信息

作用在构建期执行命令,结果写入镜像层
解释器形式命令字符串交给默认解释器执行,可用管道、通配符与变量展开
直接调用形式写成参数数组,直接调用可执行文件,不经过解释器
层级影响每条 RUN 生成一层,命令越多层越多,体积与缓存粒度都受影响
常见配套配合换行与容错参数,把安装、配置、清理放在同一条里

典型使用场景

  • 安装系统依赖:包管理器更新索引并安装运行所需的库与工具
  • 编译应用:拉取依赖、执行构建、产出可执行文件或前端静态资源
  • 调整文件属性:创建应用目录并设置属主,让运行用户可写
  • 生成配置或密钥:在构建期把默认配置与脚本放进镜像的约定位置
  • 清理构建痕迹:删掉包管理器的索引与临时文件,减小镜像体积

两种形式与常见写法

两种形式与常见写法
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates
RUN set -eux; apt-get update; apt-get install -y --no-install-recommends curl; rm -rf /var/lib/apt/lists/*
RUN ["go", "build", "-o", "/out/app", "."]          # 直接调用,不经解释器
RUN mkdir -p /app && chown 1000:1000 /app             # 建目录并调整属主
RUN npm ci --omit=dev                                  # 按锁文件安装依赖

两种书写形式对照

对比项解释器形式直接调用形式
写法一整条命令字符串参数数组
变量展开会展开,可用环境变量不展开,变量原样传给程序
管道与通配符可用不可用
信号与参数传递多一层解释器,需要留意行为直接到达目标程序,更可控
推荐场景安装依赖、需要串联命令编译与调用固定程序

写 RUN 的实用原则

  • 安装与清理放同一条:上一层删掉的文件仍占体积,分开写等于没清理
  • 变更频率低的操作放前面,让后面的步骤尽量复用缓存
  • 命令开头加容错与打印参数,中间命令失败会立刻中止并留下线索
  • 避免在同一条里塞过多无关命令,局部改动会触发整层重建
  • 不要写入日期、随机数或临时文件,会让该层缓存永远无法命中

常见失败与处理方向

  • 包索引过期导致安装失败:更新索引与安装要同一条执行,或先刷新再装
  • 找不到某个系统库:确认基础镜像与目标发行版的包名差异
  • 编译时缺少工具链:把编译阶段放到带完整工具链的镜像里
  • 权限被拒:以默认用户构建时无法写系统目录,需要时切换身份或调整目录
  • 构建变慢:检查是否每次都在下载依赖,考虑使用缓存挂载或分层策略
每条执行指令都会留下一层历史。合并命令能减少层数,但过度合并会让局部改动触发整层重建,按变更频率分组是更实用的折中。
构建期的缓存命中的判断依据是命令文本与相关文件内容。命令文本里带日期或随机值,会让这一层以及它后面的所有层每次都重新执行。

易错点

  • 安装与清理拆成两条执行指令,被删掉的文件仍留在上一层里,镜像体积并没有变小
  • 把更新索引与安装依赖分开执行,使用了过期的索引,安装到不存在的版本
  • 在构建期写入当前时间或随机内容,导致构建缓存永久失效,构建时间成倍增加
  • 以特权用户执行安装后忘记调整产物属主,运行用户无权限写入,服务启动即失败

数据来源与参考

  • Docker 官方文档:Dockerfile RUN(docs.docker.com)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌