Lesson 08 Terraform Basics + Remote State
Theme:
Lesson 08 · Slide 1

Lesson 08 — Terraform Basics + Remote State

Replace the cloud console with code. Then teach the code to share itself.

Module 3 Single-server Deployment Terraform IaC
Lesson 08 · Slide 2

Recap — What L07 left unfinished

What we have

A working URL on a t3.micro. The deploy is three commands. Caddy handles TLS automatically.

What still hurts

The VM itself took 18 clicks in the AWS console to bring up. If it dies — or if a teammate wants their own copy — we re-do the 18 clicks. That’s a pet, not infrastructure.

“If you can’t describe it as code, you can’t repeat it reliably.”

Lesson 08 · Slide 3

What Terraform actually is

Lesson 08 · Slide 4

The four files you write

main.tf       # resources: the VM, security group, key pair, EIP
variables.tf  # input knobs: region, instance_type, ssh_key_name
outputs.tf    # what to print after apply: public IP, ssh command
versions.tf   # pin Terraform + provider versions

That’s the whole project for a single VM — roughly 80 lines of HCL. Add user_data.sh (the first-boot script) and terraform/backend/ for the remote-state bootstrap and you have the complete Module 3 Terraform tree.

Lesson 08 · Slide 5

The provider block (versions.tf)

terraform {
  required_version = ">= 1.6.0"
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
}

provider "aws" {
  region = var.region
}
Lesson 08 · Slide 6

The VM resource (main.tf)

resource "aws_instance" "vm" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = var.instance_type
  key_name      = var.ssh_key_name
  vpc_security_group_ids = [aws_security_group.web.id]
  user_data     = local.user_data
  tags          = { Name = "url-shortener" }
}

One resource declaration ≈ one click in the EC2 console. user_data runs the Docker install script from L07 automatically on first boot — by the time apply returns the IP, the stack is already running.

Lesson 08 · Slide 7

The plan / apply loop

terraform init     # download providers (once per checkout)
terraform plan     # show diff — no changes applied
terraform apply    # apply the diff after confirmation
terraform destroy  # remove everything you created
Lesson 08 · Slide 8

State — the dirty secret

Why state exists

terraform.tfstate maps your .tf resource names to real cloud IDs (aws_instance.vm → i-0abc123). Without it, every plan would try to create everything from scratch.

Lesson 08 · Slide 9

Local state: fine solo, dangerous shared

Lesson 08 · Slide 10

Remote state with S3 + DynamoDB

terraform {
  backend "s3" {
    bucket         = "url-shortener-tfstate-acme"
    key            = "prod/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "url-shortener-tflock"
    encrypt        = true
  }
}
Lesson 08 · Slide 11

Chicken-and-egg: who creates the backend?

The S3 bucket and DynamoDB table can’t live in the same state — state has to already exist for that to work. Two clean solutions:

Option A — Hand-create (HashiCorp pattern)

Three CLI commands once. Fast, but not reproducible across environments without docs.

Option B — Bootstrap module (our pick)

A tiny separate Terraform project with local state creates the bucket + table. Reproducible per-environment. This is terraform/backend/.

Lesson 08 · Slide 12

Migrating local state to S3

cd cloud-devops/sample-app/terraform/backend
terraform init && terraform apply -auto-approve   # creates bucket + table

cd ..
# Edit versions.tf — uncomment the backend "s3" { ... } block
terraform init -migrate-state                     # uploads local tfstate to S3
# Confirm 'yes'; the local file becomes a stub

After migration: wipe your laptop, clone the repo, run terraform init + plan from any machine with AWS credentials — same diff, same state.

Lesson 08 · Slide 13

What we build today

Lesson 08 · Slide 14

Scope limits — what L08 deliberately skips

Lesson 08 · Slide 15

Recap & what’s next

Coming up: Module 4 — Kubernetes. We trade one VM for a small fleet and stop SSH’ing into hosts entirely. The terraform apply rhythm stays; what it provisions changes from a single EC2 instance to an EKS cluster.
1 / ?