Lifecycle #
Secara default, Terraform mengikuti siklus sederhana untuk setiap resource: buat jika belum ada, ubah jika berbeda, hapus jika tidak lagi dikonfigurasi. Tapi default ini tidak selalu tepat untuk semua jenis resource. Database production tidak boleh dihapus karena kesalahan ketik. Load balancer tidak boleh down sedetikpun saat update. Beberapa atribut dikelola oleh sistem lain dan tidak boleh ditimpa Terraform. Lifecycle block memberimu kontrol untuk menangani semua kasus ini.
Default Lifecycle Terraform #
Sebelum melihat cara mengkustomisasi lifecycle, penting untuk memahami perilaku defaultnya.
flowchart TD
subgraph "Default Replace"
D1["Resource lama\nada di state"] --> D2["1. DESTROY\nresource lama"]
D2 --> D3["2. CREATE\nresource baru"]
D3 --> D4["Resource tidak ada\nselama proses = DOWNTIME"]
end
subgraph "create_before_destroy"
C1["Resource lama\nada di state"] --> C2["1. CREATE\nresource baru"]
C2 --> C3["2. DESTROY\nresource lama"]
C3 --> C4["Selalu ada resource\nyang aktif = ZERO DOWNTIME"]
end
style D4 fill:#ffebee,stroke:#c62828
style C4 fill:#e8f5e9,stroke:#2e7d32DEFAULT LIFECYCLE UNTUK SETIAP RESOURCE:
CREATE → Jika resource belum ada di state
UPDATE → Jika resource ada tapi konfigurasi berbeda
(dua kemungkinan: update in-place atau replace)
DESTROY → Jika resource ada di state tapi tidak lagi di konfigurasi
Urutan saat perlu replace (destroy + create):
1. Destroy resource lama
2. Create resource baru
Ini berarti ada periode di mana resource tidak ada sama sekali
— berpotensi menyebabkan downtime untuk resource yang aktif melayani traffic.
create_before_destroy #
create_before_destroy membalik urutan operasi replace: buat dulu resource baru, baru hapus yang lama. Ini meminimalkan downtime untuk resource yang tidak boleh down.
# SKENARIO: Update AMI pada instance yang melayani traffic production
# ANTI-PATTERN: Default behavior — downtime saat replace
resource "aws_instance" "web" {
ami = var.ami_id # Ubah AMI → forces replacement
instance_type = "t3.micro"
# Urutan default:
# 1. Destroy instance lama → traffic mati
# 2. Create instance baru → traffic hidup kembali
# Downtime: ~20-30 detik
}
# BENAR: create_before_destroy — zero downtime replace
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = "t3.micro"
lifecycle {
create_before_destroy = true
# Urutan baru:
# 1. Create instance baru → running
# 2. Destroy instance lama → tidak ada downtime
# (pastikan ada mekanisme untuk shift traffic dulu,
# misal: load balancer attachment)
}
}
# create_before_destroy sangat berguna untuk SSL certificate
resource "aws_acm_certificate" "main" {
domain_name = var.domain_name
validation_method = "DNS"
lifecycle {
create_before_destroy = true
# Sertifikat baru dibuat dan divalidasi sebelum yang lama dihapus
# Tidak ada periode di mana domain tidak punya sertifikat valid
}
}
prevent_destroy #
prevent_destroy membuat Terraform menolak menghapus resource — apply akan error sebelum operasi destroy sempat berjalan. Ini adalah lapisan perlindungan terakhir untuk resource kritis.
flowchart TD
A["terraform apply\nmendeteksi destroy"] --> B{"prevent_destroy\n= true?"}
B -->|"Ya"| C["❌ ERROR\nResource cannot\nbe destroyed"]
B -->|"Tidak"| D["✅ Destroy\nberjalan normal"]
style C fill:#ffebee,stroke:#c62828
style D fill:#e8f5e9,stroke:#2e7d32# Resource production yang tidak boleh dihapus secara tidak sengaja
resource "aws_rds_instance" "production" {
identifier = "production-db"
engine = "postgres"
engine_version = "15.3"
instance_class = "db.t3.medium"
allocated_storage = 100
storage_encrypted = true
lifecycle {
prevent_destroy = true
}
}
# Apa yang terjadi jika ada yang mencoba terraform destroy:
# ╷
# │ Error: Instance cannot be destroyed
# │
# │ on main.tf line 1, in resource "aws_rds_instance" "production":
# │ 1: resource "aws_rds_instance" "production" {
# │
# │ Resource aws_rds_instance.production has lifecycle.prevent_destroy
# │ set to true. To allow this object to be destroyed, remove or disable
# │ this attribute.
# ╵
prevent_destroyhanya melindungi dari operasi yang diinisiasi Terraform. Ia tidak mencegah penghapusan langsung dari console AWS atau CLI. Untuk perlindungan penuh, gunakan juga termination protection bawaan resource (misalnyadeletion_protection = truepada RDS) dan IAM policy yang membatasi akses delete.
ignore_changes #
ignore_changes memberitahu Terraform untuk mengabaikan perbedaan pada atribut tertentu — tidak akan memicu update meskipun nilainya berubah. Berguna untuk atribut yang dikelola di luar Terraform.
flowchart TD
A["Perubahan atribut\nterdeteksi di plan"] --> B{"Ada di\nignore_changes?"}
B -->|"Ya"| C["⬜ TIDAK ADA\naksi — abaikan"]
B -->|"Tidak"| D["Tergantung\nsifat atribut"]
D --> E["~ Update in-place\natau -/+ Replace"]
style C fill:#e8f5e9,stroke:#2e7d32
style E fill:#e3f2fd,stroke:#1565c0resource "aws_autoscaling_group" "web" {
name = "web-asg"
min_size = 2
max_size = 10
desired_capacity = 2
launch_template {
id = aws_launch_template.web.id
version = "$Latest"
}
lifecycle {
ignore_changes = [
# desired_capacity dikelola oleh auto scaling policy — abaikan
desired_capacity,
# tag "LastDeployedAt" diupdate oleh deployment pipeline — abaikan
tag,
]
}
}
# ignore_changes = all — abaikan SEMUA perubahan pada atribut resource
# Gunakan dengan sangat hati-hati — ini berarti Terraform tidak akan
# pernah mengupdate resource ini setelah dibuat
resource "aws_instance" "immutable" {
ami = var.ami_id
instance_type = "t3.micro"
lifecycle {
ignore_changes = all
# Berguna untuk resource "immutable" yang hanya dibuat sekali
# dan tidak pernah diubah — perubahan konfigurasi hanya berlaku
# untuk instance baru, bukan yang sudah ada
}
}
replace_triggered_by #
replace_triggered_by memaksa resource untuk di-replace ketika resource atau atribut lain berubah — meskipun tidak ada perubahan langsung pada resource itu sendiri.
# SKENARIO: Instance harus di-replace setiap kali launch template berubah
resource "aws_launch_template" "web" {
name_prefix = "web-"
image_id = var.ami_id
instance_type = "t3.micro"
}
resource "aws_instance" "web" {
# Instance ini tidak langsung bergantung pada launch template versi,
# tapi kita ingin ia di-replace setiap kali launch template berubah
launch_template {
id = aws_launch_template.web.id
version = aws_launch_template.web.latest_version
}
lifecycle {
replace_triggered_by = [
aws_launch_template.web # Replace instance jika launch template berubah
]
}
}
Kombinasi Lifecycle Rules #
Lifecycle rules bisa dikombinasikan sesuai kebutuhan.
resource "aws_db_instance" "main" {
identifier = "app-database"
engine = "mysql"
instance_class = "db.t3.medium"
allocated_storage = 50
storage_encrypted = true
# Password dirotasi oleh secrets manager — jangan timpa
password = data.aws_secretsmanager_secret_version.db_password.secret_string
lifecycle {
# Buat DB baru sebelum hapus yang lama saat replace
create_before_destroy = true
# Lindungi dari destroy tidak sengaja
prevent_destroy = true
# Abaikan perubahan password — dikelola oleh secrets manager
ignore_changes = [password]
}
}
| Lifecycle Rule | Fungsi | Kapan Digunakan |
|---|---|---|
create_before_destroy | Buat baru dulu, hapus lama setelahnya | Server, certificate, load balancer |
prevent_destroy | Tolak operasi destroy | Production database, stateful resource |
ignore_changes | Abaikan perubahan atribut tertentu | Atribut dikelola di luar Terraform |
ignore_changes = all | Abaikan semua perubahan | Resource immutable, hanya dibuat sekali |
replace_triggered_by | Force replace saat resource lain berubah | Sinkronisasi versi antar resource |
Lifecycle Rules dalam Produksi #
Lifecycle rules sangat penting untuk mencegah kehilangan data di production.
# Database: prevent_destroy untuk mencegah penghapusan tidak sengaja
resource "aws_db_instance" "main" {
identifier = "production-db"
engine = "postgres"
instance_class = "db.t3.medium"
lifecycle {
prevent_destroy = true
# terraform apply yang mencoba destroy → ERROR
# Harus hapus lifecycle ini dulu (dengan review) baru bisa destroy
}
}
# Instance: create_before_destroy untuk zero-downtime
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
lifecycle {
create_before_destroy = true
# Instance baru dibuat DULU, baru yang lama di-destroy
# Menghindari downtime
}
}
flowchart TD
subgraph NORMAL["Normal Replace"]
N1["Destroy lama"] --> N2["Buat baru"]
N3["⚠️ Downtime!"]
end
subgraph CBD["create_before_destroy"]
C1["Buat baru"] --> C2["Destroy lama"]
C3["✅ Zero downtime"]
end
style N3 fill:#ffebee,stroke:#c62828
style C3 fill:#e8f5e9,stroke:#2e7d32Lifecycle Edge Cases #
# Edge Case 1: prevent_destroy dengan import
# Jika kamu import resource yang sudah punya prevent_destroy:
terraform import aws_db_instance.main i-12345
# Import berhasil, tapi future destroy akan diblokir
# Edge Case 2: create_before_destroy dengan force-new
# Jika attribute berubah yang memaksa resource baru:
# 1. Terraform buat instance baru
# 2. Tunggu instance baru "selesai"
# 3. Hapus instance lama
# Tapi: dependency di instance lama bisa bermasalah
# Edge Case 3: ignore_changes yang terlalu luas
lifecycle {
ignore_changes = all # IGNORE SEMUA perubahan
# Hanya gunakan untuk resource yang Terraform manage-nya benar-benar selesai
}
Lifecycle Best Practices #
# BEST PRACTICE: Kapan menggunakan setiap lifecycle rule
# prevent_destroy: Resource yang tidak boleh hilang
# - Database production
# - S3 bucket dengan data penting
# - KMS key (encrypted data jadi tidak bisa diakses)
# - DNS zones
resource "aws_db_instance" "production" {
lifecycle {
prevent_destroy = true
}
}
# create_before_destroy: Zero-downtime replacement
# - EC2 instances behind load balancer
# - Lambda functions
# - CloudWatch alarms
resource "aws_instance" "web" {
lifecycle {
create_before_destroy = true
}
}
# ignore_changes: Abaikan perubahan tertentu
# - Auto-scaling group desired capacity
# - External monitoring yang mengubah tag
resource "aws_autoscaling_group" "web" {
desired_capacity = 2
lifecycle {
ignore_changes = [desired_capacity]
}
}
Ringkasan #
create_before_destroy = trueuntuk resource yang tidak boleh down — buat yang baru dulu sebelum hapus yang lama. Sangat penting untuk server, certificate, dan load balancer.prevent_destroy = trueuntuk resource kritis seperti production database — Terraform akan error sebelum sempat menghapusnya.prevent_destroytidak melindungi dari penghapusan di luar Terraform — kombinasikan dengan termination protection bawaan resource dan IAM policy.ignore_changesuntuk atribut yang dikelola di luar Terraform —desired_capacitypada ASG, password yang dirotasi, tag yang diupdate pipeline.ignore_changes = alluntuk resource benar-benar immutable — gunakan dengan sangat hati-hati, Terraform tidak akan pernah mengupdate resource ini.replace_triggered_byuntuk memaksa replace berdasarkan perubahan resource lain yang tidak terdeteksi secara otomatis.