层级
原文:https://docs.docker.com/build/guide/layers/
Dockerfile 指令的顺序很重要。Docker 构建包含一系列有序的构建指令。Dockerfile 中的每个指令大致对应一个镜像层。下图说明了 Dockerfile 是如何转换成容器镜像中的层堆栈的。
缓存层
当您运行构建时,构建器尝试重用早期构建的层。如果镜像的某个层未发生变化,则构建器会从构建缓存中获取它。如果某个层自上次构建以来已更改,则必须重建该层及其后续的所有层。
上一节中的 Dockerfile 将所有项目文件复制到容器中(COPY . .
),然后在下一步下载应用依赖(RUN go mod download
)。如果您更改了任何项目文件,那么会使 COPY
层的缓存失效。它还会使后续所有层的缓存失效。
由于 Dockerfile 指令的当前顺序,构建器必须再次下载 Go 模块,尽管自上次以来这些包没有发生变化。
更新指令顺序
通过重新排序 Dockerfile 中的指令,您可以避免这种冗余。改变指令的顺序,使下载和安装依赖发生在将源代码复制到容器之前。这样,即使您更改了源代码,构建器也可以重用缓存中的“依赖”层。
Go 使用两个文件,名为 go.mod
和 go.sum
,来跟踪项目的依赖。这些文件对 Go 来说,就像 JavaScript 的 package.json
和 package-lock.json
。为了让 Go 知道需要下载哪些依赖,您需要将 go.mod
和 go.sum
文件复制到容器中。在 RUN go mod download
之前添加另一个 COPY
指令,这次只复制 go.mod
和 go.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 指令可以帮助您避免在构建时进行不必要的工作。
相关信息:
下一步
下一节将展示如何使用多阶段构建来加快构建速度并减小最终输出的大小。