· Infrastructure · 2 min read
Infrastructure as Code with Terraform and Terragrunt
Stop clicking through cloud consoles. Here's how I use Terraform and Terragrunt to manage scalable, cost-optimized AWS infrastructure.
Why IaC Is Non-Negotiable
Clicking through cloud consoles is error-prone, impossible to review, and doesn’t scale. Every infrastructure change I’ve made in production for the past few years has gone through code — specifically Terraform and Terragrunt. Here’s what I’ve learned.
Terraform Basics
Terraform by HashiCorp is cloud-agnostic and declarative. Here’s a typical AWS setup I use:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-west-1"
}Real-World Example: EKS Cluster
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = "production"
cluster_version = "1.29"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
eks_managed_node_groups = {
default = {
min_size = 2
max_size = 10
desired_size = 3
instance_types = ["t3.medium"]
}
}
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}Why Terragrunt?
Terraform alone struggles with DRY configuration across multiple environments. Terragrunt solves this:
infrastructure/
terragrunt.hcl # root config (remote state, provider)
prod/
eks/terragrunt.hcl
rds/terragrunt.hcl
staging/
eks/terragrunt.hcl
rds/terragrunt.hclRoot terragrunt.hcl:
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "eu-west-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}Each environment’s terragrunt.hcl just includes the root and overrides what’s different. No copy-paste between environments.
The Core Workflow
terraform init # Download providers and modules
terraform plan # Preview changes — always review this
terraform apply # Apply changes
terraform destroy # Tear down (use with caution in prod!)With Terragrunt across environments:
terragrunt run-all plan # Plan all modules
terragrunt run-all apply # Apply all modules in dependency orderCost Optimization Tips
From managing multi-service AWS infrastructure, here are patterns that save real money:
- Use Spot instances for non-critical workloads (EKS node groups)
- Karpenter for right-sized node provisioning
- S3 lifecycle policies to move old data to cheaper storage tiers
- CloudFront in front of everything to reduce origin load
- RDS reserved instances for predictable database workloads
Conclusion
Terraform + Terragrunt is the combination I reach for on every new infrastructure project. The plan/apply cycle gives you confidence, the state file gives you auditability, and Terragrunt keeps your config DRY across environments. Once you go IaC, manual provisioning feels like a step back.