1. 简介

Docker 的构建过程通常会比较耗时,尤其是涉及拉取基础镜像、复制文件、下载和安装依赖包等操作。为了提升构建效率,docker build 命令默认会利用缓存机制来加速重复构建。

本文将深入解析 Docker 构建缓存的工作原理,并探讨在哪些场景下应避免使用缓存。


2. Docker 构建缓存简介

Docker 镜像是由多个层(Layer)组成的,每一层对应 Dockerfile 中的一条指令。这些层是叠加在一起的,每层都在前一层的基础上添加新的功能。

我们来看一个简单的 Dockerfile 示例:

FROM alpine:latest
RUN apk add --no-cache bash
ADD entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]

这个镜像运行一个名为 entrypoint.sh 的脚本,它每分钟打印一次当前时间并休眠 60 秒:

#!/bin/bash

while :
do
  echo $(date)
  sleep 60
done

第一次构建时,所有步骤都会执行:

$ docker build -t print-date-time .
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM alpine:3.12
 ---> a24bb4013296
Step 2/4 : RUN apk add --no-cache bash
 ---> 52f7aaec5411
Step 3/4 : ADD entrypoint.sh /
 ---> 66ba9eee7c3c
Step 4/4 : ENTRYPOINT ["/entrypoint.sh"]
 ---> 91a39deabc0b
Successfully built 91a39deabc0b
Successfully tagged print-date-time:latest

但当我们再次构建时,如果 Dockerfile 没有变化,输出如下:

$ docker build -t print-date-time .
...
Step 2/4 : RUN apk add --no-cache bash
 ---> Using cache
Step 3/4 : ADD entrypoint.sh /
 ---> Using cache
Step 4/4 : ENTRYPOINT ["/entrypoint.sh"]
 ---> Using cache
Successfully built 91a39deabc0b

构建过程使用了缓存,跳过了重复执行步骤

⚠️ 只要某一层发生变化,后续所有层都会重新构建

此外,Docker 会检测 ADDCOPY 指令所引用的文件是否发生变化。例如,如果我们修改了 entrypoint.sh,则第 3 层和第 4 层都会被重新构建。


3. 何时不使用缓存?

在某些情况下,缓存可能导致构建结果不是最新的,特别是当依赖项在外部更新但 Dockerfile 本身未改动时。

举个例子:
我们在 Alpine Linux 中安装了 bash 包,如果这个包因为安全修复而更新了版本,但由于 Dockerfile 没变,缓存不会触发重新安装,从而导致镜像未包含最新修复。

类似问题也常见于以下场景:

  • ✅ 使用 git clone 拉取代码仓库时(命令不变,内容可能变)
  • ✅ 安装依赖包时(如 apt-get install、apk add)
  • ✅ 构建过程中依赖远程资源(如远程配置、脚本等)

解决方案

3.1 禁用缓存构建

使用 --no-cache 参数可完全跳过缓存:

$ docker build -t print-date-time --no-cache .

这会强制所有层重新构建

⚠️ 注意:FROM 指令不受 --no-cache 影响。如果本地已有对应基础镜像,它不会被重新拉取。

3.2 强制拉取基础镜像

如果你想确保基础镜像也是最新的,可以加上 --pull 参数:

$ docker build -t print-date-time --pull .

这会强制拉取最新的基础镜像

⚠️ 生产环境慎用 latest 标签。推荐使用固定版本标签,以避免因基础镜像更新导致的不可控问题。


4. 小结

  • ✅ Docker 构建缓存能显著提升构建速度
  • ✅ 缓存机制基于层(Layer)进行对比,任何一层变化都会触发后续所有层重建
  • ✅ 适用于开发阶段快速迭代
  • ❌ 在依赖更新频繁、安全要求高的场景下,应谨慎使用缓存
  • ✅ 推荐使用 --no-cache--pull 来规避缓存陷阱
  • ❌ 生产构建应避免使用 latest 标签,建议使用固定版本号

合理使用缓存,能让你的构建更高效;但懂得何时绕开缓存,才是构建稳定镜像的关键。


原始标题:How the Docker Build Cache Works and When Not to Use It