Resource #
Resource adalah unit dasar dari konfigurasi Terraform. Setiap hal yang kamu ingin Terraform buat dan kelola — sebuah VM, sebuah database, sebuah DNS record, sebuah IAM role — dideklarasikan sebagai blok resource. Memahami cara resource bekerja, bagaimana ia berinteraksi satu sama lain, dan bagaimana Terraform mengelola lifecycle-nya adalah pondasi dari semua yang lebih kompleks di Terraform.
Anatomi Blok Resource #
Setiap blok resource memiliki struktur yang konsisten. Bagian-bagiannya sederhana tapi masing-masing punya peran yang sangat spesifik.
resource "<provider>_<type>" "<nama_lokal>" {
argumen = nilai
}
# Contoh nyata:
resource "aws_instance" "web_server" {
# │ │ │
# │ │ └── Nama lokal (hanya untuk referensi internal)
# │ └────────────── Tipe resource (dari provider AWS)
# └───────────────────────── Provider prefix (wajib, otomatis menentukan provider)
ami = "ami-0abcdef1234567890"
instance_type = "t3.micro"
tags = {
Name = "web-server"
Environment = "production"
}
}
Nama lokal (web_server di atas) hanya bermakna di dalam konfigurasi Terraform — ia tidak muncul di AWS Console. Yang muncul di AWS adalah nilai dari argumen tags.Name. Nama lokal digunakan untuk mereferensikan resource ini dari tempat lain dalam konfigurasi.
Tipe resource (aws_instance) terdiri dari dua bagian yang dipisahkan underscore: prefix provider (aws) dan tipe spesifik (instance). Terraform menggunakan prefix ini untuk menentukan provider mana yang bertanggung jawab mengelola resource.
# Contoh berbagai tipe resource dari provider berbeda:
resource "aws_instance" "web" { } # AWS EC2
resource "aws_s3_bucket" "data" { } # AWS S3
resource "google_compute_instance" "app" { }# GCP Compute
resource "cloudflare_record" "dns" { } # Cloudflare DNS
resource "kubernetes_deployment" "api" { } # Kubernetes
resource "postgresql_role" "admin" { } # PostgreSQL
Referensi Antar Resource #
Satu resource bisa mereferensikan atribut dari resource lain. Inilah yang membentuk dependency graph dan memungkinkan resource saling terhubung secara dinamis. Format referensi selalu <type>.<nama_lokal>.<atribut>.
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "public" {
# Referensi ke atribut resource lain
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-southeast-1a"
}
resource "aws_security_group" "web" {
name = "web-sg"
vpc_id = aws_vpc.main.id # Referensi ke VPC yang sama
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890"
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id # dari subnet
vpc_security_group_ids = [aws_security_group.web.id] # dari security group
}
Referensi ini bukan hanya memasukkan nilai — ia juga mendeklarasikan dependency. Ketika kamu menulis aws_vpc.main.id, Terraform tahu bahwa subnet harus dibuat setelah VPC. Dependency graph dihitung otomatis dari referensi ini.
flowchart TD
VPC["aws_vpc.main"] --> SUBNET["aws_subnet.public"]
VPC --> SG["aws_security_group.web"]
SUBNET --> EC2["aws_instance.web"]
SG --> EC2
style VPC fill:#e3f2fd,stroke:#1565c0
style SUBNET fill:#e8f5e9,stroke:#2e7d32
style SG fill:#e8f5e9,stroke:#2e7d32
style EC2 fill:#fff3e0,stroke:#e65100Atribut yang Digenerate #
Beberapa atribut hanya tersedia setelah resource dibuat — misalnya IP address, ARN, atau ID yang digenerate oleh cloud provider. Atribut ini tersimpan di state dan bisa direferensikan oleh resource lain atau di-ekspos sebagai output.
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890"
instance_type = "t3.micro"
}
# Atribut ini baru tersedia setelah apply
output "public_ip" {
value = aws_instance.web.public_ip # IP dari AWS
}
output "arn" {
value = aws_instance.web.arn # ARN dari AWS
}
# Referensi ke resource lain
resource "aws_route53_record" "app" {
zone_id = var.dns_zone_id
name = "app.example.com"
type = "A"
ttl = 300
records = [aws_instance.web.public_ip] # IP dari instance di atas
}
Daftar lengkap atribut yang tersedia untuk setiap resource type bisa dilihat di dokumentasi provider masing-masing di registry.terraform.io. Attribute yang bisa kamu set disebut argument, sedangkan yang hanya bisa kamu baca setelah create disebut attribute.
Lifecycle Resource #
Setiap resource memiliki lifecycle: dibuat, mungkin diubah, dan akhirnya dihapus. Terraform mengelola ini secara otomatis, tapi kamu bisa mengkustomisasi perilakunya melalui blok lifecycle.
create_before_destroy
#
Secara default, saat Terraform perlu me-replace resource (misalnya karena force_new attribute berubah), ia akan menghapus yang lama dulu baru membuat yang baru. Dengan create_before_destroy = true, urutannya dibalik — resource baru dibuat dulu, baru yang lama dihapus. Ini penting untuk resource yang tidak boleh ada downtime.
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890"
instance_type = "t3.micro"
lifecycle {
create_before_destroy = true
# Jika AMI berubah → buat instance baru dulu → baru hapus yang lama
# Tanpa ini: instance lama dihapus dulu → ada jeda tanpa server
}
}
prevent_destroy
#
Mencegah resource dihapus secara tidak sengaja. Jika terraform plan menghasilkan operasi destroy untuk resource ini, Terraform akan error.
resource "aws_s3_bucket" "critical_data" {
bucket = "company-critical-data"
lifecycle {
prevent_destroy = true
# terraform destroy atau menghapus blok dari config → ERROR
# Proteksi untuk resource yang tidak boleh dihapus
}
}
ignore_changes
#
Memberitahu Terraform untuk mengabaikan perubahan pada atribut tertentu. Berguna ketika atribut dikelola di luar Terraform (misalnya oleh auto-scaling, monitoring agent, atau manual operation).
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890"
instance_type = "t3.micro"
tags = {
Name = "web-server"
LastModified = timestamp()
}
lifecycle {
ignore_changes = [
tags["LastModified"], # Tag ini berubah setiap apply
ami, # AMI dikelola oleh pipeline terpisah
]
}
}
replace_triggered_by
#
Memicu replace pada resource ini ketika resource atau attribute tertentu berubah. Berguna untuk memastikan resource di-replace bersamaan dengan dependency-nya.
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = "t3.micro"
lifecycle {
replace_triggered_by = [var.ami_id]
# Jika var.ami_id berubah → instance ini di-replace
# Lebih eksplisit dari force_new yang ditentukan oleh provider
}
}
Meta-Arguments: count dan for_each
#
Terraform menyediakan meta-arguments untuk membuat beberapa instance resource sekaligus. Meta-arguments bukan atribut resource — mereka adalah instruksi untuk Terraform tentang cara membuat resource.
count — untuk Resource Identik
#
resource "aws_subnet" "public" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "public-subnet-${count.index + 1}"
}
}
# Referensi:
# aws_subnet.public[0].id
# aws_subnet.public[1].id
# aws_subnet.public[2].id
for_each — untuk Resource dengan Identitas Berbeda
#
resource "aws_iam_user" "team" {
for_each = toset(["alice", "bob", "charlie"])
name = each.key
tags = {
Name = each.key
}
}
# Referensi:
# aws_iam_user.team["alice"].arn
# aws_iam_user.team["bob"].arn
# aws_iam_user.team["charlie"].arn
# Juga bisa dari map:
resource "aws_s3_bucket" "buckets" {
for_each = {
logs = "app-logs-2024"
assets = "app-assets-2024"
backups = "app-backups-2024"
}
bucket = each.value
tags = {
Purpose = each.key
}
}
flowchart TD
A["Pilih meta-argument"] --> B{"Resource identik\natau berbeda?"}
B -->|"Identik"| C["count"]
B -->|"Berbeda identitas"| D["for_each"]
C --> E["Referensi: resource.name[index]"]
D --> F["Referensi: resource.name[key]"]
E --> G["Masalah: hapus elemen tengah\n→ index bergeser\n→ resource di-recreate"]
F --> H["Aman: hapus elemen tengah\n→ key lain tidak terpengaruh"]
style C fill:#fff3e0,stroke:#e65100
style D fill:#e8f5e9,stroke:#2e7d32
style G fill:#ffebee,stroke:#c62828
style H fill:#e8f5e9,stroke:#2e7d32Hati-hati dengancountpada resource yang sudah ada. Jika kamu menghapus elemen di tengah daftar, semua index setelahnya bergeser — Terraform akan menghapus dan membuat ulang semua resource setelah elemen yang dihapus. Gunakanfor_eachuntuk resource dengan identitas unik agar lebih aman.
Conditional Resource dengan Count #
count juga bisa digunakan untuk membuat resource secara kondisional — count = 0 berarti resource tidak dibuat.
resource "aws_nat_gateway" "main" {
count = var.enable_nat ? 1 : 0
allocation_id = aws_eip.nat[0].id
subnet_id = aws_subnet.public[0].id
}
# Referensi ke conditional resource harus hati-hati:
# aws_nat_gateway.main[0].id → error jika count = 0
# Solusi: gunakan try() atau conditional
locals {
nat_gateway_id = try(aws_nat_gateway.main[0].id, null)
}
provider Meta-Argument
#
Ketika menggunakan multi-region atau multi-account, kamu bisa menentukan provider mana yang mengelola resource tertentu.
resource "aws_s3_bucket" "replica" {
provider = aws.us_east # Gunakan provider dengan alias
bucket = "app-replica-us"
}
Resource yang Dihapus dari Konfigurasi #
Ketika kamu menghapus blok resource dari file .tf dan menjalankan terraform apply, Terraform akan menghapus resource tersebut dari infrastruktur. Ini perilaku default yang harus dipahami — menghapus dari config = menghapus dari infrastruktur.
# Sebelumnya ada di config:
# resource "aws_instance" "old_server" {
# ami = "ami-0abcdef1234567890"
# instance_type = "t3.micro"
# }
# Setelah dihapus dari config:
# $ terraform plan
# aws_instance.old_server will be destroyed
# Plan: 0 to add, 0 to change, 1 to destroy.
# Jika tidak ingin resource dihapus, ada beberapa opsi:
# 1. prevent_destroy (sebelum menghapus blok)
# 2. terraform state rm (hapus dari state tanpa destroy)
# 3. moved block (pindah ke resource baru)
moved Block untuk Rename/Restructure
#
Ketika kamu ingin mengubah nama lokal resource atau memindahkannya ke module tanpa menghapus dan membuat ulang, gunakan moved block.
# Sebelumnya:
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890"
instance_type = "t3.micro"
}
# Ingin rename menjadi "app_server" tanpa recreate:
resource "aws_instance" "app_server" {
ami = "ami-0abcdef1234567890"
instance_type = "t3.micro"
}
moved {
from = aws_instance.web
to = aws_instance.app_server
# Terraform tahu ini resource yang sama → tidak ada destroy/create
}
Ringkasan #
- Resource adalah unit dasar Terraform — setiap infrastruktur dideklarasikan sebagai blok
resource "<type>" "<nama_lokal>".- Nama lokal hanya untuk referensi internal — tidak mempengaruhi nama resource di cloud, hanya digunakan untuk referensi dalam konfigurasi.
- Referensi antar resource (
aws_vpc.main.id) membentuk dependency graph otomatis — Terraform tahu urutan eksekusi dari referensi ini.- Lifecycle block mengizinkan kustomisasi perilaku:
create_before_destroy(zero-downtime),prevent_destroy(proteksi),ignore_changes(abaikan atribut eksternal).- Gunakan
for_eachbukancountuntuk resource dengan identitas berbeda — lebih aman saat ada perubahan di tengah daftar karena key tidak bergeser.countuntuk conditional —count = 0membuat resource tidak dibuat, tapi hati-hati saat mereferensi conditional resource.movedblock memungkinkan rename/restructure tanpa destroy/create — sangat berguna saat refactoring konfigurasi.