Contents

Docker如何构建缓存以及何时不使用它

1. 简介

Docker 构建过程可能需要一些时间才能完成。它可能会下载基础镜像、复制文件以及下载和安装软件包,仅提及一些常见任务。这就是docker build 使用缓存 的原因。

在本教程中,我们将详细了解构建过程以及何时最好避免使用缓存。

2. 关于Docker Build Cache

Docker 镜像分层构建的 ,其中每一层都是来自Dockerfile的指令。层相互堆叠,逐步添加功能。

现在让我们看一个简单的Dockerfile来说明构建过程是如何工作的:

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

上面的 Docker 镜像运行一个脚本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
 ---> Using cache
 ---> 52f7aaec5411
Step 3/4 : ADD entrypoint.sh /
 ---> Using cache
 ---> 66ba9eee7c3c
Step 4/4 : ENTRYPOINT ["/entrypoint.sh"]
 ---> Using cache
 ---> 91a39deabc0b
Successfully built 91a39deabc0b
Successfully tagged print-date-time:latest

构建过程知道Dockerfile没有改变,所以它使用了最后一次构建的缓存来处理所有四个层。如果一条线发生了变化,它将从该线开始重建图层。

Docker 构建过程还检查使用ADDCOPY指令添加的文件中的更改。在我们的示例中,如果我们更改了entrypoint.sh脚本,则将重建第 3 步和第 4 步的层。

这种优化可以让我们在创建图像时节省时间,因为我们可能会多次构建和运行它。但有时缓存会阻止图像更新。

3. 什么时候不使用缓存

Dockerfile可能包含下载和安装工具的说明。在前面的示例中,我们安装了bash。虽然不需要执行脚本,但该行用于说明问题。

假设 Bash 包在 Alpine Linux 上进行了更新以修复安全问题。我们的Dockerfile不会捕捉到变化,因此不会重建镜像。

在克隆 Git 存储库时尤其如此。git clone命令可能永远不会改变,但 repo 会。

避免这些问题的最简单解决方案是根本不使用缓存:

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

no-cache参数将完全丢弃缓存,始终执行Dockerfile的所有步骤。

FROM指令是唯一不受no-cache参数影响的行。**如果机器中存在基础映像,则不会再次拉取它。**我们可以通过尝试再次拉取图像来强制执行新的拉取:

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

pull参数在我们的示例中很有用,因为最新标签必然会经常更改。

请注意,虽然这些工具对本地开发很有帮助,但我们要小心提取最新的生产环境。在这些情况下,使用特定标签比只选择最新标签更安全。 这样,我们就可以避免因意外更改破坏映像而带来的令人不快的惊喜。