Everyone Can Learn Program
中文 Start learning
Specialty · DevOpsLesson 2 of 5Free to read

Layers, caching and small images · DevOps: Containers, CI and Kubernetes

Why do some Docker builds take seconds and others minutes?

Course contents

Why 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:

  1. base image and system packages
  2. the dependency list (requirements.txt, package.json) and the install step
  3. 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 /app

Add 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

Any 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"]
Step by step
  1. L3Copies everything, including app.py, which changes all the time.
  2. L4After a cache break, so it reinstalls every library on each code change.

Dependencies 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"]
Step by step
  1. L3requirements.txt changes rarely, so this step is usually cached.
  2. L4Cached too, as long as requirements.txt is unchanged.
  3. 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 lesson

Compile 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"]
Step by step
  1. L1Stage 1, named build: has the whole Go toolchain.
  2. L8Stage 2 starts from an image with almost nothing in it: no shell, no package manager.
  3. 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?

  1. A3, 4, 5 and 6
  2. BOnly 4
  3. COnly 3
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?

  1. ACopies a file from the earlier stage named build, not from your project
  2. BDownloads a file from a website called build
  3. CBuilds the app again
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.

  1. PredictWhat gets rebuilt?

    You edit src/server.js and build again. Which steps run again?

  2. ModifyStop reinstalling

    Every change to app.py reinstalls all libraries. Reorder the Dockerfile so that changing app.py doesn't re-run any RUN step, while changing requirements.txt still does.

  3. WriteA small Go image

    Write a multi-stage Dockerfile for a Go program:

    • stage 1 from golang:1.22, named build: copy the code and run go build -o /out/app .
    • the final stage from a tiny image (gcr.io/distroless/static or alpine:3.20), copying only /out/app from build
    • run as a non-root user and start with ["/app"]

    The final image must be estimated under 50 MB.

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

TermChineseDefinition
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.dockerignoreFiles Docker should leave out of COPY . .