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:#2e7d32
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.

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_destroy hanya 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 (misalnya deletion_protection = true pada 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:#1565c0
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]
  }
}
Lifecycle RuleFungsiKapan Digunakan
create_before_destroyBuat baru dulu, hapus lama setelahnyaServer, certificate, load balancer
prevent_destroyTolak operasi destroyProduction database, stateful resource
ignore_changesAbaikan perubahan atribut tertentuAtribut dikelola di luar Terraform
ignore_changes = allAbaikan semua perubahanResource immutable, hanya dibuat sekali
replace_triggered_byForce replace saat resource lain berubahSinkronisasi 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:#2e7d32

Lifecycle 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 = true untuk resource yang tidak boleh down — buat yang baru dulu sebelum hapus yang lama. Sangat penting untuk server, certificate, dan load balancer.
  • prevent_destroy = true untuk resource kritis seperti production database — Terraform akan error sebelum sempat menghapusnya.
  • prevent_destroy tidak melindungi dari penghapusan di luar Terraform — kombinasikan dengan termination protection bawaan resource dan IAM policy.
  • ignore_changes untuk atribut yang dikelola di luar Terraform — desired_capacity pada ASG, password yang dirotasi, tag yang diupdate pipeline.
  • ignore_changes = all untuk resource benar-benar immutable — gunakan dengan sangat hati-hati, Terraform tidak akan pernah mengupdate resource ini.
  • replace_triggered_by untuk memaksa replace berdasarkan perubahan resource lain yang tidak terdeteksi secara otomatis.

← Sebelumnya: Dependency   Berikutnya: Locking →

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