层顺序与缓存是什么
Dockerfile 的每条指令形成一个缓存单元:某层失效后,其后续所有层都要重新构建。把变化频率低的指令放前面、易变的源码放后面,是让依赖安装层持续复用、缩短构建时间的核心手法。观察方式:看构建日志里的缓存标记与各步耗时分布,命中率高说明顺序与复制范围划得对。
基本信息
| 适用平台 | Docker 与 BuildKit 等兼容构建器 |
|---|---|
| 原则 | 变化越频繁的指令越靠后 |
| 典型模式 | 先复制锁文件 → 安装依赖 → 再复制源码 → 构建 |
| 观察 | 构建日志里的缓存标记与耗时分布 |
| 常见失误 | 先复制源码再装依赖,任一源码文件改动都会让依赖层重跑 |
| 排查方法 | 借构建输出逐层确认缓存命中与重建原因 |
典型使用场景
- Node 项目:依赖清单先复制,源码后复制,改动代码不触发重装
- 多语言项目:各包管理器清单先行(go.mod、pom.xml、Cargo.toml)
- CI 提速:合并请求频繁构建的场景收益最直接
- 镜像演进:系统包安装放最前,业务迭代不影响它们
- 排查变慢:对比各层耗时,找到反复失效的源头
- 私有依赖场景:在镜像内配置包管理器缓存与代理,避免每次都从上游全量拉取
Node 示例
Node 示例
FROM node:20-slim
WORKDIR /app
COPY package.json package-lock.json ./ # 只复制清单,内容长期稳定
RUN npm ci # 依赖层:代码改动时正常命中缓存
COPY . . # 源码最后进入,变化频率最高
RUN npm run build顺序原则
| 位置 | 放什么 | 原因 |
|---|---|---|
| 最前 | 基础镜像与系统包 | 几乎不变,永远命中 |
| 中间 | 依赖清单与安装 | 随版本更新而变 |
| 最后 | 业务源码与构建 | 每次提交都在变 |
RUN 指令合并要平衡:过度合并会让「某一步变化全部重跑」,按变化频率分界。
忽略文件也是缓存的一部分:测试数据与日志进构建上下文会意外触发失效,维护好忽略清单。