The build time of Golang Docker images always frustrated me as there was always a need to do the go get ./... before we started building the binary. This resulted in fetching the dependencies every time we wanted to build the image. The Dockerfile then looked like this:

FROM golang:alpine AS build-env COPY . $GOPATH/src/mypackage/myapp/

WORKDIR $GOPATH/src/mypackage/myapp/ # go get and build <-- THIS IS THE IMPORTANT PART

RUN go get -d -v

RUN go build -o /go/bin/hello FROM scratch # <- Second step to build minimal image

COPY --from=build-env /go/bin/hello /go/bin/hello

ENTRYPOINT ["/go/bin/hello"]

However. this Dockerfile comes with a major flaw — because we are copying the source code every time first, all other layers are uncached, thus must be executed again (mainly the go get -d -v )

Go mod download

Go 1.11 introduces the go mod download command, which takes go.mod and go.sum files and downloads the dependencies from them instead of using the source code. As these files don’t change frequently (unless you are updating the dependencies), they can be simply cached by the COPY command from Dockerfile.

An example file using this method can look like this:

FROM golang:1.11.1-alpine3.8 as build-env # All these steps will be cached

RUN mkdir /hello

WORKDIR /hello

COPY go.mod . # <- COPY go.mod and go.sum files to the workspace

COPY go.sum .



# Get dependancies - will also be cached if we won't change mod/sum

RUN go mod download

# COPY the source code as the last step

COPY . .



# Build the binary

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -o /go/bin/hello FROM scratch # <- Second step to build minimal image

COPY --from=build-env /go/bin/hello /go/bin/hello

ENTRYPOINT ["/go/bin/hello"]

Please note that these examples are not installing the certificates needed if you are building a networking application. However, adding this to your Dockerfile and copying certs to the scratch step should be sufficient.

RUN apk add --update --no-cache ca-certificates git