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.
DEFAULT 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.
# 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.
resource "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]
}
}
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.