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.tfharus identik di semua environment — perbedaan hanya diterraform.tfvarsdanbackend.tf.- Risiko utama adalah drift — gunakan
diffreguler 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? →