我在skaffold
开发一些 kubernetes 服务方面玩得很开心,但是我周期中最长的步骤之一是拉取容器的所有依赖项。
有没有人对我如何最好地缓存一个层中的所有依赖项有建议?在 docker 容器中构建 go 二进制文件是否有最佳实践?我应该有一个层来做一个go get
吗?(我也是一个新手构建 go 二进制文件,还不知道所有的花里胡哨。)
skaffold
我在集成时遇到了完全相同的问题kubebuilder
,完全解决这个问题的想法是:
安装 buildkit,例如brew install buildkit
:
要通过以下方式启用skaffold
本地构建:
apiVersion: skaffold/v1beta9
kind: Config
build:
local:
useBuildkit: true
useDockerCLI: true
...
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
...
然后第一次它仍然会下载每个依赖项,但之后它将使用缓存,这大大加快了构建过程。
我同意格里高利·米哈尔金的观点。关于您的性能改进,我想命名基于moby/buildkit的Docker Build Enhancements。在撰写本文时,这些工具尚未正确记录,但通过一些试验和错误,您可能会找到您的解决方案。
使用 buildkit,您可以在RUN
语句中使用缓存以减少后续执行的时间。他们也在他们的文档中提供了一个Go 的例子。为了让它工作,您必须为 Docker 守护程序和客户端启用实验性功能(在上面的链接中描述)。
我在谷歌上搜索了更多涵盖该过程的文章后发现了这篇文章:Using go mod download to speed up Golang Docker builds
该技巧的要点是将您的go.mod
和go.sum
文件复制到容器中,然后运行go mod download
以下载依赖项,然后在另一个步骤中继续您的构建。
这是有效的,因为除非您添加更多依赖项,否则您的go.mod
和go.sum
文件不会更改。因此,当下RUN
一条语句发生时,go mod download
docker 知道它可以缓存这一层。(来源)
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"]
Go 服务通常使用多阶段构建。因此,所有依赖项都已解决并且可执行文件都是在构建阶段构建的。最后阶段实际上是运行可执行文件。因此,您的最终图像尺寸会更小。虽然,它不会加快依赖解决阶段。