From Tickets to Code

Scenario: A production network was created by clicking through a cloud console, button by button. Six months later nobody can reproduce it, explain its settings, or safely build an identical staging copy.

Let's start from zero. Infrastructure just means the computing resources a system runs on: servers, networks, databases, DNS records, certificates - the plumbing an application sits on top of. Traditionally, someone builds that plumbing by hand: logging into a web console, clicking "Create Server", typing in settings, clicking again. This works for one machine. It falls apart at scale, because clicking is not repeatable, not reviewable, and leaves no record of why a setting is what it is.

Infrastructure as Code (IaC) is the practice of describing that infrastructure as text files, stored in version control (like Git), instead of as a sequence of clicks. Terraform is one tool that reads those text files and creates, updates, or deletes real infrastructure to match them.

Terraform is specifically a declarative tool. That word matters, so let's define it against its opposite. An imperative script tells the computer the exact steps to take: "check if the server exists; if not, create it; then check if the network exists...". You, the author, have to think through every edge case. A declarative file instead states the desired end result - "there should be a server named api-01 attached to this network" - and leaves the how to the tool. Terraform reads your declared end state, compares it against two other sources of truth (its own memory of what it created last time, called state, and a live check against the real infrastructure), and calculates the smallest set of operations needed to reconcile the two. This calculation step is called a plan; actually performing the operations is called apply. You will see both commands throughout this track.

Everything valuable about IaC - repeatability, peer review, an audit trail, automation, disaster recovery - falls out of this one design choice, not from any special magic in the .tf file extension.

Analogy: A restaurant order states the desired meal - "medium-rare steak, side salad" - and the kitchen decides which pans to use and in what order. A shell script for the same meal would instead dictate every knife movement. Terraform configuration is the order ticket, not the recipe steps.

A worked configuration

terraform {
  required_version = ">= 1.8, < 2.0"
}

resource "fakecloud_network" "app" {
  name = "payments-prod"
  cidr = "10.42.0.0/16"
}

Running terraform apply against the block above produces output like this, which is worth reading slowly the first time you see it:

Terraform will perform the following actions:

  # fakecloud_network.app will be created
  + resource "fakecloud_network" "app" {
      + id   = (known after apply)
      + name = "payments-prod"
      + cidr = "10.42.0.0/16"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

The + marks a brand-new object Terraform intends to create; (known after apply) means the id field doesn't exist yet because the FakeCloud provider assigns it only once the object is actually created. In production, this plan output becomes a change proposal: a pull request can show the intended diff to reviewers, automated policy checks can reject anything unsafe before a human even looks at it, and a saved plan file can guarantee the exact change a reviewer approved is the exact change that gets applied - no drift between "what was reviewed" and "what ran". IaC does not remove the need for engineering judgment; it makes that judgment visible, reviewable, and repeatable instead of trapped in one person's click history.

Common mistakes in production

Goal: Treat the plan as a change contract: understand every create, update, replacement, and destroy before approving it. Reinforce this lesson in the tf-first-apply Terraform lab. Open /labs/terraform and choose slug tf-first-apply; the lab runs real Terraform against the offline FakeCloud provider.