DevOps Peach

Linux · Terraform – Infrastructure as Code · Lesson 3 of 5

Workflow and state

Review execution plans and protect state as critical operational data.

Practice interactively →

The core workflow

A typical workflow is write → terraform fmt → terraform init → terraform validate → terraform plan → review → terraform apply. init installs providers and modules and configures the backend; rerun it when providers, modules, or backend settings change.

plan -out=tfplan saves a binary plan so apply can execute the reviewed actions; terraform show tfplan prints it again for review. A plan is not an indefinite guarantee: remote objects may change before apply, and the plan file can contain sensitive data.

flowchart LR
  I["terraform init<br/>providers, backend"] --> P["terraform plan<br/>+ create ~ update - destroy"]
  P --> R{"Plan looks<br/>right?"}
  R -- "yes" --> A["terraform apply"]
  A --> S["State<br/>S3 + lock"]
  S --> P
  %% step I: init downloads providers and connects the state backend.
  %% step P: plan compares code, state and real resources and shows what would change.
  %% step R: Read every line, especially destroy and replace (-/+).
  %% step A: apply performs exactly the reviewed changes.
  %% step S: State maps code to real resource IDs; keep it remote, locked and private.

Reading a plan

Each resource line starts with a symbol: + create, ~ update in place, - destroy, and -/+ destroy then recreate. The summary line counts them, for example Plan: 2 to add, 1 to change, 0 to destroy. Look hardest at -/+: changing an attribute that forces replacement, such as an AMI, recreates the server and may lose its data.

What state is

Artifact or command Role
terraform.tfstate Mapping between addresses and remote objects
.terraform.lock.hcl Selected provider versions and checksums; commit it
terraform state list Tracked resource addresses
terraform state show ADDR Recorded attributes of one resource
terraform output Values read from state

Do not edit or delete state with a text editor. For teams, use a remote backend with suitable access control, encryption, versioning, and locking; avoid committing state or saved plans to Git.

terraform {
  backend "s3" {
    bucket       = "example-org-tfstate"
    key          = "network/terraform.tfstate"
    region       = "ap-southeast-1"
    use_lockfile = true   # S3-native locking; older setups used a DynamoDB table
  }
}

Locking stops two people from applying to the same state at once.

Changing state safely

When code is renamed or moved, a moved block (or terraform state mv) tells Terraform it is the same object, so it is not destroyed and recreated. An import block (or terraform import) brings an existing resource under management. terraform state rm stops tracking an object without deleting it. -target limits a plan to some resources and is meant for exceptional repairs, not daily use.

Workspaces (terraform workspace new dev) keep separate state for the same code, though many teams prefer one directory per environment for clearer separation.

terraform refresh still exists, but standalone use is less favored; terraform plan or apply -refresh-only expresses review and state update more clearly. destroy plans deletion of all managed objects in the workspace, so always review scope.

Practice interactively →