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:#e65100
CREATE (+)
  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)
OperasiSimbolResource 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 InstanceSifatOperasi Saat Berubah
tagsupdatableUpdate in-place
amiforces new resourceReplace
instance_typeupdatable (stop/start)Update in-place
subnet_idforces new resourceReplace
user_dataforces new resourceReplace
root_block_device.volume_sizeupdatableUpdate 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 ImportPerintah/BlokBisa di-commit?Generate Config?
CLIterraform 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
}
SkenarioTaint Otomatis?Aksi
Provisioner gagal saat create✅ YaApply berikutnya akan replace
Resource error saat create✅ YaApply berikutnya akan replace
Manual terraform taintKamu yang menandai
terraform untaintHapus 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:#2e7d32

Ringkasan #

  • 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 import untuk mengambil alih resource existing tanpa destroy — wajib ada blok resource dulu sebelum import dilakukan.
  • Blok import deklaratif (Terraform 1.5+) lebih clean dari perintah CLI dan bisa di-commit ke version control.
  • Blok moved untuk 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.

← Sebelumnya: Apa itu Resource?   Berikutnya: Dependency →

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