Go dockerized 构建,缓存依赖拉取层

Go dockerized build, cacheing the dependency pull layer

我正在使用 skaffold 开发一些 kubernetes 服务,但我的周期中最长的步骤之一是拉取容器的所有依赖项。

有没有人对我如何最好地缓存一个层中的所有依赖项有建议?在 docker 容器内构建 go 二进制文件是否有最佳实践?我应该有一个层来做 go get 吗? (另外,我是构建二进制文件的新手,还不知道所有的花里胡哨。)

Go服务习惯用multi-stage build。 这样所有依赖项都已解决并且可执行文件是在构建阶段构建的。最后阶段实际上是 运行 可执行文件。因此,您的最终图像尺寸会更小。虽然,它不会加快依赖项解析阶段。

我同意 Grigoriy Mikhalkin 的观点。关于您的性能改进,我想命名为 Docker Build Enhancements which are based on moby/buildkit。在撰写本文时,这些工具没有正确记录,但通过反复试验,您可能会找到适合自己的解决方案。

使用 buildkit,您可以在 RUN 语句中使用缓存,以减少后续执行的时间。他们也提供 example of Go in their docs。为了让它工作,您必须为 Docker 守护程序和客户端启用实验性功能(在上面的 link 中描述)。

我在谷歌上搜索了更多内容后发现了这篇文章,其中涵盖了整个过程:Using go mod download to speed up Golang Docker builds

技巧的要点是将你的go.modgo.sum文件复制到容器中,然后运行go mod download下载依赖项,然后在另一个步骤中继续构建。

这是有效的,因为你的 go.modgo.sum 文件 不会 改变,除非你添加更多依赖项。因此,当下一个 RUN 语句发生时,go mod download docker 知道它可以缓存该层。 (Source)

FROM golang:1.13.9-buster as builder

# Make Build dir
RUN mkdir /build
WORKDIR /build

# Copy golang dependency manifests
COPY go.mod .
COPY go.sum .

# Cache the downloaded dependency in the layer.
RUN go mod download

# add the source code
COPY . .
# Build
RUN go build -o app

# Run
FROM debian:buster-slim
COPY --from=builder /build
WORKDIR /app
CMD ["./app"]

我在将 skaffoldkubebuilder 集成时遇到了完全相同的问题,完全解决此问题的想法是:

  1. 安装buildkit,例如:brew install buildkit;

  2. 要为本地构建启用 skaffold,方法如下:

apiVersion: skaffold/v1beta9
kind: Config
build:
  local:
    useBuildkit: true
    useDockerCLI: true
...
  1. 编辑 Dockerfile 以启用它:
# syntax=docker/dockerfile:experimental

# Build the manager binary
FROM golang:1.12.5 as builder

...
# Build
#RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager main.go
RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -o manager main.go
...

然后第一次它仍然会下载所有依赖项,但之后它会使用缓存,这会大大加快构建过程。