首页/云/Docker 容器速查/层缓存原理与指令排序
镜像与构建107 条

层缓存原理与指令排序

每条指令按「文本 + 相关文件内容 + 父层」计算缓存键:命中就跳过执行;把低频变更放前面、高频变更放后面是加速构建的核心。

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

层缓存是什么

构建时每条指令都会计算一个缓存键:由指令文本、相关文件内容与上一层的结果共同决定。键相同就跳过执行,直接复用已有结果。理解这一点就能明白两件事:为什么改一行代码可能触发长时间重装依赖,以及为什么某些写法会让缓存永久失效。

基本信息

缓存键组成指令文本、复制文件的内容、上一层的哈希
命中表现构建日志里标注为已缓存,该步不重新执行
排序原则变更频率低的放前面,变更频繁的放后面
相关开关禁用缓存、强制拉取新基础镜像、指定外部缓存来源
默认引擎新版本引擎在并行与缓存能力上更强

典型使用场景

  • 加速日常构建:依赖安装层长期复用,只重建源码相关的那几层
  • 流水线提速:在构建机之间传递缓存,减少重复下载与编译
  • 快速验证改动:大部分层命中缓存时,能快速得到验证结果
  • 定位构建变慢原因:通过缓存命中情况判断哪个步骤被反复执行
  • 保证发布正确性:依赖更新后做一次不用缓存的构建,排除缓存陈旧的影响

排序正误对照

排序正误对照
# 推荐:依赖清单先复制,源码变化不影响依赖层
COPY package.json package-lock.json ./
RUN npm ci
COPY . .

# 反例:任意源码改动都会触发依赖重装
COPY . .
RUN npm ci

# 依赖更新后做一次全量验证构建
docker build --no-cache --pull -t app/web:1.0 .

什么会让缓存失效

因素影响范围处理方式
改动指令文本该层与之后所有层尽量把频繁改动的指令放后面
复制的文件内容变化该层与之后所有层缩小复制范围,按文件分组复制
上一层失效连锁失效直到重建减少层数或重新组织指令顺序
写入时间或随机值该层永久无法命中去掉这类内容,或用变量在运行时注入
基础镜像更新按需拉取时可能触发重建锁定版本,需要更新时集中处理

实际优化手法

  • 把依赖描述文件单独复制并安装依赖,源码复制放在依赖安装之后
  • 把系统依赖安装与清理合并成一条指令,既减层也提速
  • 把不常改动的配置与脚本放前面,源码与产物放后面
  • 外部缓存来源在流水线里配置好,多台机器共享缓存收益最大
  • 出现可疑结果时用禁用缓存的方式做一次对照构建
缓存命中不代表正确。缓存键覆盖的是输入内容,如果依赖在远端被覆盖而内容判断没变,可能一直用到旧的结果,定期做一次全量验证构建更稳妥。
构建日志里的命中标注是判断问题的直接依据:看哪一步开始不再命中,就知道改动的实际影响范围。

易错点

  • 在构建指令里写入日期或随机值,该层每次都不命中,后面所有层跟着重建,构建时间成倍增长
  • 把源码与依赖一起复制再安装依赖,改一行代码就重装依赖
  • 长期依赖缓存不做全量验证,发布时才暴露问题
  • 以为缓存命中就等于结果正确,忽略了远端依赖内容可能被覆盖的情况

数据来源与参考

  • Docker 官方文档:Build cache(docs.docker.com/build/cache)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌