Dockerfile as Build 缓存

在使用 Docker 构建镜像的过程中,如果我们在 Dockerfile 中的某一层进行了修改,Docker 默认会重新构建这个层及其后面的所有层。这就导致了构建时间的增加。为了解决这个问题,Docker 提供了 Dockerfile as Build 缓存 的机制。这个机制允许我们在不修改镜像构建过程的前提下,保持部分层的缓存,从而加快构建速度。

Dockerfile as Build 缓存的原理

在了解 Dockerfile as Build 缓存的原理之前,我们先了解一下 Dockerfile 的基本结构。Dockerfile 是一个文本文件,用于描述镜像的构建过程。它由一系列的指令构成,每个指令对应一个层。当我们执行 docker build 命令时,Docker 会按照 Dockerfile 的顺序执行这些指令,并生成对应的层。

Docker 会根据每个指令的内容生成一个唯一的标识符,这个标识符称为 指令的摘要(instruction digest)。指令的摘要是根据指令的内容计算而来的,如果指令的内容发生了变化,那么它的摘要也会发生改变。

当 Docker 执行 docker build 命令时,它会检查前面的每个层的摘要是否与当前 Dockerfile 中对应的指令的摘要相匹配。如果匹配,Docker 将使用缓存的层,否则将重新构建该层及其后面的所有层。

Dockerfile as Build 缓存的使用

为了利用 Dockerfile as Build 缓存,我们需要遵循一些规则,以便 Docker 能够正确地识别并利用缓存。

1. 避免无关变更

如果我们不希望某个指令产生的层被缓存,可以在其前面添加一个无关变更的指令,如 RUN echo 'build version 1'。这样,当我们修改了后续指令时,前面的指令会被重新构建,从而不会使用缓存。

2. 使用 ARG 和 ENV

ARG 指令用于定义一个构建时的变量,而 ENV 指令用于定义一个运行时的环境变量。由于构建时的变量和运行时的环境变量在构建过程中是可见的,因此它们的值的改变会导致摘要的改变,从而使缓存失效。

例如,我们可以使用以下方式在 Dockerfile 中定义一个构建时的变量和一个运行时的环境变量:

ARG VERSION
ENV APP_VERSION=${VERSION}

在执行 docker build 命令时,可以使用 --build-arg 参数来指定构建时的变量的值:

docker build --build-arg VERSION=1.0 .

由于构建时的变量的值是可变的,因此它会导致对应层的摘要的改变,从而使缓存失效。

3. 使用 COPY 和 ADD 指令时,尽量使用绝对路径

当我们使用 COPY 和 ADD 指令将文件复制到镜像中时,如果指定的路径是相对路径,Docker 将会在构建过程中解析这个路径,并生成对应的摘要。如果我们修改了这个相对路径指向的文件,摘要也会发生改变,从而使缓存失效。

为了避免这种情况,我们应该尽量使用绝对路径。例如,我们可以使用以下方式将文件复制到镜像中:

COPY ./src /app/src

4. 使用多个 RUN 指令

尽量将多个命令放在一个 RUN 指令中,而不是分开写成多个 RUN 指令。这样可以减少层数,从而减少缓存失效的可能性