Apa itu Resource? #

Di section Concept, kamu sudah berkenalan dengan resource sebagai unit dasar konfigurasi Terraform. Di section ini, kita masuk lebih dalam — bagaimana resource berinteraksi satu sama lain, bagaimana Terraform mengelola lifecycle-nya, dan bagaimana menulis resource yang robust untuk infrastruktur production. Artikel ini membangun fondasi untuk topik-topik yang lebih dalam di section ini: lifecycle, dependency, dan operation.

Resource vs Data Source #

Salah satu kebingungan paling umum di Terraform adalah perbedaan antara resource dan data. Keduanya adalah blok konfigurasi, tapi perannya sangat berbeda.

flowchart LR
    subgraph "resource (Manage)"
        R1["aws_vpc.main"] --> R2["Terraform BUAT\nresource ini"]
        R2 --> R3["Terraform UPDATE\njika config berubah"]
        R3 --> R4["Terraform HAPUS\njika di-destroy"]
    end

    subgraph "data (Read)"
        D1["aws_ami.ubuntu"] --> D2["Terraform BACA\ndari yang sudah ada"]
        D2 --> D3["Tidak bisa\ndibuat/dihapus"]
        D3 --> D4["Hanya referensi\nuntuk resource lain"]
    end

    style R1 fill:#e3f2fd,stroke:#1565c0
    style D1 fill:#e8f5e9,stroke:#2e7d32
# resource — Terraform MEMBUAT dan MENGELOLA ini
# Terraform bertanggung jawab atas lifecycle-nya: create, update, destroy
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "main-vpc"
  }
}

# data — Terraform MEMBACA ini, tidak membuatnya
# Resource sudah ada di luar Terraform, kamu hanya ingin referensikan
data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"]  # Canonical

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-*-22.04-amd64-server-*"]
  }
}

# Menggunakan keduanya bersama
resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id  # AMI dari data source
  instance_type = "t3.micro"
  vpc_id        = aws_vpc.main.id         # VPC dari resource
}
Aspekresourcedata
TujuanBuat dan kelola resource baruBaca resource yang sudah ada
LifecycleCreate, update, destroyTidak ada
Di state?✅ Ya, disimpan dan dilacak✅ Ya, tapi hanya sebagai cache
Dibuat oleh Terraform?✅ Ya❌ Tidak, sudah ada di luar
ContohBuat VPC, EC2, S3Baca AMI, baca VPC existing

Anatomi Lengkap Blok Resource #

flowchart TD
    A["Blok Resource"] --> B["Argumen Required\n(ami, instance_type)"]
    A --> C["Argumen Optional\n(subnet_id, tags)"]
    A --> D["Nested Block\n(tags, root_block_device)"]
    A --> E["Meta-Arguments\n(depends_on, count,\nfor_each, provider,\nlifecycle)"]

    B --> B1["Wajib ada\nDisediakan provider"]
    C --> C1["Opsional\nDisediakan provider"]
    D --> D1["Struktur bersarang\nDisediakan provider"]
    E --> E1["Disediakan Terraform\nBerlaku untuk SEMUA\nresource"]

    style A fill:#e3f2fd,stroke:#1565c0
    style E fill:#fff3e0,stroke:#e65100
    style E1 fill:#fff3e0,stroke:#e65100
# Struktur lengkap blok resource dengan semua bagiannya

resource "<PROVIDER>_<TYPE>" "<NAME>" {
  # ─────────────────────────────────────────
  # ARGUMEN — konfigurasi spesifik resource ini
  # ─────────────────────────────────────────
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.micro"

  # Blok bersarang (nested block)
  tags = {
    Name        = "web-server"
    Environment = var.environment
  }

  # ─────────────────────────────────────────
  # META-ARGUMENTS — berlaku untuk semua resource
  # ─────────────────────────────────────────

  # Dependency eksplisit
  depends_on = [aws_iam_role_policy_attachment.node]

  # Buat beberapa instance
  count = 3
  # atau: for_each = var.instance_map

  # Gunakan provider non-default
  provider = aws.us_east

  # Kustomisasi lifecycle
  lifecycle {
    create_before_destroy = true
    prevent_destroy       = false
    ignore_changes        = [tags["LastModified"]]
  }
}

Meta-arguments (depends_on, count, for_each, provider, lifecycle) adalah argumen khusus yang dikenali Terraform sendiri — bukan argumen dari provider. Mereka berlaku untuk semua resource, apapun tipe dan providernya.


Bagaimana Resource Direpresentasikan di State #

Setiap resource yang dibuat Terraform disimpan di state dengan identitas uniknya. Memahami struktur ini membantu saat kamu perlu berinteraksi dengan state secara langsung.

flowchart TD
    A["State File"] --> B["Resource Type\naws_instance"]
    B --> C["Resource Name\nweb"]
    C --> D["Resource Address\naws_instance.web"]
    D --> E["Atribut\nid, ami, ip, tags"]

    F["Resource + count"] --> G["aws_instance.workers[0]"]
    F --> H["aws_instance.workers[1]"]
    F --> I["aws_instance.workers[2]"]

    J["Resource + for_each"] --> K["aws_subnet.public[\"a\"]"]
    J --> L["aws_subnet.public[\"b\"]"]
    J --> M["aws_subnet.public[\"c\"]"]

    style D fill:#e3f2fd,stroke:#1565c0
    style G fill:#e8f5e9,stroke:#2e7d32
    style K fill:#e8f5e9,stroke:#2e7d32
# Lihat semua resource di state
terraform state list

# Output:
# aws_instance.web
# aws_instance.workers[0]
# aws_instance.workers[1]
# aws_instance.workers[2]
# module.vpc.aws_vpc.main
# module.vpc.aws_subnet.public["ap-southeast-1a"]
# Lihat detail satu resource di state
terraform state show aws_instance.web

# Output:
# # aws_instance.web:
# resource "aws_instance" "web" {
#     ami                    = "ami-0abcdef1234567890"
#     id                     = "i-0abcdef1234567890"
#     instance_type          = "t3.micro"
#     private_ip             = "10.0.1.42"
#     public_ip              = "54.123.45.67"
#     ... (semua atribut, termasuk yang digenerate AWS)
# }

Address resource di state mengikuti format: <type>.<name> untuk resource biasa, <type>.<name>[index] untuk resource dengan count, dan <type>.<name>["key"] untuk resource dengan for_each.

Pola ResourceFormat AddressContoh
Resource biasa<type>.<name>aws_instance.web
Dengan count<type>.<name>[index]aws_instance.workers[0]
Dengan for_each<type>.<name>["key"]aws_subnet.public["a"]
Di dalam modulemodule.<name>.<type>.<name>module.vpc.aws_vpc.main

Resource Address dan Cara Mereferensikannya #

Setiap resource memiliki address yang bisa direferensikan dari tempat lain dalam konfigurasi.

flowchart LR
    A["Referensi antar\nresource"] --> B["Format:\ntype.name.attribute"]

    B --> C["aws_vpc.main.id\n(id dari VPC)"]
    B --> D["aws_subnet.public.id\n(id dari subnet)"]
    B --> E["aws_instance.web.public_ip\n(IP dari instance)"]

    F["Splat expression"] --> G["aws_subnet.private[*].id\nSemua ID subnet sekaligus"]

    style B fill:#e3f2fd,stroke:#1565c0
# Format referensi: <TYPE>.<NAME>.<ATTRIBUTE>

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "public" {
  vpc_id = aws_vpc.main.id  # Referensi ke atribut "id" dari aws_vpc.main
}

# Untuk resource dengan count:
resource "aws_subnet" "private" {
  count  = 3
  vpc_id = aws_vpc.main.id
  cidr_block = "10.0.${count.index + 10}.0/24"
}

resource "aws_route_table_association" "private" {
  count          = 3
  subnet_id      = aws_subnet.private[count.index].id  # Akses per index
  route_table_id = aws_route_table.private.id
}

# Semua subnet sekaligus menggunakan splat expression:
output "private_subnet_ids" {
  value = aws_subnet.private[*].id  # ["subnet-001", "subnet-002", "subnet-003"]
}

Pola Penulisan yang Konsisten #

Konsistensi dalam cara menulis resource membuat konfigurasi lebih mudah dibaca dan di-review.

# POLA YANG DIREKOMENDASIKAN:

resource "aws_instance" "web" {
  # 1. Argumen required (wajib) di atas
  ami           = var.ami_id
  instance_type = var.instance_type

  # 2. Argumen optional yang penting
  subnet_id              = aws_subnet.public.id
  vpc_security_group_ids = [aws_security_group.web.id]
  iam_instance_profile   = aws_iam_instance_profile.web.name

  # 3. Blok bersarang
  root_block_device {
    volume_size = 20
    volume_type = "gp3"
    encrypted   = true
  }

  # 4. Tags selalu di akhir
  tags = merge(
    var.common_tags,
    {
      Name = "web-server"
      Role = "web"
    }
  )

  # 5. Lifecycle di paling akhir (jika ada)
  lifecycle {
    create_before_destroy = true
  }
}


Resource Addressing #

Resource addressing memungkinkan referensi spesifik ke resource tertentu.

# Format: module.module_name.resource_type.resource_name[index]

# Root level resource
aws_instance.web

# Resource dalam module
module.networking.aws_vpc.main

# Resource dalam count
aws_instance.web[0]
aws_instance.web[1]

# Resource dalam for_each
aws_instance.web["app-server"]
aws_instance.web["db-server"]

# Nested module
module.networking.module.subnets.aws_subnet.private[0]
# Referensi resource untuk dependency
resource "aws_instance" "app" {
  subnet_id = module.networking.private_subnet_ids[0]
  # Implicit dependency ke module.networking
}

Resource Metadata #

# Setiap resource memiliki metadata yang bisa diakses

resource "aws_instance" "web" {
  ami           = "ami-12345"
  instance_type = "t3.micro"
  
  tags = {
    Name = "web-server"
  }
}

# Metadata yang tersedia:
# aws_instance.web.id           → Instance ID
# aws_instance.web.arn          → ARN
# aws_instance.web.private_ip   → Private IP
# aws_instance.web.public_ip    → Public IP (jika ada)
# aws_instance.web.availability_zone → AZ
# aws_instance.web.instance_state → State (running, stopped)
# Lihat semua attributes resource
terraform state show aws_instance.web
# Menampilkan SEMUA atribut yang tersimpan di state

Resource Lifecycle States #

RESOURCE STATES:

1. pending_create: Akan dibuat saat apply
2. creating: Sedang dibuat
3. created: Sudah dibuat (aktif)
4. pending_update: Akan diupdate saat apply
5. updating: Sedang diupdate
6. pending_destroy: Akan dihapus saat apply
7. destroying: Sedang dihapus
8. destroyed: Sudah dihapus

TERRAFORM PLAN ICONS:
+  Create (resource baru)
~  Update (resource berubah)
-  Destroy (resource dihapus)
-/+ Replace (destroy + create)
<= Read (data source)
# Lihat state resource
terraform state show aws_instance.web

# List semua resource di state
terraform state list

# List dengan filter
terraform state list | grep aws_instance

Ringkasan #

  • resource untuk membuat, data untuk membaca — resource dikelola Terraform, data source hanya dibaca dari yang sudah ada.
  • Meta-arguments (depends_on, count, for_each, provider, lifecycle) berlaku untuk semua resource, bukan argumen dari provider.
  • Address resource di state mengikuti format <type>.<name> — penting diketahui untuk operasi terraform state dan referensi antar resource.
  • Referensi menggunakan format <type>.<name>.<attribute> — ini yang membentuk dependency graph otomatis Terraform.
  • Splat expression ([*]) untuk mengakses semua instance sekaligus dari resource dengan count.
  • Konsistensi penulisan — required args dulu, optional, nested blocks, tags, lifecycle — membuat review lebih mudah.

← Sebelumnya: Idempotency   Berikutnya: Lifecycle →

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