登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  软件教程

Docker BuildKit 怎样复用构建缓存

来源:17golang原创

时间:2026-10-14 10:28:10 148浏览 收藏

Docker BuildKit 复用构建缓存有两条不同路径:输入没变时复用已完成的构建层;安装步骤需要重跑时,用 cache mount 保留包管理器下载缓存。要减少重复依赖下载,先把依赖清单复制放在源码复制之前,再把缓存挂载到包管理器实际使用的目录。两者可以一起使用,但不能混为一谈。

官方地址:https://docs.docker.com/build/cache/。下面以已有 package.json、package-lock.json 和 server.js 的 Node.js 项目为例,使用 Docker Desktop 的 Linux 容器构建环境。示例与配图仅供操作说明,没有实际运行或速度测试;不会承诺固定加速倍数。

1. 确认当前构建器,避免每次换一个缓存位置

在 Docker Desktop Dashboard 左侧点击 Builds,查看右上角显示的当前 builder 名称。需要了解构建器时,点击 Builder settings,进入 Settings 的 Builder 页面,确认使用的构建器正在运行。这里先观察,不删除历史、不清理缓存,也不为了教程切换团队共享环境。

Builds 中只有活动、运行中的构建器记录可见;Windows 容器的旧构建器记录不属于这个 BuildKit 视图。如果机器只装命令行工具,也可以使用下面的只读命令查看,后续 UI 步骤则不适用:

# 查看已有构建器及当前选择,不创建、不删除构建器
docker buildx ls

记下后续准备使用的构建器名称。不同 builder 的本地缓存彼此独立,换构建器后的首次构建不能直接拿来证明缓存配置无效。界面中能看到目标 builder,命令行也确认选择相同,才进入下一步。

Docker Desktop Builds入口与当前构建器位置说明
图一:Builds 入口与当前 builder 的原创操作示意图,不是真实截图。

2. 给依赖安装步骤挂载下载缓存

在项目编辑器的资源管理器中打开项目根目录 Dockerfile;没有时通过 New File 新建。将安装依赖步骤放到 COPY 源码之前。下面是独立示例,基础镜像版本要按项目支持范围选择;生产发布还应按团队策略固定镜像摘要。

# syntax=docker/dockerfile:1
# 选择项目支持的 Node.js 版本;此处作为演示基础镜像
FROM node:22-bookworm-slim
WORKDIR /srv/cache-demo
# 先复制依赖描述,普通源码变化不会直接影响这一步
COPY package.json package-lock.json ./
# 缓存 npm 下载内容;id 区分用途,locked 选择保守的串行访问
RUN --mount=type=cache,id=cache-demo-npm,target=/root/.npm,sharing=locked npm ci
# 安装产物留在 /srv/cache-demo/node_modules,而不是缓存挂载目录
COPY . .
# 使用项目实际入口,不在本文运行服务
CMD ["node", "server.js"]

这个镜像安装阶段以 root 用户运行,所以使用 /root/.npm。若基础镜像或 USER 指令改成其他用户,应按该用户的实际 npm cache 位置与写入权限调整 target;不能见到“npm 缓存”就固定抄 root 路径。

id 是缓存命名空间,不是保密或权限边界。sharing=locked 让共用该缓存的并发写入等待,适合保守起步,但可能降低并行吞吐;包管理器是否需要独占访问,要按其自身约束决定。

再打开根目录 .dockerignore,排除不应进入上下文的本地文件。不要将锁文件排除,否则 npm ci 缺少输入。

# 防止本机安装产物覆盖容器里安装的依赖
node_modules
# 不发送仓库历史和本地环境文件;项目若确需非敏感配置,应单独评估
.git
.env
.env.*
# 忽略调试日志,避免无关变化扩大上下文
npm-debug.log*

保存 Dockerfile 与 .dockerignore 后,检查编辑器的文件标签没有未保存标记,并确认 COPY 清单位于安装步骤之前,安装步骤位于 COPY . . 之前。这是配置完成的可见状态,不代表已经命中缓存。

Dockerfile依赖清单与npm缓存挂载字段的编辑说明
图二:Dockerfile 缓存挂载与上下文排除的原创操作示意图。

3. 构建后区分层命中和下载缓存复用

读者可在项目根目录执行下面的构建命令,它会产生本地镜像;请使用自己的演示项目和已确认的构建器。本文不启动命令、不生成实测日志:

# 用当前构建器构建,输出详细日志并把结果加载到本地镜像库
docker buildx build --progress=plain --load -t cache-demo:local .

构建结束后,在 Docker Desktop → Builds → Build history 选择对应记录,打开 Info 查看 Cache usage,再打开 Logs,使用 List view 展开依赖安装步骤;需要完整文本时切换 Plain-text view。记录应显示成功,失败时先看 Error 标签对应的指令,不把错误归为缓存失效。

有两种不同观察:不改输入重复构建,依赖安装层可能显示 CACHED,意味着没有重新执行 npm ci;改了锁文件使安装步骤重新执行,下载缓存才有机会帮助复用已有包。第二种不能靠 CACHED 标签证明,也不能只凭总耗时变短推断没有下载。要结合包管理器日志、网络请求与实际输入判断,不写死日志格式或命中比例。

一个低风险对照是先只改 server.js 的无功能影响注释,再构建,观察依赖安装是否仍复用;另一组在独立分支中正常更新依赖及锁文件,再观察安装步骤。不要手工破坏 package-lock.json 只为强制重跑,也不要在生产构建器上删除缓存做对照。

Build history记录与Info和Logs观察入口的原创说明
图三:构建记录检查入口的结果示意图,未展示虚构耗时或命中率。

CI 重建机器时,还要考虑另一种缓存

本地 builder 的缓存挂载不是镜像内容,也不应成为正确构建的必需输入。缓存可能被垃圾回收,构建仍须能从依赖清单重新获取内容。不要把源码、唯一产物或凭据保存在缓存挂载里;私有仓库认证需要独立的 secret 机制。

临时 CI 机器每次创建新的 builder,原来的本地缓存自然不在。外部缓存通过 cache-to 与 cache-from 导出和导入构建缓存,但不能因此假设普通缓存挂载目录也自动跨机器恢复。后端类型和缓存挂载持久化方式要单独确认,尤其不要把构建层缓存与 npm 下载缓存用同一个“缓存成功”标签带过。

情况先看哪里
源码改动导致依赖重装COPY 顺序、上下文是否混入无关文件
安装步骤总是下载实际 cache 路径、用户权限、builder 是否变化
本地有效,CI 首次无效builder 生命周期与外部缓存策略
缓存目录为空就构建失败是否错误依赖缓存中的唯一文件

最后确认三件事:构建能在空缓存时成功,固定 builder 的重复构建能按输入复用,安装层重跑时缓存挂载使用正确路径。优化的结果应由自己的构建记录描述,不用本文说明图替代数据。

常见问题

cache mount 会把 npm 缓存带进最终镜像吗?挂载内容不作为该指令的普通镜像产物保存;安装在挂载之外的 node_modules 才随镜像层保留。

层缓存命中后还会执行 npm ci 吗?命中并复用该步骤时不会重新执行,这与执行安装时使用下载缓存是两回事。

清缓存是否是排障第一步?不是。先确认输入、路径和 builder,清理会影响其他构建并破坏观察条件。

参考:https://docs.docker.com/build/cache/optimize/;Dockerfile 字段:https://docs.docker.com/reference/dockerfile/;界面入口:https://docs.docker.com/desktop/use-desktop/builds/。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>