Directory Based #

Pendekatan directory based memberikan setiap environment direktori konfigurasi sendiri. Masing-masing punya backend, provider, dan state yang sepenuhnya terpisah. Ini adalah pendekatan yang lebih eksplisit dan lebih mudah di-audit dibanding workspace — kamu bisa melihat langsung di filesystem mana konfigurasi untuk environment mana. Trade-off-nya: tanpa disiplin yang baik, konfigurasi antar environment bisa perlahan menyimpang.

Struktur Dasar #

environments/
  ├── dev/
  │   ├── main.tf           ← Panggil module + resource spesifik dev
  │   ├── variables.tf      ← Variable declarations
  │   ├── terraform.tfvars  ← Nilai variable untuk dev
  │   ├── outputs.tf
  │   └── backend.tf        ← Backend config untuk dev
  ├── staging/
  │   ├── main.tf
  │   ├── variables.tf
  │   ├── terraform.tfvars  ← Nilai variable untuk staging
  │   ├── outputs.tf
  │   └── backend.tf        ← Backend config untuk staging
  └── production/
      ├── main.tf
      ├── variables.tf
      ├── terraform.tfvars  ← Nilai variable untuk production
      ├── outputs.tf
      └── backend.tf        ← Backend config untuk production
# Cara kerja: masuk ke direktori environment, lalu terraform apply

cd environments/production
terraform init
terraform apply -var-file="terraform.tfvars"

# Tidak ada risiko "lupa workspace aktif" karena direktori sudah jelas

Menghindari Duplikasi dengan Module #

Tantangan utama directory based adalah konsistensi — tiga direktori berarti tiga tempat yang bisa menyimpang. Solusinya adalah memindahkan semua logik ke module dan membuat direktori environment se-tipis mungkin.

# environments/production/main.tf — se-tipis mungkin
# Hanya konfigurasi yang memang berbeda per environment

terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "production/terraform.tfstate"
    region         = "ap-southeast-1"
    dynamodb_table = "terraform-state-lock"
    encrypt        = true
  }
}

provider "aws" {
  region = var.aws_region

  assume_role {
    role_arn = "arn:aws:iam::${var.account_id}:role/TerraformDeployRole"
  }
}

# Module yang sama dipanggil di semua environment
module "networking" {
  source = "../../modules/networking"

  environment          = var.environment
  vpc_cidr             = var.vpc_cidr
  public_subnet_count  = var.public_subnet_count
  private_subnet_count = var.private_subnet_count
}

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

  environment    = var.environment
  vpc_id         = module.networking.vpc_id
  subnet_ids     = module.networking.private_subnet_ids
  instance_type  = var.instance_type
  instance_count = var.instance_count
}

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

  environment       = var.environment
  vpc_id            = module.networking.vpc_id
  subnet_ids        = module.networking.private_subnet_ids
  instance_class    = var.db_instance_class
  multi_az          = var.db_multi_az
  backup_retention  = var.db_backup_retention
}
# environments/production/terraform.tfvars
environment  = "production"
aws_region   = "ap-southeast-1"
account_id   = "333333333"

vpc_cidr             = "10.2.0.0/16"
public_subnet_count  = 3
private_subnet_count = 3

instance_type  = "t3.medium"
instance_count = 3

db_instance_class   = "db.r5.large"
db_multi_az         = true
db_backup_retention = 30
# environments/dev/terraform.tfvars — struktur IDENTIK, nilai berbeda
environment  = "dev"
aws_region   = "ap-southeast-1"
account_id   = "111111111"

vpc_cidr             = "10.0.0.0/16"
public_subnet_count  = 1
private_subnet_count = 1

instance_type  = "t3.micro"
instance_count = 1

db_instance_class   = "db.t3.micro"
db_multi_az         = false
db_backup_retention = 0

Struktur Proyek Lengkap #

infrastructure/
  ├── modules/                ← Shared modules (sumber kebenaran tunggal)
  │   ├── networking/
  │   │   ├── main.tf
  │   │   ├── variables.tf
  │   │   └── outputs.tf
  │   ├── compute/
  │   │   └── ...
  │   └── database/
  │       └── ...
  │
  └── environments/
      ├── dev/
      │   ├── main.tf         ← Semua panggil module yang sama
      │   ├── variables.tf    ← Deklarasi variable (identik di semua env)
      │   ├── outputs.tf      ← Outputs (identik di semua env)
      │   ├── backend.tf      ← Backend config dev
      │   └── terraform.tfvars ← Nilai untuk dev
      ├── staging/
      │   ├── main.tf         ← Identik dengan dev/main.tf
      │   ├── variables.tf    ← Identik dengan dev/variables.tf
      │   ├── outputs.tf      ← Identik dengan dev/outputs.tf
      │   ├── backend.tf      ← Backend config staging
      │   └── terraform.tfvars ← Nilai untuk staging
      └── production/
          ├── main.tf         ← Identik dengan dev/main.tf
          ├── variables.tf    ← Identik dengan dev/variables.tf
          ├── outputs.tf      ← Identik dengan dev/outputs.tf
          ├── backend.tf      ← Backend config production
          └── terraform.tfvars ← Nilai untuk production

Perhatikan bahwa main.tf, variables.tf, dan outputs.tf di setiap environment identik satu sama lain — perbedaan hanya ada di terraform.tfvars dan backend.tf.


Menjaga Konsistensi Antar Environment #

Risiko terbesar directory based adalah drift — ketika seseorang menambahkan resource di production/main.tf tapi lupa menambahkannya di dev/main.tf dan staging/main.tf.

# Cara 1: Diff antara environment untuk mendeteksi perbedaan
diff environments/dev/main.tf environments/production/main.tf
diff environments/dev/variables.tf environments/production/variables.tf

# Jika ada perbedaan yang tidak disengaja, segera perbaiki

# Cara 2: Gunakan symlink untuk file yang harus identik
# (tidak umum tapi bisa dipertimbangkan)
cd environments/staging
ln -sf ../dev/main.tf main.tf
ln -sf ../dev/variables.tf variables.tf
ln -sf ../dev/outputs.tf outputs.tf
# Hanya terraform.tfvars dan backend.tf yang berbeda

# Cara 3: Buat script yang memeriksa konsistensi dalam CI
# (deteksi jika main.tf di satu env berbeda dari yang lain)
# Cara 4: Pindahkan SEMUA logik ke module
# Jika environments/*/main.tf hanya berisi pemanggilan module,
# tidak ada logik yang bisa menyimpang di sana

# environments/dev/main.tf:
module "app" {
  source = "../../modules/app"
  # variable values dari tfvars
}

# environments/production/main.tf:
module "app" {
  source = "../../modules/app"
  # variable values dari tfvars
}

# Kedua file identik — perbedaan hanya di tfvars
# → Tidak ada risiko drift logik

Perbandingan: Workspace vs Directory Based #

                    WORKSPACE           DIRECTORY BASED
──────────────────────────────────────────────────────────
Isolasi state       ✓ (terpisah)        ✓ (terpisah penuh)
Isolasi account     ✗ (tidak bisa)      ✓ (beda provider)
Isolasi akses       ✗ (sama semua)      ✓ (per direktori)
Kemudahan setup     ✓ (lebih cepat)     ✗ (lebih banyak file)
Risiko salah env    Tinggi              Rendah (direktori jelas)
Multi-region        ✗ (sulit)           ✓ (beda provider config)
Cocok untuk         Ephemeral / dev     Staging & production

Ringkasan #

  • Directory based memberikan isolasi penuh — backend terpisah, provider terpisah, account terpisah per environment.
  • Module adalah kunci konsistensi — pindahkan semua logik ke module, buat direktori environment se-tipis mungkin (hanya tfvars dan backend).
  • main.tf, variables.tf, outputs.tf harus identik di semua environment — perbedaan hanya di terraform.tfvars dan backend.tf.
  • Risiko utama adalah drift — gunakan diff reguler atau symlink untuk memastikan file yang seharusnya identik tidak menyimpang.
  • Lebih aman dari workspace untuk production — tidak ada risiko “lupa workspace aktif”, akses bisa dikontrol per direktori.
  • Pilih directory based ketika butuh multi-account, multi-region, atau isolasi akses per environment. Pilih workspace untuk ephemeral environment.

← Sebelumnya: Workspace   Berikutnya: Apa itu Multi Provider? →

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