Lesson 01 of 7 · Modules
IaC principles & Terraform basics
Why infrastructure belongs in code, and how Terraform turns declarations into real resources: providers, resources, the init/plan/apply cycle, the dependency lock file, and your first free lab with no cloud account.
Why infrastructure as code
Clicking in a console doesn't scale: nobody can review it, repeat it, or say exactly what changed last Tuesday. Infrastructure as code (IaC) puts infrastructure in files:
- Reviewable: changes go through pull requests.
- Repeatable: the same code builds dev, staging and prod.
- Auditable: Git history says who changed what, and why.
- Recoverable: lose an environment, rebuild it from code.
Building LEGO from memory, you'll never make the same model twice. Building from the instruction booklet, anyone can build it exactly, again and again, and if a piece goes missing, the booklet tells you what to put back. Terraform code is the instruction booklet for your infrastructure.
Terraform in one picture
your .tf files (desired state) ──┐
├──► terraform plan ──► list of changes ──► terraform apply ──► provider APIs
state (what Terraform manages) ──┤ (AWS, Kubernetes, libvirt…)
reality (read via providers) ────┘
- Providers are plugins that talk to APIs (AWS, Azure, Kubernetes, Helm, GitHub, libvirt, hundreds more).
- Resources are the things you manage (
aws_s3_bucket,kubernetes_namespace). - State records which real objects belong to which resource (lesson 02).
Your first configuration (no cloud needed)
# main.tf
terraform {
required_version = ">= 1.6"
required_providers {
random = { source = "hashicorp/random", version = "~> 3.6" }
local = { source = "hashicorp/local", version = "~> 2.5" }
}
}
resource "random_pet" "server" {
length = 2
}
resource "local_file" "inventory" {
filename = "${path.module}/inventory.txt"
content = "server: ${random_pet.server.id}\n"
}
output "server_name" {
value = random_pet.server.id
}
$ terraform init
Initializing provider plugins...
- Installing hashicorp/random v3.6.x...
- Installing hashicorp/local v2.5.x...
Terraform has been successfully initialized!
$ terraform plan
# local_file.inventory will be created
# random_pet.server will be created
Plan: 2 to add, 0 to change, 0 to destroy.
$ terraform apply
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Outputs:
server_name = "fluent-heron"
Notice: Terraform created random_pet first, because local_file references it. References build the dependency graph automatically.
Run terraform apply again: no changes. That's idempotency: running the same code twice doesn't do anything twice.
Reading a plan
| Symbol | Meaning |
|---|---|
+ |
Create |
~ |
Update in place |
-/+ |
Destroy and recreate (replacement), so read why ("forces replacement") |
- |
Destroy |
Replacing a database or a cluster by accident is the classic Terraform disaster. Read every plan.
The dependency lock file
terraform init writes .terraform.lock.hcl with the exact provider versions and checksums chosen. Commit it. Upgrade deliberately with terraform init -upgrade, and review the diff.
Try it: your first free Terraform project
- Install Terraform (or OpenTofu, which is command-compatible for these basics) and create the configuration above.
init,plan,apply; readinventory.txt.- Change
length = 2to3. Plan: why israndom_petreplaced, and why doeslocal_filechange too? - Edit
inventory.txtby hand, then runplanagain. What does Terraform want to do? terraform destroyand confirm both are gone.
Going deeper: IaC habits
- Everything through code: console changes are drift (see lesson 07). Use read-only console access for most people.
- Keep configurations small and focused (per environment and layer), not one giant repository-wide state.
terraform fmtandvalidatein pre-commit hooks and CI.- OpenTofu is an open-source fork of Terraform; most concepts and commands in this course apply to both.
Recap
- IaC = infrastructure as reviewable, repeatable, auditable code.
- Providers talk to APIs; resources describe desired objects; state tracks them.
- init → plan → apply (→ destroy); references build the dependency graph; re-runs are idempotent.
- Read plans carefully (
-/+= replacement) and commit the lock file.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.