Container Build and Run Diagram
What happens between a Dockerfile and a running process — the layer cache that decides build time, the multi-stage boundary that decides image size, and the runtime settings that are wrong by default.
SVG. No sign-up, no email.
Two paths, drawn separately because they fail differently. The build path decides what is in the image. The run path decides what the image is allowed to do. Most container problems are clearly one or the other, and confusing them is why people debug builds when the problem is a capability.
The build path#
The base image is a supply chain decision. Pinned by digest, it is the same bytes every time. Pinned by tag, it changes when the publisher rebuilds it, which means the image running in production was assembled from something nobody reviewed. This is the most common reproducibility failure and it produces the sentence "it built fine last week".
Dependencies belong in their own layer, before the source is copied. The layer cache is keyed on what changed: put the source copy first and every code change invalidates the dependency install, turning a 10-second build into a 4-minute one. This ordering is the whole of build-time performance.
The stage boundary is where image size is decided. Everything needed to build — compilers, headers, package managers, test fixtures — stays in the build stage. Only the artefact crosses into the final image. A 900 MB image and a 90 MB image usually differ by nothing except whether this boundary exists.
It is also a security boundary. A final image with no compiler and no package manager is a much less useful place for an attacker to land.
The registry lane#
Drawn as a set because these are gates, not steps — each one independently blocks a bad image from going further.
Secret scanning deserves particular attention, because the intuition is wrong. A secret added in one layer and deleted in the next is still in the image: deletion writes a new layer recording the removal, and every earlier layer remains readable by anyone who pulls it. The file is gone from the filesystem view and present in the image.
The run path#
Two settings are wrong by default and both are one line.
Containers run as root unless told otherwise. A process that does not need root running as root inside a container is the same mistake as running it as root outside one, with the added problem that it feels contained when it is only namespaced.
The root filesystem is writable by default. Making it read-only, with explicit writable volumes, converts a whole class of compromise into a failed write — and it surfaces, usually immediately, everything that was writing to the container filesystem and should not have been.
PID 1 is the box worth understanding. The process in a container is PID 1, and PID 1 has special signal-handling behaviour: signals with no handler are ignored rather than applying their default action. A process that does not explicitly handle SIGTERM will therefore not stop when asked. It waits out the grace period and is killed.
Every rolling update, every scale-down and every node drain sends SIGTERM. A container that ignores it drops whatever it was doing, every time, and the symptom is intermittent errors during deployments that nobody can reproduce.
Using this diagram#
Trace your own image along the top lane and note which boxes are missing. The two most common gaps are a base pinned by tag rather than digest, and no stage boundary — the first makes builds unreproducible, the second makes images ten times larger than they need to be.
Then check the two warning boxes in the bottom lane. If your container runs as root with a writable root filesystem, both fixes are one line each and neither requires understanding anything else on this page.