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


缓存层
当你运行构建时,构建器会尝试重用来自之前构建的层。如果镜像中的一个层没有改变,构建器会从构建缓存中获取它。如果一个层自上次构建以来发生了改变,那么该层及其之后的层都必须重新构建。
上一节中的 Dockerfile 将所有项目文件复制到容器中(COPY . .
),然后在接下来的步骤中下载应用程序依赖项(RUN go mod download
)。如果你要更改任何项目文件,那么这将使 COPY
层的缓存失效。它还会使之后所有层的缓存失效。


由于 Dockerfile 指令的当前顺序,构建器必须再次下载 Go 模块,即使自上次下载以来没有一个包发生改变。
更新指令顺序
你可以通过重新排序 Dockerfile 中的指令来避免这种冗余。更改指令顺序,使下载和安装依赖项发生在源代码复制到容器之前。这样,构建器就可以重用缓存中的“依赖项”层,即使你对源代码进行了更改。
Go 使用两个名为 go.mod
和 go.sum
的文件来跟踪项目的依赖项。这些文件对于 Go 来说就像 package.json
和 package-lock.json
对于 JavaScript 一样。为了让 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 指令可以帮助你在构建时避免不必要的步骤。
相关信息
下一步
下一节将介绍如何使用多阶段构建使构建运行得更快,并使最终输出更小。