RUN指令排布核心是“稳定优先、合并执行、避免污染”:换源与通用工具安装前置;依赖清单单独COPY后立即安装;每条RUN须用&&链式合并并清理临时文件,严禁含时间戳、未声明变量或命令文本差异等缓存杀手。

RUN 指令的排布核心是“稳定优先、合并执行、避免污染”,不是随便写几条命令就行,而是要让每一层都尽可能复用——尤其得避开那些看似无害、实则必然破坏缓存的操作。
把系统级配置和依赖安装放在最前面
基础环境越早固定,后续越容易命中缓存。比如换源、装系统工具、设时区这类操作,几乎不随代码变更,应集中写在靠前位置:
- 先 RUN 换国内镜像源(如 apt 或 apk),再 update + install,用 && 链式执行,避免中间层残留临时文件
- 安装 build-essential、curl、git 等通用构建工具,不绑定具体业务逻辑
- 不要在同一个 RUN 里混入“换源”和“装业务包”,否则源一变或包一更新,整层缓存就废了
语言依赖必须单独分层、提前安装
Go、Python、Node.js 的依赖下载行为高度可缓存,前提是把声明文件(go.mod、requirements.txt、package.json)的 COPY 和安装命令严格拆开:
- COPY go.mod go.sum . → RUN go mod download
- COPY requirements.txt . → RUN pip install --no-cache-dir -r requirements.txt
- COPY package.json package-lock.json . → RUN npm ci --no-audit
- 关键点:只复制依赖清单,不复制源码;安装命令不带动态参数(如版本号硬编码或环境变量未声明)
RUN 命令本身要合并、精简、清理
每多一个 RUN 就多一层,也多一次缓存判断机会。冗余的 RUN 不仅拖慢构建,还容易因中间状态干扰缓存:
- apt-get install 后立刻加 apt-get clean 和 rm -rf /var/lib/apt/lists/*,否则残留包列表会让下一层缓存失效
- 避免写成多个独立 RUN:RUN apt-get update,RUN apt-get install foo,RUN rm -rf ... —— 这三行会生成三层,第二层永远无法跳过
- 推荐写法:RUN apt-get update && apt-get install -y foo bar && apt-get clean && rm -rf /var/lib/apt/lists/*
避开 RUN 中的缓存杀手
有些 RUN 写法看起来合理,实际每次构建都强制重建:
- 含时间戳或随机值:RUN date > build.time、RUN echo $RANDOM,这类指令永远不命中缓存
- 引用未声明的构建参数:RUN echo $VERSION,但没写 ARG VERSION,Docker 默认当空字符串处理,稍后参数值变化就导致缓存跳过
- 命令文本微小差异:RUN apt-get update && apt-get install foo 和 RUN apt-get update \&\& apt-get install foo(换行+转义),Docker 视为不同指令,缓存不共享


















