DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Docker 构建已挂载 APT 缓存,deb 包仍反复下载

定位基础镜像的 docker-clean 清理钩子,在构建阶段调整 APT 缓存策略,并区分缓存挂载、构建层命中和临时构建器。

Dockerfile 已给 /var/cache/apt 配置 BuildKit 缓存挂载,修改安装包列表后重新构建,之前下载过的 deb 包仍再次下载。构建日志显示安装步骤实际执行了,并非直接命中 CACHED。

在部分 Debian、Ubuntu 系基础镜像中,/etc/apt/apt.conf.d/docker-clean 会在 APT 更新或 dpkg 操作后删除下载的包。缓存目录能够跨构建保留,并不意味着里面的文件不会被 APT 自己清空。

这篇只处理使用 BuildKit RUN --mount=type=cache、基础镜像确实启用了该清理规则的情况。包版本更新、缓存被回收、换了构建器,也会造成重新下载,不能仅凭下载日志就认定是清理钩子。

核对清理规则和缓存是否属于同一个构建器

在基础镜像的构建阶段检查 /etc/apt/apt.conf.d/docker-clean,重点看 DPkg::Post-Invoke 和 APT::Update::Post-Invoke。如果规则删除 /var/cache/apt/archives/*.deb,即使这个路径来自缓存挂载,文件仍会被删除。

同时确认前后构建使用相同的 BuildKit 构建器和缓存标识。type=cache 的内容保存在构建器一侧;新建的临时 CI 构建器不能因为导入了普通构建缓存,就必然拥有上一次的 APT 缓存挂载内容。

若镜像没有这份文件,检查其实际 APT 配置和构建脚本,寻找其他清理命令。不要为了匹配示例去删除整个 /etc/apt/apt.conf.d。

在使用缓存的构建阶段调整 APT 行为

下面是独立构建阶段的完整示例,基于 Ubuntu 24.04,使用稳定 Dockerfile 前端。包名仅用于展示安装步骤,实际项目按需求替换:

# syntax=docker/dockerfile:1
FROM ubuntu:24.04 AS build

RUN rm -f /etc/apt/apt.conf.d/docker-clean \
    && printf '%s\n' 'Binary::apt::APT::Keep-Downloaded-Packages "true";' \
       > /etc/apt/apt.conf.d/keep-cache

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update \
    && apt-get install -y --no-install-recommends ca-certificates curl

第一步只调整这层镜像里的缓存清理配置,不是让你修改宿主机的 APT。移除删除 deb 的钩子,才能让下载目录中的内容留在缓存里;保留下载包的设置与它配合使用。

第二步同时缓存包归档和 APT 状态目录,并用 sharing=locked 避免多个构建同时写同一个 APT 缓存。安装所需索引仍由这次 apt-get update 更新,不能把缓存存在当成索引永远有效。

不要在该步骤末尾再加删除 deb 包或清空这两个缓存目录的命令,否则会主动抹掉要复用的内容。也不要把整个 /var/lib/dpkg 当作可随意丢弃的下载缓存;它保存的是已安装包的状态。

用实际执行的安装步骤验证

为了观察下载复用,需要有一次安装步骤确实重新执行,例如正常修改了所需包列表。若整个 RUN 显示 CACHED,只能说明构建层被复用,还没有验证 APT 下载缓存。

保留相同构建器与缓存标识,检查前后安装步骤的日志:已有且仍符合所需版本的包可以复用,新包或新版包仍需下载。这里不应以“完全没有网络请求”作为成功标准,更新索引本身仍可能访问软件源。

缓存挂载是性能优化,构建必须能在空缓存下正确完成。垃圾回收、另一次构建更改缓存内容或临时构建器销毁,都会让它失去复用效果。--cache-to、--cache-from 的普通构建缓存导入导出也不能代替缓存挂载内容的持久化安排。

保留镜像体积策略的边界

这套设置放在需要 APT 缓存的构建阶段最容易控制。缓存挂载里的文件不会作为该 RUN 的普通镜像层内容保存,但删除 docker-clean 和新增 keep-cache 的配置会保留在这个阶段中。

如果直接把该阶段作为运行镜像,之后在没有缓存挂载的容器中安装软件,下载包可能留在容器文件系统,增加占用。应按最终镜像的用途恢复原清理策略,或采用明确的独立运行阶段,不要顺带改变所有镜像的 APT 行为。

回退时恢复原 Dockerfile 中的 APT 配置步骤并重新构建。仅恢复构建文件不会删除现有缓存;无需为回退这项修改执行全局 Docker 清理,也不应删除其他构建正在使用的缓存。