问题
I'm having a ripping good time using skaffold
to develop some kubernetes services, but one of the longest steps in my cycle is pulling all the dependencies for the container.
Does anyone have recommendations on how I can best cache all the dependencies in a layer? Are there best practices with building go binaries inside docker containers? Should I have a layer where I do a go get
? (Also I'm a novice building go binaries, don't know all the bells and whistles yet.)
回答1:
I agree with Grigoriy Mikhalkin. Regarding your performance improvements, I want to name the Docker Build Enhancements which are based on moby/buildkit. At the time of writing, the tools aren't properly documented, but with some trial and error, you might find your solution.
Using buildkit, you can use a cache in your RUN
statements in order to reduce the time of subsequent executions. They provide an example of Go in their docs, as well. In order to have it work, you have to enable the experimental features for both the Docker daemon and client (described on the link above).
回答2:
I encountered exactly the same issue while integrating skaffold
with kubebuilder
and the idea to completely resolve this issue was:
To install buildkit, for example:
brew install buildkit
;To enable
skaffold
for local build by having something like this:
apiVersion: skaffold/v1beta9
kind: Config
build:
local:
useBuildkit: true
useDockerCLI: true
...
- Edit the
Dockerfile
to enable it:
# 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
...
Then at first time it will still download every dependency but afterwards it will use the cache, which dramatically speeds up the build process.
回答3:
It's customary to use multi-stage build for go services. So that all dependencies resolved and executable is built at build stage. And final stage is actually running executable. As a result, your final image will be more slim in size. Although, it's not gonna speed up dependency resolution stage.
回答4:
I found this article after googling some more which covers the process: Using go mod download to speed up Golang Docker builds
The gist of the trick is to copy your go.mod
and go.sum
files into the container, then run go mod download
to download dependencies, and then in another step continue with your build.
This works because your the go.mod
and go.sum
files do not change unless you add more dependencies. So, when the next RUN
statement happens which is the go mod download
docker knows that that it can cache this layer. (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"]
来源:https://stackoverflow.com/questions/61083819/go-dockerized-build-cacheing-the-dependency-pull-layer