如何利用 BuildKit 的 `--mount=type=cache` 加速 apt/yum 安装
解读
国内镜像构建普遍面临两大痛点:
- 每次
docker build都会重新下载软件包,外网带宽不稳定导致 CI 超时; - 多阶段构建或并行 Job 重复拉取相同依赖,浪费时间和存储。
BuildKit 的--mount=type=cache可以把宿主机目录绑定到构建容器内部,实现跨构建、跨阶段共享缓存,从而把 apt/yum 的元数据和软件包持久化,显著缩短构建耗时。面试官想确认你是否:
- 知道 BuildKit 在国内环境下的启用方式;
- 能正确写出 Dockerfile 语法并解释缓存目录映射原理;
- 理解权限、并发安全、缓存失效策略等生产细节。
知识点
- 启用 BuildKit:
- 环境变量
DOCKER_BUILDKIT=1或 daemon.json"features": { "buildkit": true }; - 国内 CI(Jenkins、GitLab Runner、阿里云 ACR、腾讯云 TCR)均默认开启,无需 root 改 daemon。
- 环境变量
- 缓存挂载语法:
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked ...type=cache:标识缓存挂载;target:容器内路径,需与 apt/yum 缓存路径一致;sharing=locked:防止并行构建写冲突;id:可选,显式命名缓存,便于多镜像共享;mode/uid/gid:保证与安装用户一致,避免权限拒绝。
- apt 缓存路径:
/var/cache/apt/archives存放 deb 包,/var/lib/apt/lists存放索引;两者均需挂载。 - yum/dnf 缓存路径:
/var/cache/yum(CentOS 7)或/var/cache/dnf(CentOS 8+),同时保留/etc/yum.repos.d不变即可。 - 缓存失效策略:
- BuildKit 默认永不过期,需手动
docker builder prune --filter type=cache或设置--mount=type=cache,id=xxx,timeout=24h; - 国内云厂商的远程构建机每日清盘,可忽略手动清理。
- BuildKit 默认永不过期,需手动
- 与多阶段构建结合:
在 builder 阶段挂载缓存,最终阶段仅拷贝产物,缓存层不会进入镜像,既提速又保持镜像最小化。
答案
以国内 Debian 源为例,给出完整 Dockerfile 与构建命令:
# syntax=docker/dockerfile:1.4 # 必须放在第一行,启用 1.4 语法
FROM debian:11-slim AS builder
ARG DEBIAN_FRONTEND=noninteractive
RUN rm -f /etc/apt/apt.conf.d/docker-clean && \
echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/99-no-languages
# 挂载缓存目录并锁定,防止并行冲突
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-cache \
--mount=type=cache,target=/var/lib/apt/lists,sharing=locked,id=apt-lists \
apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
python3-dev \
python3-pip && \
apt-get clean
# 多阶段拷贝产物,缓存层不会带到最终镜像
FROM debian:11-slim
COPY --from=builder /usr/local/lib/python3.9/dist-packages /usr/local/lib/python3.9/dist-packages
CMD ["python3"]
构建命令:
export DOCKER_BUILDKIT=1
docker build -t myapp:1.0 .
效果:
- 首次构建耗时 120 s,后续仅更新索引,耗时降至 8 s;
- 缓存目录位于宿主机
/var/lib/docker/buildkit/cache,镜像层不含缓存,体积不变; - 同一台宿主机上并行 Job 通过
sharing=locked排队写,避免损坏。
对于 CentOS 7,只需替换路径:
RUN --mount=type=cache,target=/var/cache/yum,sharing=locked,id=yum-cache \
yum install -y gcc make ...
拓展思考
- 国内源加速与缓存结合:
在apt update前把/etc/apt/sources.list换成清华、阿里、中科大源,再挂载缓存,可进一步节省索引下载时间;注意源地址变化会导致缓存失效,需统一在基础镜像层完成换源。 - CI 缓存跨节点共享:
自建 GitLab Runner 可配置[[runners.docker]] helper_image = "docker/buildkit:latest",并把/var/lib/docker/buildkit挂载到 NFS 或 OSS,实现多节点共享同一份缓存,但需加id命名空间防止冲突。 - 安全加固:
- 缓存目录默认 755,若公司安全基线要求 700,可在挂载后加
RUN chmod 700 /var/cache/apt; - 对公网构建机,建议给缓存目录加
node.unique后缀,防止不同租户横向读取缓存包。
- 缓存目录默认 755,若公司安全基线要求 700,可在挂载后加
- 与 BuildKit 外置化缓存(gha、s3)对比:
国内云原生场景下,外置化缓存需额外开放公网出口,直接使用本地 type=cache 性价比最高;只有跨地域构建才考虑 gha/s3。 - 清理策略:
在 nightly pipeline 里加docker builder prune --filter type=cache --keep-storage 5GB,防止宿主机 inode 耗尽;阿里 ACR 企业版已内置自动清理,无需干预。