构建缓存失效

在构建镜像时,Docker会按照Dockerfile中的指令顺序逐步执行每条指令。对于每条指令,builder会检查是否可以从构建缓存中重用该指令。

通用规则

构建缓存失效的基本规则如下:

  • 构建器首先检查基础镜像是否已经被缓存。每个后续指令都会与缓存的层进行比较。如果没有缓存的层完全匹配该指令,则缓存失效。

  • 在大多数情况下,将Dockerfile指令与相应的缓存层进行比较就足够了。然而,某些指令需要额外的检查和解释。

  • 对于ADDCOPY指令,以及带有绑定挂载的RUN指令(RUN --mount=type=bind),构建器会从文件元数据计算缓存校验和,以确定缓存是否有效。在缓存查找期间,如果涉及的任何文件的元数据发生变化,缓存将失效。

    在计算缓存校验和时,不考虑文件的修改时间(mtime)。如果仅复制文件的mtime发生了变化,缓存不会失效。

  • 除了ADDCOPY命令外,缓存检查不会查看容器中的文件来确定缓存匹配。例如,在处理RUN apt-get -y update命令时,不会检查容器中更新的文件以确定是否存在缓存命中。在这种情况下,仅使用命令字符串本身来查找匹配。

一旦缓存失效,所有后续的Dockerfile命令都会生成新的镜像,并且不会使用缓存。

如果你的构建包含多个层,并且你希望确保构建缓存是可重用的,请尽可能将指令从较少更改的排序到更频繁更改的。

运行指令

RUN 指令的缓存在构建之间不会自动失效。 假设你在 Dockerfile 中有一个步骤来安装 curl

FROM alpine:3.21 AS install
RUN apk add curl

这并不意味着你镜像中的curl版本总是最新的。 一周后重新构建镜像仍然会得到与之前相同的包。 要强制重新执行RUN指令,你可以:

  • 确保它之前的层已经改变
  • 在构建之前使用 docker builder prune 清除构建缓存
  • 使用 --no-cache--no-cache-filter 选项

--no-cache-filter 选项允许您指定一个特定的构建阶段来使缓存失效:

$ docker build --no-cache-filter install .

构建密钥

构建机密的内容不是构建缓存的一部分。 更改机密的值不会导致缓存失效。

如果你想在更改密钥值后强制缓存失效,你可以传递一个带有任意值的构建参数,这个值在更改密钥时也会更改。构建参数确实会导致缓存失效。

FROM alpine
ARG CACHEBUST
RUN --mount=type=secret,id=TOKEN,env=TOKEN \
    some-command ...
$ TOKEN="tkn_pat123456" docker build --secret id=TOKEN --build-arg CACHEBUST=1 .

秘密的属性,如ID和挂载路径,确实参与了缓存校验和的计算,如果这些属性发生变化,将导致缓存失效。