A practical overview of Terraform-driven IaC: organizing modules, managing state, and creating reproducible infrastructure deployments.
Figure: store Terraform in Git, run plan/apply in CI, keep state in a remote backend with locking and use workspaces for environment isolation.
Keep reusable components as modules. Example: simple VPC/network module (modules/network/main.tf).
// modules/network/main.tf
variable "name" {}
variable "cidr" { default = "10.0.0.0/16" }
resource "aws_vpc" "this" {
cidr_block = var.cidr
tags = { Name = var.name }
}
output "vpc_id" { value = aws_vpc.this.id }
module "network" {
source = "./modules/network"
name = "prod-vpc"
cidr = "10.1.0.0/16"
}
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "envs/prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}
Use workspaces or one directory per environment. Keep secrets out of version control and supply via secure variable sources (Vault, cloud secrets).
# recommended workflow
terraform workspace new prod
terraform init
terraform plan -var-file=env/prod.tfvars
terraform apply -var-file=env/prod.tfvars
Run plan on PRs and apply only after approvals or merging to main/production branch.
name: Terraform
on:
pull_request:
push:
branches: [ main ]
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: hashicorp/setup-terraform@v2
- name: Terraform Init
run: terraform init
- name: Terraform Format
run: terraform fmt -check
- name: Terraform Plan
run: terraform plan -var-file=env/${{ github.ref_name }}.tfvars
- name: Upload plan artifact
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v3
with:
name: tfplan
path: plan.out
Use Terraform modules, remote state with locking, and automated plan/apply in CI to maintain stable, auditable infrastructure across environments. Treat state carefully, secure secrets, and adopt policy-as-code to prevent risky changes.