A short course on Docker
Docker: the layer cache and image size
Two questions everyone who builds Docker images runs into: why does the build take three minutes
when I changed one line of code, and why is the image still enormous after I rm-ed
all the temporary files. Both have exact answers, and both are measurable with
docker build and docker image inspect. The figures here come from
Docker 29.7.2 with BuildKit (buildx v0.36.1).
RUN line of a six-step Dockerfile makes the five steps after it
run again. And an image that writes 20 MB and deletes it in the next RUN measures
25,104,035 bytes — 463 bytes more than the same image that keeps the
file.
The two lessons
Twelve to fifteen minutes of reading each, with a lab that runs in the browser.
What breaks the build cache
Fourteen real builds, each changing exactly one thing. With a lab that takes your own Dockerfile and what you just edited.
Lesson 2You deleted the file and the image stayed the same size
Three images built for real from three spellings, 6.09 times apart. With a lab that lets you compose the RUN steps and watch each layer.
How the measurements were taken
The rig is a small build directory and a script that runs docker build
exactly once per scenario and then reads the CACHED lines from the log.
That detail matters: the first version of the script ran the build twice, and the second run
always reported every step as CACHED — the resulting table was 100% cache hits and completely
meaningless.
DOCKER_BUILDKIT=1 docker build -t dlab:t ctx > /tmp/b.log 2>&1
awk '/^#[0-9]+ \[[0-9]+\/[0-9]+\]/ { … }
/^#[0-9]+ CACHED/ { … }' /tmp/b.log
docker image inspect dsize:two --format '{{.Size}}'
# 25104035
Image sizes come from docker image inspect --format '{{.Size}}', not from the SIZE
column of docker image ls. The two commands disagree: with the containerd image
store in use here, docker image ls reports 55.3 MB for the very image that
inspect reports as 25,104,035 bytes, because it counts both the compressed blob and
the unpacked copy. This course uses only the inspect figure, and always names the
command that produced a number.