Skip to content

Immutable Infrastructure

Configuration management ended on a nagging point: Terraform and Ansible both correct drift after it happens. Immutable infrastructure asks the deeper question — what if a server simply never changed after it was created, so drift had nowhere to creep in? This is the endgame of this Part, and it’s the same idea that made containers so powerful, applied to whole machines.

The classic metaphor, and worth internalizing:

PETS CATTLE
───────────────────────── ─────────────────────────────
named, unique, hand-raised numbered, identical, disposable
"web-prod-01" — we know it "web-7f3a" — one of fifty
when sick, you nurse it back when sick, you replace it
patched, tweaked, snowflaked rebuilt from the same image
irreplaceable interchangeable

A pet server is one you care for individually: you SSH in, patch it, tweak its config, nurse it through problems. Over years it accumulates a unique, undocumented state nobody fully understands — a snowflake. Lose it and you can’t recreate it.

Cattle servers are identical and disposable. There’s nothing special about any one of them; when one misbehaves, you don’t diagnose and repair it — you terminate it and let a fresh, identical one take its place. Immutable infrastructure is the discipline of treating servers as cattle.

The core distinction:

  • Mutable infrastructure — you change servers in place after they’re running. SSH in, run a package upgrade, edit a config, apply a patch. The server’s state evolves over its lifetime. This is the world Ansible operates in, and it’s where drift lives.
  • Immutable infrastructure — once a server is deployed, it is never modified. Need a change — a new package version, a config tweak, a security patch? You don’t touch the running server. You build a new image with the change baked in, deploy fresh servers from it, and destroy the old ones.
MUTABLE: patch in place IMMUTABLE: rebuild and replace
────────────────────────── ──────────────────────────────────
server v1 ──patch──► v1.1 image v1 ──build──► image v2
│ │ │
(in-place edits accumulate) deploy v1 deploy v2, kill v1
│ └── never edited ──┘
eventual snowflake every server == its image, exactly

The enabling artifact is the golden image — a fully built, pre-configured machine image (an AWS AMI, a GCP image, a VM template) that contains the OS, your runtime, your application, and all its config, ready to boot and serve. You build it once, in your pipeline, and deploy many identical copies.

This is the same “build once, run many” move you saw with container images — a container image is an immutable, golden image for a process. Immutable infrastructure generalizes the idea to the whole machine. Tools like Packer build golden images by running your provisioning steps (even an Ansible playbook) at build time, then snapshotting the result:

Terminal window
# Build a golden image once, in the pipeline (e.g. with Packer)
packer build web-server.pkr.hcl
# → produces ami-0newimage123, fully configured, ready to boot

Then Terraform deploys that finished image — no per-boot configuration, no SSH, no in-place changes:

resource "aws_instance" "web" {
ami = "ami-0newimage123" # the golden image, fully baked
instance_type = "t3.micro"
# no provisioner, no post-boot config — the image is already complete
}

To ship a change, you build ami-0newimage456, update the reference, and let Terraform replace the fleet. The running servers are never touched — they’re replaced.

Drift only exists because servers can change after they’re created. Remove that possibility and drift has no mechanism to form:

  • No in-place changes → no divergence. If no one ever edits a running server, it cannot drift away from its image. Every server provably equals its golden image, because that’s the only thing it ever was.
  • The image is the single source of truth. “What’s on this server?” is answered by “whatever’s in the image” — fully described, version-controlled, and reproducible. No archaeology required.
  • No configuration accumulation. Snowflakes form from years of small undocumented tweaks. With rebuild-don’t-patch, that accumulation is impossible — each deploy starts from a clean, known image.
  • Rollback is trivial. A bad release? Redeploy the previous image. Since servers are disposable and identical, rolling back is just deploying an earlier known-good artifact — exactly like a container rollback, and a natural fit for the deployment strategies (blue-green, canary) you’ve already met.

Immutability isn’t free, and honesty matters:

  • State must live elsewhere. If servers are disposable, no important data can live on them. Databases, user uploads, and logs must go to managed services, attached volumes, or external stores — see storage & stateful workloads. You design for disposability.
  • Builds get heavier. Every change means baking and deploying a whole image, which is slower than editing a file in place. The payoff — no drift, trivial rollback, identical fleets — is almost always worth it, but it shifts work to the build pipeline.

That closes the loop for this Part. Infrastructure went from clicks in a console (overview) to declarative code (Terraform) to servers that can’t drift because they’re never changed at all. The same control-loop, build-once, cattle-not-pets ideas run through containers, Kubernetes, CI/CD, and IaC alike — one philosophy, applied at every layer.

Five questions for the rebuild-don’t-patch discipline:

  • Why does it exist? Because Terraform and Ansible only correct drift after it forms — immutability asks the deeper question: if a server is never changed after birth, drift has no mechanism to appear.
  • What problem does it solve? Snowflakes and accumulated tweaks: you bake a golden image once, deploy identical cattle from it, and ship any change by building a new image and replacing the fleet — so every server provably equals its image.
  • What are the trade-offs? State must live elsewhere (databases, uploads, logs move to managed stores, since servers are disposable), and builds get heavier — you bake and roll a whole image instead of editing a file in place.
  • When should I avoid it? Stateful machines that genuinely can’t externalize their data cheaply, or a low-stakes single box where the build-pipeline overhead isn’t worth it.
  • What breaks if I remove it? The SSH-in-and-patch habit returns, snowflakes re-accumulate, and rollback stops being “just redeploy the previous image.”
  1. Explain the pets-vs-cattle metaphor. What is a “snowflake” server, and how does one come to exist?
  2. Define mutable and immutable infrastructure. In the immutable model, how do you ship a config change to a running fleet?
  3. What is a golden image, and how does it relate to the container images you learned about earlier?
  4. Give two distinct reasons immutability eliminates drift, rather than merely correcting it after the fact.
  5. Name a real trade-off of immutable infrastructure, and explain — using the book’s thread — the manual step it removes and the production-safety property you gain.
Show answers
  1. Pets are named, hand-raised servers you nurse back to health when sick; cattle are numbered, identical, disposable servers you replace rather than repair. A snowflake is a pet that has accumulated years of small, undocumented in-place tweaks until nobody fully understands its state and it can’t be recreated.
  2. Mutable infra changes servers in place (SSH in, upgrade, edit, patch); immutable infra never modifies a running server. To ship a config change you build a new image with the change baked in, deploy fresh servers from it, and destroy the old ones — replace, never edit.
  3. A golden image is a fully built, pre-configured machine image (an AMI, GCP image, VM template) with OS, runtime, app, and config baked in, ready to boot. It’s the same “build once, run many” idea as a container image — immutable infrastructure just generalizes it from a single process to the whole machine.
  4. Any two: no in-place changes means no divergence — every server provably equals its image because that’s all it ever was; the image is the single source of truth — “what’s on this server?” is answered by the version-controlled image, no archaeology; no configuration accumulation — each deploy starts from a clean known image, so snowflakes can’t form.
  5. A real trade-off: state must live elsewhere (databases, uploads, logs go to managed services or external stores, since servers are disposable) — or alternatively, builds get heavier. The manual step removed is patching and tweaking live servers over SSH; in return drift becomes structurally impossible rather than merely correctable, and recovery is just redeploying a known-good image.