层数

Dockerfile 指令的顺序很重要。 Docker 构建由一系列有序的构建指令组成。 Dockerfile 中的每条指令大致翻译为一个镜像层。下图说明了 Dockerfile 如何转换为容器映像中的层堆栈。

从 Dockerfile 到层

缓存层

当您运行构建时,构建器会尝试重用早期构建中的层。如果图像的某个图层未更改,则构建器会从构建缓存中选取它。如果自上次构建以来某个层发生了更改,则必须重新构建该层以及后续的所有层。

上一节中的 Dockerfile 将所有项目文件复制到容器 ( COPY . .),然后在以下步骤 ( RUN go mod download) 中下载应用程序依赖项。如果您要更改任何项目文件,那么该层的缓存就会失效COPY。它还会使后续所有层的缓存失效。

层缓存已失效

由于 Dockerfile 指令的当前顺序,构建器必须再次下载 Go 模块,尽管自上次以来没有任何包发生更改。

更新指令顺序

您可以通过重新排序 Dockerfile 中的指令来避免这种冗余。更改指令的顺序,以便在将源代码复制到容器之前下载和安装依赖项。这样,即使您对源代码进行了更改,构建器也可以重用缓存中的“依赖项”层。

Go 使用两个文件(名为go.modgo.sum)来跟踪项目的依赖关系。这些文件是 Go 的文件,whatpackage.jsonpackage-lock.jsonJavaScript 的文件。为了让 Go 知道要下载哪些依赖项,您需要将go.modgo.sum文件复制到容器中。在 之前添加另一COPY条指令 RUN go mod download,这次仅复制go.modgo.sum文件。

  # syntax=docker/dockerfile:1
  FROM golang:1.21-alpine
  WORKDIR /src
- COPY . .
+ COPY go.mod go.sum .
  RUN go mod download
+ COPY . .
  RUN go build -o /bin/client ./cmd/client
  RUN go build -o /bin/server ./cmd/server
  ENTRYPOINT [ "/bin/server" ]

现在,如果您编辑源代码,构建映像将不会导致构建器每次都下载依赖项。该COPY . .指令出现在包管理指令之后,因此构建器可以重用该 RUN go mod download层。

重新排序

概括

适当地排序 Dockerfile 指令可以帮助您避免构建时不必要的工作。

相关信息:

下一步

下一节将展示如何使用多阶段构建使构建运行得更快,并使生成的输出更小。