Use Build Stages
Categories:
One common pattern developers use for a Dockerfile is do everything at once. This might be fine for simple images but if you are compiling the application then this is bad as you can easily bloat the final image with either the source code or even the compilers needed to build but not to run.
The solution to this is to use stages. Here you break up your build into separate stages. The earlier stages do the compiling of your application whilst the last one contains your application.
The last stage always becomes the final built image.
For example:
1FROM golang:alpine AS build
2RUN apk add --no-cache tzdata
3
4WORKDIR /work
5
6RUN go env -w GOFLAGS=-mod=mod
7COPY go.mod .
8RUN go mod download
9
10COPY src/ src/
11RUN CGO_ENABLED=0 go build -o /dest/exampleapp src/bin/main.go
12
13FROM debian:11-slim AS final
14COPY --from=build /dest/* /usr/local/bin/
15WORKDIR /work
Here we have two stages:
-
Lines 1…11 is the first stage, and it uses the
golang:alpine
image to compile an example application which it stores the built binary under the /dest/ directory. -
Lines 13…15 is the second and last stage.
It uses the
debian:11-slim
image, copies the built application from the first stage into /usr/local/bin
The final image is now a lot smaller as it doesn't have any of the compilers installed.
This is a simple example of build staging. There are other techniques you can use with this like ordering stages and intermediate stages to reduce the number of layers.