Immutable Infrastructure
Why containers are a statement about truth
The shift to container-based deployment happened gradually across the industry, driven by practical benefits: consistency between environments, faster deployments, easier rollbacks, better resource utilisation. These are real benefits, and they explain adoption.
But they do not explain why immutable infrastructure feels qualitatively different from what preceded it — why teams that adopt it describe a change in how they think about systems, not just how they operate them.
The reason is that immutable infrastructure is not primarily a deployment strategy. It is a commitment to treating software artifacts the same way the framework treats facts: as things that happened, fixed at a point in time, never modified — only superseded by new things (Truth Doesn’t Change).
What mutable infrastructure actually means
In mutable infrastructure, servers accumulate history. SSH sessions apply configuration changes. Packages are upgraded in place. Configuration files are edited on running systems. The server’s current state is the result of every change ever applied to it, in the order applied, including changes made months ago by people who have since left.
The server is a L2 materialised projection of its entire operational history — or worse, a L3 view with no declared lineage. But the history is not recorded. Only the current state is visible. When something goes wrong, the question “what changed?” often cannot be answered. The server’s current state is treated as tier zero, the Real; the L0 events that produced it are gone.
This is the mutable history problem from Truth Doesn’t Change, applied to infrastructure — and it is The Overwritten Balance from the opening of this series, wearing a server’s clothes.
What immutable infrastructure actually means
Immutable infrastructure applies the L0–L3 ladder from Why Atomicity Matters to deployment artifacts (From Immutable Events to Immutable Software).
Build inputs are L0. The Dockerfile, base-image reference, and pinned dependency lockfile are committed specifications — what the build authority decided to use before the image exists. An unpinned requirements file is not yet a stable spec; the environment it resolves to is L2 — it changes when upstream packages move (Event Sourced Science, Break 2).
A published container image is L1. It is the deterministic output of one build step from those L0 inputs: tagged, immutable from publish, SHA digest as cryptographic pin. Same SHA, same contents — the invariant artifact downstream systems depend on. This is not the stream-maintained L1 of a live account balance; it is a single-step invariant aggregate with explicit causal refs to the L0 specs that produced it (logical inference at one aggregation step).
The deployment decision is L0. Someone or something decided to run this image in this environment, at this moment. That decision is a principled committed fact:
The running container is L2. It instantiates the L1 image in a specific environment and accumulates runtime state — a multi-step compound, not the image itself. Logs the process emits are L0 designated observations — measure captures of what happened, recorded as they occur.
The properties that follow
Reproducibility. A container image built from a pinned Dockerfile, with pinned dependencies, in a pinned base image, produces the same runtime behaviour every time it is instantiated. “It worked on staging but not on production” becomes a diagnosable problem — the L1 images differ, or the L0 deployment configuration differs — rather than a mysterious environmental difference.
Auditability. Every deployment is an L0 event in the permanent record. The full history of what ran in production — which image, deployed by whom, at what time, replacing what — is always available.
Rollback. Rolling back is not undoing a change. It is deploying an older L1 image that already exists and was never modified when it was superseded — and recording a new L0 deployment decision (supersession, not mutation).
A/B testing. Routing a fraction of traffic to a new image version is a routing decision — an L0 configuration commit. Two images run simultaneously, producing separate streams of L0 observations. Comparison is a query against those streams.
The connection to the facets: a container image built from a pinned Dockerfile with a pinned lockfile is L1-U-low — one aggregation step from committed L0 inputs, deterministic build, negligible staleness. An unpinned requirements file yields L2-U-high — the resolved environment changes when upstream packages move, making it unstable. This is why the ML reproducibility crisis (Event Sourced Science) — ruptured provenance chain — and the infrastructure reliability problem have the same root cause and the same solution: commit the L0 specs, pin the L1 artifacts, capture observations as they happen, and let stability propagate upward through every layer.
Part IX — Synthesis and Epilogue steps back from applications to name the whole theory in one place — how truth, capture, commitment, facets, and bind discipline fit together.