Scale Terraform #

Konfigurasi Terraform yang dimulai kecil — satu main.tf, satu terraform.tfstate — bisa tumbuh hingga mengelola ratusan resource dalam satu konfigurasi. Di titik ini, masalah mulai muncul: terraform plan butuh waktu lama karena harus refresh semua resource, satu kesalahan bisa mempengaruhi infrastruktur yang tidak berhubungan, dan blast radius dari setiap apply menjadi terlalu besar. Scaling Terraform bukan soal menambah spesifikasi mesin yang menjalankan pipeline, tapi soal memecah konfigurasi berdasarkan prinsip yang tepat.

Tanda Konfigurasi Perlu Dipecah #

SINYAL BAHWA KONFIGURASI SUDAH TERLALU BESAR:

  ✗ terraform plan butuh lebih dari 5 menit (terlalu banyak API refresh)
  ✗ Satu apply mempengaruhi puluhan resource yang tidak berhubungan
  ✗ Tim berbeda sering konflik karena mengubah file yang sama
  ✗ Ada resource yang "tidak boleh disentuh" campur dengan yang rutin berubah
  ✗ Test perubahan kecil butuh menunggu plan seluruh infrastruktur
  ✗ State file lebih dari beberapa MB (ribuan resource)
  ✗ Tim tidak tahu lagi resource apa yang ada di konfigurasi ini

Prinsip Pemisahan: Lifecycle dan Blast Radius #

Cara paling efektif memecah konfigurasi bukan berdasarkan tipe resource, tapi berdasarkan dua pertanyaan: seberapa sering berubah, dan apa dampak jika ada yang salah?

PRINSIP LIFECYCLE:
  Resource yang berubah dengan frekuensi berbeda sebaiknya dipisah.

  Jarang berubah (bulan/tahun):
    VPC, subnets, routing, peering
    IAM roles, SCPs, organizations
    DNS zones (bukan records)
    → Satu konfigurasi, apply sangat jarang

  Sesekali berubah (minggu/bulan):
    Cluster Kubernetes, RDS instances
    Load balancers, security groups
    S3 buckets, KMS keys
    → Konfigurasi terpisah per domain

  Sering berubah (hari/minggu):
    Kubernetes deployments
    Task definitions ECS
    Lambda functions
    DNS records
    → Konfigurasi terpisah, bisa auto-apply

PRINSIP BLAST RADIUS:
  Resource yang kritis (downtime mahal) dipisah dari yang tidak kritis.
  Jika ada bug saat apply database konfigurasi,
  jangan sampai mempengaruhi networking.

Pola Layering: Dependency Antar Konfigurasi #

ARSITEKTUR LAYERED:

  Layer 1: Foundation (paling jarang berubah)
    ├── VPC, subnets, internet gateway
    ├── Route53 zones
    ├── IAM roles dasar
    └── S3 bucket untuk state
    Output: vpc_id, subnet_ids, route53_zone_id

  Layer 2: Platform (berubah saat ada upgrade infrastruktur)
    ├── EKS cluster / ECS cluster
    ├── RDS instances
    ├── ElastiCache
    └── Load balancers
    Input: vpc_id, subnet_ids (dari layer 1)
    Output: cluster_endpoint, db_endpoint, lb_dns_name

  Layer 3: Application (paling sering berubah)
    ├── Kubernetes deployments
    ├── Task definitions ECS
    ├── DNS records (pointing ke LB dari layer 2)
    └── Lambda functions
    Input: cluster_endpoint, db_endpoint (dari layer 2)

  Setiap layer hanya bergantung ke layer di bawahnya.
  Perubahan di layer atas tidak mempengaruhi layer bawah.
# Layer 3 membaca output dari Layer 2 via remote state
data "terraform_remote_state" "platform" {
  backend = "s3"
  config = {
    bucket = "my-terraform-state"
    key    = "platform/terraform.tfstate"
    region = "ap-southeast-1"
  }
}

resource "aws_route53_record" "app" {
  zone_id = data.terraform_remote_state.platform.outputs.route53_zone_id
  name    = "api.example.com"
  type    = "CNAME"
  ttl     = 300
  records = [data.terraform_remote_state.platform.outputs.lb_dns_name]
}

Struktur Direktori untuk Infrastruktur Besar #

infra-repo/
  ├── modules/                      ← Shared, versioned modules
  │   ├── networking/
  │   ├── eks-cluster/
  │   └── rds/
  │
  ├── foundation/                   ← Layer 1
  │   ├── networking/
  │   │   ├── main.tf
  │   │   ├── outputs.tf
  │   │   └── backend.tf
  │   └── iam/
  │
  ├── platform/                     ← Layer 2
  │   ├── eks/
  │   ├── databases/
  │   └── load-balancers/
  │
  ├── applications/                 ← Layer 3
  │   ├── api-service/
  │   ├── worker-service/
  │   └── frontend/
  │
  └── scripts/
      ├── plan-all.sh               ← Plan semua layer secara berurutan
      └── apply-all.sh
# plan-all.sh — plan semua layer dengan order yang benar
#!/bin/bash
set -e

ENVIRONMENT=${1:-staging}

echo "=== Layer 1: Foundation ==="
cd foundation/networking
terraform plan -var="environment=$ENVIRONMENT"

echo "=== Layer 2: Platform ==="
cd ../../platform/eks
terraform plan -var="environment=$ENVIRONMENT"

echo "=== Layer 3: Applications ==="
cd ../../applications/api-service
terraform plan -var="environment=$ENVIRONMENT"

Paralel vs Serial Execution #

SERIAL (default untuk dependency):
  Layer 1 selesai → Layer 2 mulai → Layer 3 mulai
  Cocok untuk dependency yang ketat antar layer

PARALEL (untuk konfigurasi yang independen):
  Layer 2: eks, databases, load-balancers bisa diapply bersamaan
  Masing-masing hanya bergantung ke Layer 1 (sudah selesai)

  Dalam CI/CD matrix:
  jobs:
    apply-platform:
      strategy:
        matrix:
          component: [eks, databases, load-balancers]
        max-parallel: 3
      steps:
        - run: terraform apply platform/${{ matrix.component }}/tfplan

  PERHATIAN: Paralel hanya aman jika tidak ada dependency antar komponen
  yang dirun paralel. Jika EKS butuh output dari databases, harus serial.

Mengelola Banyak Environment dengan Satu Konfigurasi #

# Pola: Satu konfigurasi, tiga environment, backend berbeda

# environments/dev/backend.tf
terraform {
  backend "s3" {
    bucket = "terraform-state-dev"
    key    = "platform/eks/terraform.tfstate"
    region = "ap-southeast-1"
  }
}

# environments/production/backend.tf
terraform {
  backend "s3" {
    bucket = "terraform-state-production"
    key    = "platform/eks/terraform.tfstate"
    region = "ap-southeast-1"
  }
}

# Konfigurasi utama (symlink atau shared) menggunakan variable
variable "environment" {
  type = string
}

module "eks" {
  source = "../../modules/eks"

  cluster_name    = "myapp-${var.environment}"
  node_count      = var.environment == "production" ? 5 : 2
  instance_type   = var.environment == "production" ? "m5.xlarge" : "t3.medium"
}

Ringkasan #

  • Tanda konfigurasi perlu dipecah: plan butuh lebih dari 5 menit, tim sering konflik di file yang sama, ada resource “tidak boleh disentuh” campur dengan yang rutin berubah.
  • Pecah berdasarkan lifecycle dan blast radius, bukan berdasarkan tipe resource — resource yang jarang berubah dan kritis dipisah dari yang sering berubah dan tidak terlalu kritis.
  • Pola layering (foundation → platform → application) memberikan dependency yang jelas: setiap layer hanya bergantung ke layer di bawahnya, perubahan di atas tidak mempengaruhi bawah.
  • Gunakan terraform_remote_state untuk membaca output antar konfigurasi yang terpisah — tapi ingat ini menciptakan coupling antar konfigurasi.
  • Komponen di layer yang sama (EKS, database, load balancer) bisa diapply secara paralel jika tidak ada dependency antar sesama.
  • Mulai sederhana — jangan premature decompose konfigurasi sebelum ada masalah nyata. Pecah hanya ketika sinyal sudah jelas muncul.

← Sebelumnya: Lifecycle Management   Berikutnya: Performance Optimization →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact