直接观察构建日志中每步末尾是否出现“Using cache”即可判断缓存是否命中;若某层缺失该提示且后续全重做,说明缓存在此处失效,需结合docker image history、buildx du和dive进一步定位根因。

构建日志里找 Using cache 最直接
每次 docker build 执行时,控制台输出的每一步都会明确标注是否复用了缓存。只要看到某行末尾出现 Using cache,就说明该层命中了本地缓存。
常见错误现象:加了 --no-cache 却仍有 Using cache —— 这通常是因为 --no-cache 只跳过复用,不清理底层缓存;而真正被复用的是基础镜像层(FROM),它不受 --no-cache 影响,除非同时加 --pull 强制拉取新镜像。
实操建议:
- 观察每步输出,重点关注
RUN、COPY、ADD行末是否带Using cache - 若某层没出现该字样,且后续所有层都重新执行,说明缓存在此处断点失效
- 避免仅依赖日志判断“整体是否缓存”,因为哪怕只有一层未命中,后面全重做
docker image history 查看每一层来源
docker image history 能列出镜像各层的创建命令、大小和时间戳,是验证缓存是否真实生效的第二道依据。
使用场景:构建完一个镜像后,想确认某条 COPY go.mod 是否真的复用了旧层,而不是重新下载依赖。
关键识别点:
- 如果某层
CreatedBy显示/bin/sh -c #(nop) COPY ...且Created时间明显早于本次构建时间 → 大概率是缓存复用 - 若某层
Size为 0B,但CreatedBy是RUN go mod download→ 很可能只是复用了空执行结果,不代表依赖没更新 - 注意:
docker image history不显示 BuildKit 的元数据,启用DOCKER_BUILDKIT=1后建议配合docker buildx du辅助分析
BuildKit 开启后用 docker buildx du 看缓存占用详情
默认 Docker Desktop(2024.12+)已启用 BuildKit,它的缓存不走传统 docker system prune 路径,而是存在独立构建器中。此时 docker builder du -v 才能看到真实缓存体积和各阶段分布。
为什么容易忽略:很多人用 docker system df 看到“Build Cache”只有几百 MB,却不知道实际 docker builder du 显示几十 GB —— 因为前者只统计被引用的缓存,后者才包含所有中间产物。
实操建议:
- 运行
docker builder du -v查看缓存总大小、各构建器下的缓存条目数 - 结合
docker builder prune --filter until=24h清理闲置缓存,比盲目--all更安全 - 若发现某项目反复构建后缓存持续增长,大概率是
.dockerignore漏掉了node_modules或dist目录,导致每次 COPY 都生成新哈希层
dive 工具逐层 inspect 缓存内容差异
当怀疑某层“看似命中缓存,实则内容已变”(比如 COPY . . 命中了缓存,但源码其实改了),dive 是唯一能打开镜像、对比文件树哈希的工具。
典型问题:本地构建测试通过,CI 上却失败 —— 很可能是开发机上某层缓存了旧版二进制,而 CI 环境干净,触发了真实构建,暴露出编译错误。
安装与使用:
- macOS:
brew install dive;Windows / Linux:从 GitHub releases 下载二进制 - 运行
dive,进入交互界面后按Tab切换图层视图,用方向键逐层查看文件变动 - 重点检查
COPY或ADD层的文件哈希是否与当前工作目录一致(需配合sha256sum手动校验)
缓存机制本身不记录“为什么这一层没命中”,只记录“有没有命中”。真正定位失效根源,得靠日志 + history + buildx du + dive 四者交叉验证——尤其当项目引入多阶段构建或远程缓存时,单看一行 Using cache 容易误判。











