Operation #
Setiap resource dalam konfigurasi Terraform akan mengalami salah satu dari lima operasi: create, read, update, delete, atau replace. Terraform memutuskan operasi mana yang tepat berdasarkan perbandingan antara konfigurasi, state, dan kondisi aktual di cloud. Memahami logika di balik keputusan ini — termasuk mengapa kadang update bisa berubah jadi replace — membantumu menulis konfigurasi yang lebih terprediksi dan menghindari kejutan saat apply.
Lima Operasi Resource #
flowchart TD
A["Konfigurasi .tf\nvs State\nvs Kondisi aktual"] --> B{"Resource\nada di mana?"}
B -->|"Ada di config,\ntidak di state"| C["+ CREATE\nResource baru"]
B -->|"Ada di config\ndan state"| D{"Ada perubahan?"}
B -->|"Ada di state,\ntidak di config"| E["- DELETE\nHapus resource"]
B -->|"Data source"| F["<= READ\nQuery data"]
D -->|"Ada, bisa\nin-place"| G["~ UPDATE\nModifikasi"]
D -->|"Ada, tidak\nbisa in-place"| H["-/+ REPLACE\nDestroy + Create"]
style C fill:#e8f5e9,stroke:#2e7d32
style D fill:#e3f2fd,stroke:#1565c0
style E fill:#ffebee,stroke:#c62828
style F fill:#fff3e0,stroke:#e65100
style G fill:#e3f2fd,stroke:#1565c0
style H fill:#fff3e0,stroke:#e65100CREATE (+)
Kondisi: Resource ada di konfigurasi, tidak ada di state
Tindakan: Terraform memanggil API provider untuk membuat resource baru
Simbol di plan: +
READ (<=)
Kondisi: Data source dibaca
Tindakan: Terraform query data dari provider, tidak ada perubahan infrastruktur
Simbol di plan: <=
UPDATE IN-PLACE (~)
Kondisi: Resource ada di konfigurasi dan state, tapi konfigurasi berbeda
DAN provider mendukung update in-place untuk atribut yang berubah
Tindakan: Terraform memanggil API update — resource tetap running
Simbol di plan: ~
DELETE (-)
Kondisi: Resource ada di state, tidak ada di konfigurasi
Tindakan: Terraform memanggil API provider untuk menghapus resource
Simbol di plan: -
REPLACE (-/+)
Kondisi: Resource perlu diupdate TAPI perubahan tersebut
tidak bisa dilakukan in-place (provider tidak mendukung)
Tindakan: Delete resource lama, create resource baru
Simbol di plan: -/+ (atau +/- jika create_before_destroy aktif)
| Operasi | Simbol | Resource di Config? | Resource di State? | Contoh Aksi |
|---|---|---|---|---|
| Create | + | ✅ | ❌ | Buat EC2 baru |
| Read | <= | — (data) | — | Baca AMI |
| Update in-place | ~ | ✅ | ✅ | Ubah tag |
| Delete | - | ❌ | ✅ | Hapus VPC |
| Replace | -/+ | ✅ | ✅ | Ganti AMI |
Bagaimana Terraform Memilih Operasi #
Keputusan apakah suatu perubahan bisa dilakukan in-place atau harus replace ditentukan oleh provider, bukan Terraform core.
flowchart TD
A["Perubahan terdeteksi\ndi plan"] --> B["Provider cek:\natribut ini sifatnya apa?"]
B -->|"updatable"| C["UPDATE IN-PLACE (~)\nResource tetap ada\nHanya atribut yang berubah"]
B -->|"forces new resource"| D["REPLACE (-/+)\nResource lama dihapus\nResource baru dibuat"]
C --> E["Contoh:\nubah tag, ubah size\ntanpa restart"]
D --> F["Contoh:\nganti AMI, ganti\ninstance type tertentu"]
style C fill:#e8f5e9,stroke:#2e7d32
style D fill:#fff3e0,stroke:#e65100# Setiap argumen resource punya sifat yang didefinisikan provider:
# - "updatable" → perubahan memicu UPDATE in-place
# - "forces new resource" → perubahan memicu REPLACE
resource "aws_instance" "web" {
ami = var.ami_id # forces new resource — tidak bisa diganti in-place
instance_type = var.type # updatable — bisa diganti in-place (dengan stop/start)
tags = {
Name = "web" # updatable — bisa diubah tanpa restart instance
}
root_block_device {
volume_size = 30 # forces new resource di beberapa kondisi
}
}
# Plan output memberitahu kamu atribut mana yang forces replacement:
# -/+ resource "aws_instance" "web" {
# ~ ami = "ami-OLD" -> "ami-NEW" # forces replacement
# id = "i-0abcdef1234567890"
# }
#
# Tanda "# forces replacement" atau "forces new resource"
# muncul di samping atribut yang menyebabkan replace
| Atribut AWS Instance | Sifat | Operasi Saat Berubah |
|---|---|---|
tags | updatable | Update in-place |
ami | forces new resource | Replace |
instance_type | updatable (stop/start) | Update in-place |
subnet_id | forces new resource | Replace |
user_data | forces new resource | Replace |
root_block_device.volume_size | updatable | Update in-place |
Import: Mengambil Alih Resource yang Sudah Ada #
Salah satu operasi penting yang sering dibutuhkan saat migrasi ke Terraform adalah import — mengambil alih pengelolaan resource yang sudah ada di cloud tanpa harus menghapus dan membuat ulang.
flowchart TD
A["Resource sudah ada\ndi cloud\ntanpa Terraform"] --> B["1. Buat blok\nresource di .tf"]
B --> C["2. Jalankan\nterraform import"]
C --> D["3. State diupdate\ndengan resource\neksisting"]
D --> E["4. Cek dengan\nterraform state show"]
E --> F["5. Lengkapi\nkonfigurasi .tf"]
F --> G["6. terraform plan\nSeharusnya 'No changes'"]
style A fill:#fff3e0,stroke:#e65100
style G fill:#e8f5e9,stroke:#2e7d32# Format: terraform import <resource_address> <resource_id>
# Import EC2 instance yang sudah ada
terraform import aws_instance.web i-0abcdef1234567890
# Import VPC yang sudah ada
terraform import aws_vpc.main vpc-0abcdef1234567890
# Import S3 bucket
terraform import aws_s3_bucket.assets my-existing-bucket
# Import resource di dalam module
terraform import module.vpc.aws_vpc.main vpc-0abcdef1234567890
# Sebelum import, kamu harus sudah punya blok resource yang kosong
# (atau dengan konfigurasi yang kamu inginkan)
# Langkah 1: Buat blok resource (bisa kosong dulu)
resource "aws_instance" "web" {
# Isi ini setelah import, berdasarkan output terraform state show
}
# Langkah 2: Import
# terraform import aws_instance.web i-0abcdef1234567890
# Langkah 3: Lihat kondisi aktual di state
# terraform state show aws_instance.web
# Langkah 4: Lengkapi konfigurasi berdasarkan kondisi aktual
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890" # dari state show
instance_type = "t3.micro" # dari state show
subnet_id = "subnet-0abcdef" # dari state show
}
# Langkah 5: Jalankan plan — seharusnya "No changes"
# terraform plan
Import dengan Blok import (Terraform 1.5+) #
Sejak Terraform 1.5, ada cara yang lebih deklaratif untuk melakukan import menggunakan blok import dalam konfigurasi.
# Blok import bisa di-commit ke version control
# dan dieksekusi sebagai bagian dari terraform apply
import {
to = aws_instance.web
id = "i-0abcdef1234567890"
}
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890"
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id
}
# Terraform 1.5+ juga bisa generate konfigurasi otomatis:
# terraform plan -generate-config-out=generated.tf
# Menghasilkan file .tf dengan konfigurasi berdasarkan kondisi aktual
| Metode Import | Perintah/Blok | Bisa di-commit? | Generate Config? |
|---|---|---|---|
| CLI | terraform import <addr> <id> | ❌ | ❌ |
Blok import (1.5+) | import { to = ... id = ... } | ✅ | ✅ (-generate-config-out) |
Moved Block: Rename Resource Tanpa Destroy #
Saat kamu ingin mengganti nama resource di konfigurasi, Terraform secara default akan menghapus yang lama dan membuat yang baru. Blok moved mencegah ini.
flowchart LR
subgraph "Tanpa moved"
A1["aws_instance.web"] --> B1["Rename ke\naws_instance.web_server"]
B1 --> C1["Plan: -web +web_server\nDESTROY + CREATE ❌"]
end
subgraph "Dengan moved"
A2["aws_instance.web"] --> B2["moved {\n from = web\n to = web_server\n}"]
B2 --> C2["Plan: moved\nTidak ada perubahan ✅"]
end
style C1 fill:#ffebee,stroke:#c62828
style C2 fill:#e8f5e9,stroke:#2e7d32# MASALAH: Rename resource menyebabkan destroy + create
# Sebelum:
resource "aws_instance" "web" { ... }
# Sesudah rename:
resource "aws_instance" "web_server" { ... }
# Plan: -aws_instance.web + aws_instance.web_server → DESTROY + CREATE!
# SOLUSI: Gunakan blok moved
moved {
from = aws_instance.web
to = aws_instance.web_server
}
resource "aws_instance" "web_server" {
ami = var.ami_id
instance_type = "t3.micro"
}
# Plan: aws_instance.web moved to aws_instance.web_server
# → TIDAK ada destroy, tidak ada create
# moved juga berguna saat refactoring ke module
moved {
from = aws_vpc.main
to = module.networking.aws_vpc.main
}
Tainted Resource #
Resource yang ditandai “tainted” oleh Terraform berarti resource tersebut dianggap rusak dan perlu di-replace pada apply berikutnya.
# Tandai resource sebagai tainted (akan di-replace saat apply)
terraform taint aws_instance.web
# Hapus taint jika kamu berubah pikiran
terraform untaint aws_instance.web
# Cek resource yang tainted di state
terraform state list # Resource tainted ditandai dengan (tainted)
# Kasus di mana resource otomatis tainted:
# - Provisioner gagal saat create
# - Resource dibuat tapi berada dalam kondisi error
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = "t3.micro"
provisioner "remote-exec" {
inline = ["sudo apt update && sudo apt install -y nginx"]
connection {
type = "ssh"
user = "ubuntu"
host = self.public_ip
}
}
# Jika provisioner gagal, instance ini otomatis tainted
# terraform apply berikutnya akan destroy + recreate instance ini
}
| Skenario | Taint Otomatis? | Aksi |
|---|---|---|
| Provisioner gagal saat create | ✅ Ya | Apply berikutnya akan replace |
| Resource error saat create | ✅ Ya | Apply berikutnya akan replace |
Manual terraform taint | — | Kamu yang menandai |
terraform untaint | — | Hapus tanda, tidak jadi replace |
Operation Ordering dan Dependency Graph #
# Terraform menentukan urutan operasi berdasarkan dependency graph
# Resource tanpa dependency bisa di-create secara paralel
# Visualisasi dependency graph
terraform graph | dot -Tpng > graph.png
terraform graph | dot -Tsvg > graph.svg
flowchart TD
A["aws_vpc.main"] --> B["aws_subnet.public"]
A --> C["aws_subnet.private"]
B --> D["aws_instance.web"]
C --> E["aws_db_instance.main"]
D --> F["aws_lb_target_group_attachment"]
style A fill:#e3f2fd,stroke:#1565c0
style D fill:#e8f5e9,stroke:#2e7d32
style E fill:#e8f5e9,stroke:#2e7d32Ringkasan #
- Lima operasi: create
+, read<=, update in-place~, delete-, replace-/+— Terraform memilih berdasarkan perbandingan konfigurasi, state, dan kondisi aktual.- Apakah update atau replace ditentukan oleh provider, bukan Terraform core — cek dokumentasi provider untuk tahu atribut mana yang “forces new resource”.
terraform importuntuk mengambil alih resource existing tanpa destroy — wajib ada blok resource dulu sebelum import dilakukan.- Blok
importdeklaratif (Terraform 1.5+) lebih clean dari perintah CLI dan bisa di-commit ke version control.- Blok
moveduntuk rename resource atau refactoring ke module tanpa menyebabkan destroy + create.- Tainted resource adalah resource yang dianggap rusak dan akan di-replace pada apply berikutnya — bisa ditandai manual atau otomatis saat provisioner gagal.