Docker multi stage build

Om de footprint van een dockerfile klein te houden, is er de mogelijkheid om de zogenaamde multi-stage-build te gebruiken. Bijvoorbeeld om eerst met een Ubuntu image een go applicatie te builden en deze dan daarna uit te voeren met de veel kleinere alpine.

Een initiele Dockerfile zou er zo uit kunnen zien:

FROM ubuntu:22.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y golang-go
RUN useradd -m appuser
COPY app.go /home/appuser/
USER appuser
WORKDIR /home/appuser
RUN CGO_ENABLED=0 go build app.go
CMD ["/home/appuser/app"]

En als we die builden en dan de grootte van de image bekijken:

$ docker build -t app1 .
$ docker image ls | grep app1
app1    latest    9e658b8c6e35    17 seconds ago    654MB

De grootte van de 654MB bevat dus ook allerlei binaries die niet nodig zijn om de go-app uit te voeren. Een multi-stage-build Dockerfile ziet er dan zo uit:

FROM ubuntu:20.04 AS build
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y golang-go=2:1.13~1ubuntu2
COPY app.go .
RUN pwd
RUN CGO_ENABLED=0 go build app.go

FROM alpine:3.12.0
RUN chmod a-w /etc
RUN addgroup -S appgroup && adduser -S appuser -G appgroup -h /home/appuser
RUN rm -rf /bin/*
COPY --from=build /app /home/appuser/
USER appuser
CMD ["/home/appuser/app"]

Deze builden en de image opvragen laat zien dat de grootte slechts 7.71MB is:

$ docker build -t app2 .
$ docker image ls | grep app2
app2    latest    ad9da6395454    17 seconds ago    7.71MB