Curious Pandas

Plan, apply, drift

Infrastructure as code keeps three things apart - what you wrote, what the tool last did, and what really exists. Read plans that update, replace and destroy, catch a hand change in the console, and stop a deletion before it happens.

17 min+45 XP for finishing

Clicking through a cloud console works once. The second time, nobody remembers which boxes were ticked, and the third environment is a little different from the first two. Infrastructure as code writes the infrastructure down in files instead, and a tool - Terraform, OpenTofu, Pulumi, Crossplane - makes reality match them.

The tool keeps three things apart, and every surprise in this lesson lives in the gaps between them:

  • The configuration - what you wrote.
  • The state - what the tool remembers creating, as of its last apply.
  • The cloud - what actually exists right now.
Visual guideThree versions of the truth
Three versions of the truthYour code and the tool's state both feed the plan. The plan, once applied, changes the cloud. A change made by hand in the console changes the cloud without touching the code or the state - that gap is drift, and the next plan finds it.your codewhat you wrotestate filewhat it last didplanthe proposed diffthe cloudwhat is realconsole clicka hand changedesiredlast applyapplydriftThree versions of the truthYour code and the tool's state both feed the plan. The plan, once applied, changes the cloud. A change made by hand in the console changes the cloud without touching the code or the state - that gap is drift, and the next plan finds it.your codewhat you wrotestate filewhat it last didplanthe proposed diffthe cloudwhat is realconsole clicka hand changedesiredlast applyapplydrift
  1. You change the code. Nothing happens to the cloud yet.
  2. Plan reads the real objects, compares them with your code and its state, and proposes actions. It changes nothing.
  3. Apply carries out the plan you read. Now the cloud, the code and the state agree.
  4. Someone fixes something by hand in the console. The cloud moved; the code and state did not. That gap is drift.

Reading a plan

The OpenTofu docs describe what a plan does in three steps: it reads the current state of the real objects, compares the configuration with what it knows, and proposes the changes that would make them match. A plan is safe to run as often as you like. It’s the review.

Each proposed change carries a symbol, and the symbols are the whole skill:

Symbol Meaning Ask yourself
+ create is this new thing meant to exist?
~ update in-place the object stays; one setting changes
-/+ replace: destroy, then create what was on the old one, and what points at it?
- destroy is anything in there you need?

A replace is the one people miss. Some settings can’t be changed on a live object - HashiCorp’s docs put it as arguments that cannot be updated in-place due to remote API limitations - so the tool destroys the object and creates a new one. A new server gets a new address, and everything pointing at the old one has to change in the same plan.

Try it

A toy cloud, a plan, and a consoletoy engine, real plan shapes
Your code
Cloud console: hand changes
Plan first. A plan is free; it changes nothing.
What the tool believes vs what is really there
resourcestate filethe cloud

Drift is a symptom

HashiCorp’s drift tutorial says it directly: you should not make manual changes to resources a tool controls, because the state drifts from the real infrastructure. The next plan will quietly put your code back - undoing a 3am console fix that was holding something up. When you must change things by hand, write the change into the code straight afterwards. Then the plan agrees with you.

This is the same idea as Git as the source of truth, where a controller re-applies the repository on a timer instead of waiting for someone to run a plan.

Check yourself+10 XP

A plan line reads: -/+ server.web must be replaced, with image marked '# forces replacement'. What happens on apply?

Check yourself+10 XP

Someone resized a server in the console last night. You change an unrelated tag in the code and run plan. What does the plan propose for the size?

Check yourself+10 XP

You removed a bucket from the code by accident. Where is the cheapest place to catch it?

Do it for real · your machine+50 XP bonus

Everything above ran in your browser. Now do it on a real cluster with tilt lab 01-deploy-a-service (profile minimal). You need Docker, kind and Tilt, about 15 GB of free disk and 8 GB of spare RAM. Setup guide · Can my machine run it?

Kubernetes manifests are infrastructure as code too, and kubectl diff is their plan: it exits 0 when nothing differs and 1 when something does. On the running platform, after lab 01:

kubectl diff -k examples/hello-world; echo "exit $?"     # 0: live matches the files
kubectl -n hello scale deploy/hello --replicas=3        # the console click
kubectl diff -k examples/hello-world; echo "exit $?"     # 1: replicas 3 -> 1, drift found
kubectl apply -k examples/hello-world                   # apply: the files win
Self-reported. We can't see your machine, and we don't want to. This is a bonus, never required.

Sources

Finished reading?

Missions and quizzes above earn their own XP. This marks the lesson done.