Layers, caching and small images · DevOps: Containers, CI and Kubernetes
Why do some Docker builds take seconds and others minutes?
Course contentsWhy you need it
You'll rebuild images many times a day, and so will your CI. A well-ordered Dockerfile reuses almost everything and finishes in seconds; a badly ordered one reinstalls every library on each small code change. Small images also download, start and patch faster, and carry fewer tools an attacker could use.
The intuition
Every instruction makes a layer, and Docker keeps a cache of them. On the next build, each step is reused as long as nothing it depends on changed.
The rule that matters: the first COPY whose files changed breaks the cache, and that step and every step after it run again.
So order a Dockerfile from what changes least to what changes most:
- base image and system packages
- the dependency list (
requirements.txt,package.json) and the install step - your code, which changes all the time
Now editing app.py only re-runs the final COPY . ., not the slow install.
Multi-stage builds keep the final image small: build in a big image with compilers, then copy only the result into a tiny one:
FROM golang:1.22 AS build
…
FROM gcr.io/distroless/static
COPY --from=build /out/app /appAdd a .dockerignore file so COPY . . doesn't send .git, node_modules or secrets into the image.
Definition
Layer
The result of one Dockerfile instruction. Images are stacks of layers, cached and shared between builds.
Build cache
Docker reuses a step if nothing it depends on changed; the first changed COPY invalidates it and all later steps.
Multi-stage build
A Dockerfile with several FROM lines: build in one stage, copy only the result into a small final stage.
Examples
Slow order
Run it in the lessonAny code change invalidates the COPY on step 3, so pip install runs again every time.
FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
USER 1000
CMD ["python", "app.py"]- L3Copies everything, including app.py, which changes all the time.
- L4After a cache break, so it reinstalls every library on each code change.
Fast order
Run it in the lessonDependencies first: changing app.py only re-runs step 5.
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER 1000
CMD ["python", "app.py"]- L3requirements.txt changes rarely, so this step is usually cached.
- L4Cached too, as long as requirements.txt is unchanged.
- L5Your code: the only step that re-runs after an edit (plus the cheap ones after it).
A multi-stage Go build
Run it in the lessonCompile in the big Go image; ship only the binary.
FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/app .
FROM gcr.io/distroless/static
COPY --from=build /out/app /app
USER 65532
CMD ["/app"]- L1Stage 1, named build: has the whole Go toolchain.
- L8Stage 2 starts from an image with almost nothing in it: no shell, no package manager.
- L9Take just the compiled program from stage 1. The compiler stays behind.
Common mistakes
COPY . . before installing
Every code change then reinstalls all dependencies. Copy the dependency list first, install, then copy the code.
No .dockerignore
COPY . . sends everything in the folder: .git, local virtualenvs, .env files with secrets. List them in .dockerignore.
Shipping the build tools
Compilers and package caches in the final image make it bigger and give attackers more to work with. Use a multi-stage build.
Quick quiz
1. Steps: 1 FROM, 2 WORKDIR, 3 COPY requirements.txt, 4 RUN pip install, 5 COPY . ., 6 CMD. You change requirements.txt. Which steps run again?
Show the answer
Answer: A
Step 3's input changed, so it and everything after it run again.
2. What does `COPY --from=build /out/app /app` do?
Show the answer
Answer: A
--from points at another stage of the same Dockerfile.
Practice
3 exercises in three steps: predict what a program prints, change a program to meet a new requirement, then write one from scratch. Your code runs in the browser and is checked the moment you submit.
- PredictWhat gets rebuilt?
You edit
src/server.jsand build again. Which steps run again? - ModifyStop reinstalling
Every change to
app.pyreinstalls all libraries. Reorder the Dockerfile so that changingapp.pydoesn't re-run anyRUNstep, while changingrequirements.txtstill does. - WriteA small Go image
Write a multi-stage Dockerfile for a Go program:
- stage 1 from
golang:1.22, namedbuild: copy the code and rungo build -o /out/app . - the final stage from a tiny image (
gcr.io/distroless/staticoralpine:3.20), copying only/out/appfrombuild - run as a non-root user and start with
["/app"]
The final image must be estimated under 50 MB.
- stage 1 from
Practise this lesson
Open the interactive lesson to edit and run these examples and solve the exercises with instant feedback. Free to start, no sign-up.
Interactive lessons open in order. If you have not done the earlier ones yet, you start at the course map.
Terms in this lesson
| Term | Chinese | Definition |
|---|---|---|
| Layer | 镜像层 | The result of one Dockerfile instruction; cached between builds. |
| Build cache | 构建缓存 | Reused layers; the first changed COPY breaks it. |
| Multi-stage build | 多阶段构建 | Build in one stage, ship only the result from a small one. |
| .dockerignore | .dockerignore | Files Docker should leave out of COPY . . |