Stage Ordering
Categories:
One common issue with complex Dockerfiles is that your final image might require additional packages installed. If this is a lot it can slow down your build.
A technique here is to break up your final image, create a stage early on in your Dockerfile which prepares the final image, installing any required packages, then your compilation stages.
The last stage will be based on the first stage and installs your build artefacts.
The benefit of this is that whilst you are developing your image the first stages are cached by docker, so unless something changes they don't get run again and later stages then use the cache.
For example:
1FROM debian:11-slim AS base
2WORKDIR /root
3RUN apt-get update &&\
4 apt-get install -y ca-certificates chromium nodejs npm &&\
5 npm install npm@latest -g &&\
6 npm install -g postcss postcss-cli &&\
7 npm install autoprefixer &&\
8 chmod -R +rx /root &&\
9 rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ~/.npmrc
10
11FROM golang:alpine AS build
12RUN apk add --no-cache tzdata
13
14WORKDIR /work
15
16RUN go env -w GOFLAGS=-mod=mod
17COPY go.mod .
18RUN go mod download
19
20COPY src/ src/
21RUN CGO_ENABLED=0 go build -o /dest/exampleapp src/bin/main.go
22
23FROM base AS final
24COPY --from=build /dest/* /usr/local/bin/
25WORKDIR /work
Here we now have three stages:
-
Lines 1…9 is the first stage based on
debian:11-slim
and we install chromium and nodejs. - Lines 11…21 is the second stage, which compiles our application using go.
- Lines 23…25 is the third and last stage forming our final image. Here it uses the first stage as the base and just copies the built application from the second stage into /usr/local/bin
The main benefit here is that if you change something in the source, only those steps after the
COPY src/ src/
line will be run, everything else is in the cache.