Course outline · 0% complete

0/29 lessons0%

Course overview →

Image size hygiene

lesson 6-2 · ~12 min · 18/29

Why size matters

docker images on a beginner's machine often shows apps weighing 1.2 GB. Size is not just disk space:

  • Slow ships: every deploy and every CI run pulls the image. Gigabytes × many machines × many deploys a day adds up to real minutes and real money
  • Attack surface: a full OS image ships hundreds of packages your app never uses, and every one of them can carry security vulnerabilities you now have to patch

First fix, choose a smaller base in your FROM:

Base imageRough size
python:3.12~1.0 GB
python:3.12-slim~150 MB
python:3.12-alpine~50 MB

slim drops build tools and docs. alpine uses a minimal Linux distribution, tiny but occasionally incompatible with packages that expect standard libraries. slim is the safe default, which is why lesson 3-1's Dockerfile used it.

Code exercise · bash

Your turn: put numbers on the size argument. With 50 deploys a month, print the monthly transfer for the full image, for the slim image, and the savings, formatted exactly as in the expected output. Bash does integer math with $(( ... )).

Multi-stage builds

Compiled languages have a worse problem: building needs the whole toolchain (compiler, headers, caches), but running needs only the final binary. A multi-stage build uses two FROMs in one Dockerfile:

FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o /out/server .

FROM alpine:3.20
COPY --from=builder /out/server /server
CMD ["/server"]
  • FROM golang:1.22 AS builder: stage one, named builder, has the full ~800 MB Go toolchain
  • RUN go build ...: compile to a single binary
  • FROM alpine:3.20: stage two starts fresh from a ~8 MB base
  • COPY --from=builder ...: reach back into stage one and take only the binary

Only the final stage becomes the shipped image. The toolchain, source, and caches are all left behind. Result: ~15 MB instead of ~900 MB.

same app, three ways to build the image~900 MBFROM golang:1.22 (toolchain ships with the app)~150 MB · slim base~15 MB · multi-stage, binary onlysmaller image = faster pulls in CI and deploys, fewer packages to patch
The same application shipped three ways. Multi-stage builds keep the build toolchain out of the final image entirely.

Quiz

In the multi-stage Dockerfile, why does the giant Go toolchain not end up in the shipped image?

Problem

What is the technique called where one Dockerfile stage compiles the app and a second, minimal stage copies in only the built artifact?