Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Write a Dockerfile and read its layers

After this lesson: I can write a Dockerfile and say which of its steps run again after a change.

55 min lesson4 commandsDocker basics lab: learn containers, logs and restarts by fixing a broken service

Four minutes for one changed line

A Dockerfile is a text file of steps that builds a container image, and Docker saves each step as a layer it can reuse. The order of the steps decides how fast a rebuild is.

A team changes one line of a shop's code. The build takes four minutes, because it downloads every library again.

Another team changes the same line and waits one second. Both wrote a build file. They wrote the steps in a different order.

By the end of this lesson

Note

I can write a Dockerfile and say which of its steps run again after a change.

Key words

WordWhat it means
Dockerfilea text file of steps that builds an image
Base imagethe image a build starts from
Layerthe saved result of one build step
Cachesaved layers that a build reuses
Buildto make an image by running the steps

The cells students fill in are left blank in this preview.

What the lab cannot do

Note

The lab's docker refuses to build or pull an image, because a build runs steps with rights on the machine. We built the Dockerfiles in this lesson on our own machine. You read them, look at what an image leaves in a container, and check your own file in the assignment. To build for real, use your own machine.

A Dockerfile is a list of steps

Each line starts with an instruction word. FROM names the base image. COPY brings files in. RUN runs a command while the image is built. CMD says what to run when a container starts.

Docker reads the lines from the top. Here is a small shop written that way.

A Dockerfile for a small Python shop

Code: bash
FROM python:3.12-alpine
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]

The start folder, set by WORKDIR

Command
docker inspect --format '{{.Config.WorkingDir}}' cache

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

The signal that stops web (set by STOPSIGNAL)

Command
docker inspect --format '{{.Config.StopSignal}}' web

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Worked example: what each instruction leaves behind

InstructionWhat it does in a buildWhere you see it later
FROMstarts from a base imageConfig.Image names the image
WORKDIRsets the folder the next steps useConfig.WorkingDir, /data for cache
EXPOSEsays which door the program usesConfig.ExposedPorts, 80/tcp for web
STOPSIGNALsays how to ask the program to stopConfig.StopSignal, SIGQUIT for web
COPY and RUNadd files and run commandsa new layer each

The cells students fill in are left blank in this preview.

Each step makes a layer

A build saves the result of every step as a layer. The layers are stacked, and an image is the whole stack. A layer never changes once it is made.

A container adds one thin layer on top, where it writes. docker diff lists what is in that top layer.

Worked example: the layers of the shop image

StepSize on our test machine
The base image, python:3.12-alpineabout 48 MB for its biggest layer
WORKDIR /app8 kB
COPY requirements.txt .12 kB
RUN pip install ...10.6 MB
COPY app.py .12 kB
CMD ["python", "app.py"]0 B

The cells students fill in are left blank in this preview.

Write a file in web's own folders

Command
docker exec web touch /tmp/layer-demo.txt

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Find it in the container's top layer

Command
docker diff web | grep layer-demo

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A layer is reused if nothing above changed

Before it runs a step, Docker asks one question. Is this the same step with the same files as last time, and was everything above it the same too? If yes, it reuses the saved layer. That is the cache.

The first step that differs runs again. So does every step after it. Put what changes least at the top.

Order 1: copy everything first (our example)

Code: bash
FROM python:3.12-alpine
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
CMD ["python", "app.py"]

Worked example: edit app.py, then build again

StepOrder 1Order 2 (the first Dockerfile above)
WORKDIR /appcachedcached
COPY requirements.txt .not in this ordercached
COPY . .runs againnot in this order
RUN pip install ...runs again, 11 secondscached
COPY app.py .not in this orderruns again, under a second

The cells students fill in are left blank in this preview.

A common mistake

Warning

Many people think Docker reruns only the line they edited. It reruns that step and every step after it. Copy the file that lists your libraries first and install them, then copy your own code. The slow step then stays cached.

Going further

Write the Dockerfile for a tiny site of your own. Start from nginx:1.27-alpine, copy one index.html into /usr/share/nginx/html and add nothing else.

On a machine with Docker, build it twice. The second build should say CACHED on every step.

About this lab and its source: Docker basics lab: learn containers, logs and restarts by fixing a broken service

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.