Lifecycle Management #

Membuat resource dengan Terraform itu mudah. Yang lebih menantang adalah mengelolanya setelah dibuat — terutama ketika perlu diubah, dipindahkan, atau dihapus tanpa menyebabkan gangguan pada infrastruktur yang sedang berjalan. Terraform menyediakan beberapa mekanisme untuk ini: lifecycle block yang mengontrol perilaku resource, moved block untuk refactoring tanpa destroy, dan removed block untuk decommission yang terkontrol. Memahami alat-alat ini membuat kamu bisa melakukan perubahan besar pada konfigurasi dengan aman.

Lifecycle Block: Kontrol Perilaku Resource #

# Empat opsi lifecycle yang paling berguna

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type

  lifecycle {
    # 1. create_before_destroy
    # Buat resource baru SEBELUM menghapus yang lama
    # Berguna untuk resource yang tidak boleh ada jedanya
    create_before_destroy = true

    # 2. prevent_destroy
    # Terraform error jika ada yang mencoba destroy resource ini
    # Perlindungan untuk resource kritikal (database production, dll.)
    prevent_destroy = true

    # 3. ignore_changes
    # Abaikan perubahan pada atribut tertentu
    # Berguna jika atribut diubah di luar Terraform
    ignore_changes = [
      tags["LastModified"],
      user_data,
    ]

    # 4. replace_triggered_by (Terraform 1.2+)
    # Trigger replacement saat resource lain berubah
    replace_triggered_by = [
      aws_launch_template.web.id
    ]
  }
}

create_before_destroy: Zero-Downtime Replacement #

# Tanpa create_before_destroy (default):
# 1. Hapus resource lama
# 2. Buat resource baru
# → Ada jeda di mana tidak ada resource yang jalan (downtime)

# ANTI-PATTERN: Resource yang butuh high availability tanpa create_before_destroy
resource "aws_lb_target_group" "app" {
  name     = "production-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = var.vpc_id
  # Jika nama TG perlu diubah → destroy dulu, baru create → downtime
}

# BENAR: Dengan create_before_destroy dan name_prefix
resource "aws_lb_target_group" "app" {
  name_prefix = "app-"    # AWS generate suffix unik
  port        = 80
  protocol    = "HTTP"
  vpc_id      = var.vpc_id

  lifecycle {
    create_before_destroy = true
    # 1. Buat TG baru dengan nama baru
    # 2. Pindahkan listener ke TG baru
    # 3. Hapus TG lama
    # → Tidak ada downtime
  }
}

moved Block: Refactoring Tanpa Destroy #

moved block adalah cara yang tepat untuk mengubah address resource di state tanpa menghapus dan membuat ulang resource di cloud. Berguna saat refactoring konfigurasi — rename resource, pindah ke module, atau reorganisasi struktur.

# Skenario 1: Rename resource
# Sebelum: resource "aws_instance" "server"
# Sesudah: resource "aws_instance" "web_server"

moved {
  from = aws_instance.server
  to   = aws_instance.web_server
}

# Terraform akan memperbarui state (rename address)
# tanpa menghapus dan membuat ulang instance di AWS
# Skenario 2: Pindah resource ke dalam module
# Sebelum: resource "aws_vpc" "main" di root module
# Sesudah: dipindah ke module "networking"

moved {
  from = aws_vpc.main
  to   = module.networking.aws_vpc.main
}

# terraform plan akan menampilkan:
# # aws_vpc.main has moved to module.networking.aws_vpc.main
# → Tidak ada resource yang dihapus atau dibuat ulang
# Skenario 3: Pindah dari count ke for_each
# Sebelum: resource "aws_subnet" "public" count = 3
# Sesudah: resource "aws_subnet" "public" for_each

moved {
  from = aws_subnet.public[0]
  to   = aws_subnet.public["ap-southeast-1a"]
}

moved {
  from = aws_subnet.public[1]
  to   = aws_subnet.public["ap-southeast-1b"]
}

moved {
  from = aws_subnet.public[2]
  to   = aws_subnet.public["ap-southeast-1c"]
}
moved block bisa dihapus setelah semua environment sudah di-apply dan state sudah diperbarui. Tapi sebaiknya biarkan beberapa sprint sebelum dihapus agar environment yang jarang di-apply juga kebagian.

removed Block: Decommission yang Terkontrol #

removed block (Terraform 1.7+) memungkinkan kamu menghapus resource dari konfigurasi dan state tanpa menghapus resource aktual di cloud — berguna untuk “melepaskan” resource dari kontrol Terraform tanpa menghancurkannya.

# Skenario: Database lama tidak lagi dikelola Terraform
# tapi tidak mau dihapus dari cloud (masih ada data)

removed {
  from = aws_db_instance.legacy

  lifecycle {
    destroy = false  # Jangan hapus dari cloud, hanya hapus dari state
  }
}

# Setelah apply:
# - Resource dihapus dari state Terraform
# - Resource TETAP ada di AWS
# - Terraform tidak lagi mengelola resource ini
# Berbeda dengan destroy = true (untuk resource yang memang perlu dihapus):
removed {
  from = aws_instance.deprecated_worker

  lifecycle {
    destroy = true  # Hapus dari state DAN dari cloud
  }
}

Mengelola Breaking Change di Module #

Ketika modul yang digunakan banyak tempat perlu perubahan breaking, ada cara yang lebih aman dari “langsung ubah dan semua pemanggilnya pecah”.

# Strategi: Backward compatibility dengan deprecation period

# modules/networking/main.tf — tambahkan alias untuk input yang berubah nama

variable "vpc_cidr_block" {
  description = "CIDR block untuk VPC"
  type        = string
}

# Variable lama yang sudah deprecated — masih ada untuk backward compatibility
variable "cidr_block" {
  description = "DEPRECATED: Gunakan vpc_cidr_block. Akan dihapus di v3.0"
  type        = string
  default     = null
}

locals {
  # Gunakan yang baru jika ada, fallback ke yang lama
  vpc_cidr = coalesce(var.vpc_cidr_block, var.cidr_block)
}

resource "aws_vpc" "main" {
  cidr_block = local.vpc_cidr
}
TIMELINE DEPRECATION YANG AMAN:
  v2.0 — Variable baru ditambahkan, variable lama masih ada
  v2.1 — Warning ditampilkan jika masih menggunakan variable lama
  v3.0 — Variable lama dihapus (di CHANGELOG dan README disebutkan)

Pemanggilnya punya waktu untuk migrasi di antara versi major.

Kapan State Surgery Dibutuhkan #

Ada situasi di mana manipulasi state manual diperlukan — ini harus jadi pilihan terakhir, bukan default.

# State surgery — gunakan dengan sangat hati-hati

# Pindahkan resource antar state (jika moved block tidak cukup)
terraform state mv \
  -state=old/terraform.tfstate \
  -state-out=new/terraform.tfstate \
  aws_vpc.main \
  aws_vpc.main

# Hapus resource dari state tanpa menghapus dari cloud
terraform state rm aws_instance.orphaned

# Import resource yang sudah ada ke state
terraform import aws_instance.existing i-0abcdef1234567890

# SELALU backup sebelum state surgery
terraform state pull > backup-$(date +%Y%m%d-%H%M%S).tfstate

# Verifikasi setelah state surgery
terraform plan  # Harusnya "No changes" jika state sudah benar

Ringkasan #

  • create_before_destroy penting untuk resource high-availability — pastikan terpasang pada load balancer, target group, dan resource yang tidak boleh ada jedanya saat diganti.
  • prevent_destroy sebagai perlindungan terakhir untuk resource kritikal — Terraform error jika ada plan yang akan menghapus resource ini.
  • moved block adalah cara yang tepat untuk refactoring konfigurasi — rename resource, pindah ke module, atau ganti dari count ke for_each tanpa destroy.
  • removed block untuk decommission yang terkontrol — bisa memilih apakah resource dihapus dari cloud atau hanya dilepaskan dari kontrol Terraform.
  • Breaking change di module butuh deprecation period — tambahkan variable baru sambil jaga yang lama, beri waktu pemanggilnya untuk migrasi sebelum variable lama dihapus.
  • State surgery (terraform state mv/rm) adalah pilihan terakhir — selalu backup state sebelum, verifikasi dengan terraform plan sesudah.

← Sebelumnya: Monorepo vs Multirepo   Berikutnya: Scale Terraform →

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