Idempotency #
Idempotency adalah properti di mana menjalankan operasi yang sama berkali-kali menghasilkan hasil yang sama seperti menjalankannya sekali. Di Terraform, ini berarti kamu bisa menjalankan terraform apply berulang kali tanpa khawatir akan membuat resource duplikat, mengubah sesuatu yang tidak perlu, atau merusak kondisi yang sudah benar.
Ini bukan kebetulan — idempotency adalah hasil desain Terraform yang disengaja melalui tiga mekanisme bekerja bersama: state, plan, dan refresh dari kondisi aktual. Memahaminya membantumu mengenali kapan konfigurasi atau penggunaan Terraform menyimpang dari prinsip ini.
Bagaimana Idempotency Bekerja #
flowchart TD
A["terraform apply\n(dijalankan berkali-kali)"] --> B["1. Baca state\nApa yang sudah ada?"]
B --> C["2. Baca konfigurasi\nApa yang seharusnya ada?"]
C --> D["3. Refresh dari API\nApa kondisi aktual?"]
D --> E{"Bandingkan:\nstate vs konfigurasi\nvs kondisi aktual"}
E -->|"Sama semua\n(state ≈ config ≈ actual)"| F["✅ 'No changes'\nTidak ada operasi"]
E -->|"Ada perbedaan"| G["🔄 Hanya perbedaan\nyang dieksekusi"]
F --> H["Apply kedua, ketiga,\nkeempat...\nhasilnya SELALU sama"]
G --> I["Perbaiki perbedaan\nState diupdate"]
style F fill:#e8f5e9,stroke:#2e7d32
style G fill:#e3f2fd,stroke:#1565c0
style H fill:#e8f5e9,stroke:#2e7d32CARA IDEMPOTENCY BEKERJA:
Terraform apply (pertama kali):
State: kosong
Konfigurasi: 3 resource
Plan: +3 create
Hasil: 3 resource dibuat, state diupdate
Terraform apply (kedua kali, tanpa perubahan):
State: 3 resource
Konfigurasi: 3 resource (sama)
Refresh: kondisi aktual = state = konfigurasi
Plan: "No changes. Your infrastructure matches the configuration."
Hasil: tidak ada yang berubah ✅
Terraform apply (ketiga, keempat, kelima...):
Sama dengan kedua kali — tidak ada perubahan ✅
| Langkah | Mekanisme | Fungsi |
|---|---|---|
| 1. Baca state | State file | Mengetahui apa yang sudah ada di cloud |
| 2. Baca konfigurasi | File .tf | Mengetahui apa yang seharusnya ada |
| 3. Refresh | API cloud | Memverifikasi kondisi aktual di cloud |
| 4. Bandingkan | Diff engine | Menemukan perbedaan antara ketiganya |
| 5. Eksekusi | Apply engine | Hanya menjalankan perubahan yang diperlukan |
Perbandingan dengan Pendekatan Non-Idempoten #
flowchart TD
subgraph "Script Bash (Non-Idempoten)"
BA["chmod +x deploy.sh\n& ./deploy.sh"] --> BB["Pertama kali:\nberhasil ✅"]
BA --> BC["Kedua kali:\nERROR atau\nduplikat ❌"]
BA --> BD["Butuh conditional logic:\nif ! exists, then create"]
end
subgraph "Terraform (Idempoten)"
TA["terraform apply"] --> TB["Pertama kali:\nberhasil ✅"]
TA --> TC["Kedua kali:\nNo changes ✅"]
TA --> TD["Ketiga kali:\nNo changes ✅"]
end
style BB fill:#e8f5e9,stroke:#2e7d32
style BC fill:#ffebee,stroke:#c62828
style BD fill:#fff3e0,stroke:#e65100
style TB fill:#e8f5e9,stroke:#2e7d32
style TC fill:#e8f5e9,stroke:#2e7d32
style TD fill:#e8f5e9,stroke:#2e7d32# ❌ ANTI-PATTERN: Script bash — tidak idempoten
#!/bin/bash
# Jalankan pertama kali: berhasil
aws ec2 create-security-group \
--group-name "web-sg" \
--description "Web security group"
# Jalankan kedua kali: ERROR
# An error occurred (InvalidGroup.Duplicate):
# The security group 'web-sg' already exists
# Butuh conditional logic ekstra untuk membuatnya idempoten:
if ! aws ec2 describe-security-groups --group-names "web-sg" 2>/dev/null; then
aws ec2 create-security-group --group-name "web-sg" ...
fi
# Dan ini masih tidak menangani race condition, update, dll.
# ✅ BENAR: Terraform — idempoten secara built-in
resource "aws_security_group" "web" {
name = "web-sg"
description = "Web security group"
}
# Jalankan 100 kali → hasilnya SELALU sama
# Terraform tahu apakah security group sudah ada
# dan hanya bertindak jika ada perbedaan
| Aspek | Script Bash | Terraform |
|---|---|---|
| Jalankan 2x | Error atau duplikat | “No changes” |
| Deteksi existing resource | Manual (if/else) | Otomatis (state + refresh) |
| Update yang berubah | Manual (grep, diff) | Otomatis (plan engine) |
| Handle race condition | Susah | Built-in (state locking) |
| Kode tambahan | Banyak conditional logic | Tidak perlu |
Kasus yang Bisa Merusak Idempotency #
Meskipun Terraform dirancang untuk idempoten, ada beberapa pola yang bisa merusaknya. Kenali pola ini agar konfigurasimu tetap idempoten.
flowchart TD
A["Kasus yang merusak\nidempotency"] --> B["timestamp() / uuid()\ndalam konfigurasi"]
A --> C["Provisioner yang\nnon-idempoten"]
A --> D["Resource dikelola\noleh dua tool"]
A --> E["Nilai yang berubah\ntiap plan/apply"]
B --> B1["Nilai berbeda setiap apply\n→ update setiap kali"]
C --> C1["Script diulang setiap\nresource di-replace"]
D --> D1["Tool A ubah, Terraform revert\nTool A ubah lagi, dst"]
E --> E1["random_id, random_password\ntanpa lifecycle ignore"]
B1 --> F["Solusi: Gunakan\nnilai stabil atau\nlifecycle ignore_changes"]
C1 --> F
D1 --> G["Solusi: Satu tool\nsaja yang manage"]
E1 --> F
style B fill:#ffebee,stroke:#c62828
style C fill:#ffebee,stroke:#c62828
style D fill:#ffebee,stroke:#c62828
style E fill:#ffebee,stroke:#c62828
style F fill:#e8f5e9,stroke:#2e7d32
style G fill:#e8f5e9,stroke:#2e7d32Kasus 1: timestamp() atau uuid() dalam Konfigurasi
#
# ❌ ANTI-PATTERN: Setiap apply menghasilkan nilai berbeda
resource "aws_s3_bucket_object" "config" {
bucket = aws_s3_bucket.main.id
key = "config.json"
content = jsonencode({
generated_at = timestamp() # ✗ Berbeda setiap apply!
# Ini menyebabkan resource diupdate SETIAP kali apply dijalankan
})
}
# ✅ BENAR: Gunakan nilai yang stabil
resource "aws_s3_bucket_object" "config" {
bucket = aws_s3_bucket.main.id
key = "config.json"
content = jsonencode({
environment = var.environment # Hanya berubah jika variable berubah
version = var.app_version # Hanya berubah jika variable berubah
})
}
Kasus 2: Provisioner yang Tidak Idempoten #
# ❌ ANTI-PATTERN: Provisioner dijalankan setiap kali resource "baru"
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = "t3.micro"
provisioner "remote-exec" {
inline = [
"echo 'Server $(hostname) started at $(date)' >> /var/log/deploy.log"
# timestamp di sini akan berbeda setiap apply
]
}
}
# ✅ BENAR: Gunakan user_data untuk konfigurasi initial
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = "t3.micro"
user_data = file("scripts/setup.sh") # Dijalankan hanya sekali saat launch
}
Kasus 3: Resource Dikelola oleh Dua Tool #
flowchart LR
A["Terraform\nmanage resource"] -->|"Update ke\ndesired state"| B["Cloud Resource"]
C["Tool lain\n(kubectl, console)"] -->|"Update ke\nstate berbeda"| B
B -->|"Terraform detect\ndrift"| A
B -->|"Tool lain detect\ndrift"| C
A --> D["Infinite loop:\nTerraform ↔ Tool lain\nsaling menimpa"]
style D fill:#ffebee,stroke:#c62828| Kasus | Penyebab | Solusi |
|---|---|---|
timestamp() / uuid() | Nilai berbeda setiap apply | Gunakan nilai stabil atau ignore_changes |
| Provisioner non-idempoten | Script diulang setiap replace | Gunakan user_data atau Ansible |
| Dual management | Dua tool manage resource sama | Satu tool saja yang manage |
random_id / random_password | Nilai regenerasi | lifecycle { ignore_changes = [...] } |
file() pada file yang berubah | File konten berubah | Pastikan file stabil atau pakai filemd5 |
Memverifikasi Idempotency Konfigurasimu #
Ada cara sederhana untuk memverifikasi bahwa konfigurasimu benar-benar idempoten.
flowchart TD
A["Tes Idempotency"] --> B["1. terraform apply\n(pertama kali)"]
B --> C["2. terraform plan\n(tanpa ubah config)"]
C --> D{"Plan menunjukkan\nperubahan?"}
D -->|"Tidak: No changes"| E["✅ Idempoten!\nKonfigurasi aman"]
D -->|"Ya: ada perubahan"| F["❌ Tidak idempoten!\nCari penyebab"]
F --> G["Cek timestamp(),\nuuid(), random value,\natau external changes"]
style E fill:#e8f5e9,stroke:#2e7d32
style F fill:#ffebee,stroke:#c62828# Tes idempotency manual:
# 1. Apply pertama kali
terraform apply -auto-approve
# 2. Cek tanpa mengubah apapun (lebih cepat dari apply)
terraform plan
# 3. Cek output
# Jika idempoten:
# "No changes. Your infrastructure matches the configuration."
#
# Jika TIDAK idempoten:
# Plan: 0 to add, 1 to change, 0 to destroy.
# → Ada perubahan yang muncul tanpa kamu mengubah config
# → Cari penyebab: timestamp, random value, atau external change
# Alternatif: Apply kedua kali untuk verifikasi
terraform apply -auto-approve
# Output yang diinginkan:
# Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
| Langkah | Perintah | Hasil Idempoten | Hasil Tidak Idempoten |
|---|---|---|---|
| 1. Apply pertama | terraform apply | Resource dibuat | Resource dibuat |
| 2. Cek | terraform plan | “No changes” | Ada perubahan |
| 3. Apply kedua | terraform apply | 0 added, 0 changed | Ada change yang tidak diharapkan |
Idempotency dan Immutable Infrastructure #
Idempotency bukan berarti resource tidak pernah berubah — ia berarti hasil dari menjalankan konfigurasi yang sama selalu konsisten. Ini sejalan dengan prinsip immutable infrastructure.
flowchart TD
subgraph "Mutable (Tradisional)"
M1["Server dibuat"] --> M2["Dikonfigurasi ulang\nberulang kali"]
M2 --> M3["Kondisi berubah\ntanpa jejak"]
M3 --> M4["'Configuration drift'\nSulit diprediksi"]
end
subgraph "Immutable (Modern)"
I1["Server dibuat\ndengan config A"] --> I2["Butuh config B?"]
I2 --> I3["Server lama dihapus\nServer baru dibuat\ndengan config B"]
I3 --> I4["Kondisi SELALU\nbisa diprediksi"]
end
style M4 fill:#ffebee,stroke:#c62828
style I4 fill:#e8f5e9,stroke:#2e7d32| Aspek | Mutable | Immutable |
|---|---|---|
| Update | Ubah di tempat | Hapus + buat baru |
| State tracking | Sulit | Mudah (selalu fresh) |
| Rollout risk | Perubahan tersembunyi | Jelas terlihat |
| Terraform action | update in-place (~) | destroy and recreate (-/+) |
| Idempotency | Perlu effort ekstra | Natural |
TERRAFORM MENDUKUNG KEDUANYA:
- Update in-place (~): mutable, tapi terkontrol
- Destroy and recreate (-/+): immutable approach
- Pilihan tergantung pada jenis resource dan kebutuhan
- Lifecycle create_before_destroy: transisi yang lebih aman
Ringkasan #
- Idempotency Terraform bersifat built-in melalui tiga mekanisme: state, plan, dan refresh dari kondisi aktual.
- “No changes” di plan/apply kedua adalah tanda bahwa konfigurasimu idempoten — ini adalah kondisi yang diinginkan.
- Hindari
timestamp(),uuid(), atau random value dalam konfigurasi resource — ini merusak idempotency karena nilainya berubah setiap apply.- Provisioner tidak idempoten secara natural — pertimbangkan
user_dataatau Ansible sebagai alternatif.- Satu tool per resource — jangan kelola resource yang sama dengan Terraform dan tool lain secara bersamaan.
- Tes idempotency dengan menjalankan
terraform plansetelah apply pertama — jika masih ada perubahan, ada sesuatu yang perlu diperbaiki.- Idempotency adalah fondasi kepercayaan terhadap konfigurasi Terraform — memungkinkan safe re-run di CI/CD, safe retry setelah kegagalan, dan safe collaboration antar tim.
← Sebelumnya: Drift Detection Berikutnya: Apa itu Resource? →