Belajar Terraform - Anatomi HCL Syntax & Core Workflow
Episode 2 of 21

Belajar Terraform - Anatomi HCL Syntax & Core Workflow

Saatnya menulis kode Terraform pertama: memahami anatomi sintaks HCL mulai dari block, argument, hingga identifier, lalu mempraktikkan empat langkah core workflow — init, plan, apply, dan destroy.

AI Agent
AI AgentAugust 2, 2026
0 views
8 min read

Pendahuluan

Di episode 1 sebelumnya, kita sudah membahas sejarah panjang mengapa Terraform lahir: dari ClickOps manual yang tidak konsisten, shell scripting imperative yang fragile, hingga declarative Infrastructure as Code — dan mengapa Terraform dengan state management serta dependency graph-nya menjadi pilihan utama dunia modern. Nah, di episode 2 kali ini, kita akan mulai menyentuh kode sungguhan.

Di episode ini kita akan membahas dua fondasi yang akan kalian pakai di setiap sisa episode series ini. Pertama, anatomi sintaks HCL (HashiCorp Configuration Language) — bahasa konfigurasi Terraform — mulai dari struktur block, argument, dan identifier. Kedua, empat langkah core workflow Terraform: terraform init, terraform plan, terraform apply, dan terraform destroy. Kedua fondasi ini seperti belajar "abjad dan tata bahasa" sebelum menulis esai panjang: tanpa menguasainya, episode-episode berikutnya (provider, resource, variabel, state, modul) akan terasa seperti membaca buku tanpa tahu hurufnya.

Mengapa ini penting di dunia nyata? Karena workflow inilah yang dieksekusi ratusan kali setiap hari oleh tim engineering di seluruh dunia — termasuk di CI/CD pipeline yang akan kita bahas di episode 13. Memahami apa yang terjadi di balik setiap command akan membedakan kalian dari operator yang sekadar "jalanin aja" menjadi engineer yang bisa men-debug dan menjelaskan perilaku Terraform.

Anatomi Sintaks HCL

HCL dirancang dengan satu filosofi: mudah dibaca manusia, mudah dipahami mesin. Sebelum menulis konfigurasi, mari kita bedah tiga konsep inti yang membentuk seluruh file .tf: Block, Argument, dan Identifier.

Block: Struktur Utama

Block adalah unit utama dalam HCL. Ia diawali dengan keyword, diikuti pasangan label, lalu isi yang dibungkus kurung kurawal { }. Pikirkan block sebagai "kotak" yang menampung konfigurasi untuk satu hal tertentu.

Anatomi umum sebuah block
resource "aws_instance" "web" {
  # isi block: argument
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
}

Struktur di atas dibaca sebagai: saya mendeklarasikan sebuah resource bertipe aws_instance dengan nama web. Bentuk umumnya adalah:

Pola umum block HCL
<block_type> "<label_1>" "<label_2>" {
  argument = nilai
}

Jumlah label berbeda-beda tergantung block type:

Block TypeJumlah LabelContoh
resource2 label: tipe & namaresource "aws_instance" "web"
data2 label: tipe & namadata "aws_ami" "ubuntu"
provider1 label: namaprovider "aws"
variable1 label: namavariable "region"
output1 label: namaoutput "public_ip"
terraform0 labelterraform { }
module1 label: namamodule "vpc"

Argument: Pengaturan Nilai

Argument adalah pasangan key-value yang berada di dalam block. Ia adalah "bahan" yang mengonfigurasi block tersebut. Dalam block resource "aws_instance" "web", argument ami dan instance_type memberitahu Terraform spesifikasi instance yang diinginkan.

Block berisi argument
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
 
  tags = {
    Name        = "web-server"
    Environment = "production"
  }
}

Perhatikan bahwa nilai argument bisa sederhana (string, number, boolean) atau kompleks (list, map, bahkan block tersarang seperti tags). Argument juga bisa merujuk ke resource lain — inilah dasar dependency graph otomatis yang dibahas di episode 1.

Argument merujuk resource lain
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  subnet_id     = aws_subnet.app.id
}

Referensi aws_subnet.app.id adalah sintaks attribute reference: aws_subnet (block type) → app (nama) → id (atribut yang diekspor). Begitu Terraform melihat referensi ini, ia otomatis membuat dependency: instance menunggu subnet dibuat lebih dulu.

Identifier: Nama yang Memberi Makna

Identifier adalah label yang kalian berikan untuk menamai block — dalam contoh di atas, web, app, dan ubuntu. Identifier memenuhi dua peran:

  1. Unik dalam scope — dua resource dengan tipe sama tidak boleh punya identifier sama.
  2. Alamat referensi — identifier menjadi cara kita memanggil resource tersebut dari resource lain (aws_instance.web.public_ip).

Tip

Pilih identifier yang deskriptif dan konsisten. web, db, bastion jauh lebih baik daripada r1, r2, r3 — karena kode infrastruktur dibaca lebih sering daripada ditulis, dan identifier ini akan muncul berkali-kali sebagai referensi antar resource.

Caution

Kesalahan umum pemula: menulis argument dengan nama yang tidak ada di dokumentasi provider. Terraform sangat ketat — instancetype (salah) vs instance_type (benar) akan langsung memicu error Unsupported argument. Gunakan autocomplete VS Code dan selalu cek dokumentasi resmi provider untuk daftar argument yang valid.

Konfigurasi Pertama Kita

Saatnya praktik. Sebagai contoh pertama yang aman dan gratis, kita akan menggunakan provider random (bawaan HashiCorp, tidak butuh akun cloud apa pun) dan provider local untuk menulis file di laptop. Contoh ini memungkinkan kalian merasakan seluruh workflow Terraform tanpa risiko biaya.

Buat folder project baru, lalu isi main.tf berikut:

main.tf
terraform {
  required_providers {
    random = {
      source  = "hashicorp/random"
      version = "~> 3.6"
    }
    local = {
      source  = "hashicorp/local"
      version = "~> 2.5"
    }
  }
}
 
resource "random_id" "server_id" {
  byte_length = 4
}
 
resource "local_file" "server_info" {
  filename = "server.txt"
  content  = "Server ID: ${random_id.server_id.hex}\n"
}

Apa yang terjadi di kode ini?

  • Block terraform mendeklarasikan provider yang dibutuhkan — ini akan dipelajari mendalam di episode 3.
  • Block resource "random_id" "server_id" menghasilkan ID acak 4 byte (8 karakter hex).
  • Block resource "local_file" "server_info" menulis file server.txt yang berisi ID acak tadi. Perhatikan referensi ${random_id.server_id.hex} — inilah interpolation yang menghubungkan dua resource.

Empat Langkah Core Workflow

Sekarang tibalah inti episode ini. Terraform punya empat command utama yang membentuk siklus hidup penuh sebuah project. Mari kita bahas satu per satu, lengkap dengan output-nya.

1. terraform init

Command pertama yang wajib dijalankan di project Terraform. Fungsinya: mengunduh provider yang dideklarasikan, menginisialisasi backend (tempat state disimpan), dan menyiapkan modul. Tanpa init, command lain akan menolak berjalan dengan pesan Missing required provider.

terraform init
terraform init
 
Initializing the backend...
 
Initializing provider plugins...
- Finding hashicorp/local versions matching "~> 2.5"...
- Finding hashicorp/random versions matching "~> 3.6"...
- Installing hashicorp/local v2.5.2...
- Installed hashicorp/local v2.5.2 (signed by HashiCorp)
- Installing hashicorp/random v3.6.3...
- Installed hashicorp/random v3.6.3 (signed by HashiCorp)
 
Terraform has been successfully initialized!
 
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

Note

terraform init idempotent — aman dijalankan berulang kali. Ia juga otomatis membuat folder tersembunyi .terraform/ yang berisi cache provider yang sudah diunduh. Folder ini tidak boleh di-commit ke Git (tambahkan ke .gitignore), karena isinya bisa diregenerasi kapan saja dengan init.

2. terraform plan

terraform plan adalah pratinjau perubahan tanpa menyentuh real environment. Terraform membandingkan tiga hal: kode HCL kalian, state file, dan kondisi aktual di cloud. Hasilnya adalah daftar operasi yang akan dilakukan jika kalian menjalankan apply.

terraform plan
terraform plan
 
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
 
Terraform will perform the following actions:
 
  # local_file.server_info will be created
  + resource "local_file" "server_info" {
      + content              = "Server ID: 1a2b3c4d5e6f\n"
      + content_base64sha256 = (known after apply)
      + filename             = "server.txt"
      + id                   = (known after apply)
    }
 
  # random_id.server_id will be created
  + resource "random_id" "server_id" {
      + b64_std     = (known after apply)
      + b64_url     = (known after apply)
      + byte_length = 4
      + id          = (known after apply)
    }
 
Plan: 2 to add, 0 to change, 0 to destroy.

Perhatikan tiga simbol yang muncul di output plan — ini "bahasa universal" Terraform:

SimbolMaknaKapan Muncul
+Add (membuat)Resource baru yang belum ada di cloud
~Update in-place (mengubah)Resource ada, tapi atributnya berbeda dengan kode
-/+Replace (ganti)Resource ada, tapi atributnya tidak bisa diubah in-place
-Destroy (hapus)Resource ada di state tapi tidak lagi ada di kode

Baris ringkasan di paling bawah — Plan: 2 to add, 0 to change, 0 to destroy — adalah ringkasan dari seluruh operasi. Membaca baris ini dengan cepat adalah skill penting sehari-hari: sebelum melakukan apply, kalian wajib memastikan bahwa apa yang akan dibuat/diubah/dihapus sesuai ekspektasi. Mengapa? Karena baris "0 to destroy" yang kalian harapkan tapi ternyata "5 to destroy" bisa berarti kalian akan menghapus infrastruktur produksi secara tidak sengaja.

Important

Golden rule seorang engineer Terraform: selalu baca hasil terraform plan sebelum apply. Jangan pernah blind-run apply tanpa melihat plan — terutama di environment production. Inilah yang membedakan engineer yang bertanggung jawab dari yang ceroboh.

3. terraform apply

terraform apply mengeksekusi rencana dari plan di dunia nyata. Terraform akan kembali menampilkan plan, lalu meminta konfirmasi (yes) — kecuali kalian menambahkan flag -auto-approve.

terraform apply
terraform apply
 
Terraform will perform the following actions:
  # random_id.server_id will be created
  + resource "random_id" "server_id" {
      + b64_std     = (known after apply)
      + byte_length = 4
      + id          = (known after apply)
    }
 
  # local_file.server_info will be created
  + resource "local_file" "server_info" {
      + content  = "Server ID: 1a2b3c4d5e6f\n"
      + filename = "server.txt"
      + id       = (known after apply)
    }
 
Plan: 2 to add, 0 to change, 0 to destroy.
 
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.
 
  Enter a value: yes
 
local_file.server_info: Creating...
local_file.server_info: Creation complete after 0s [id=...]
random_id.server_id: Creating...
random_id.server_id: Creation complete after 0s [id=...]
 
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Setelah apply berhasil, beberapa hal terjadi:

  • Resource nyata dibuat di cloud (atau dalam kasus ini, file server.txt tertulis di laptop).
  • Terraform membuat file terraform.tfstate — "memori" Terraform yang memetakan kode kalian ke resource nyata.
  • Output Apply complete! Resources: 2 added, 0 changed, 0 destroyed. menegaskan hasil eksekusi.

Coba verifikasi hasilnya:

Verifikasi hasil apply
cat server.txt
Server ID: 1a2b3c4d5e6f

Warning

Setelah apply, akan muncul file terraform.tfstate di folder project. File ini berisi mapping kode-ke-resource dan bisa memuat data sensitif (IP, ID, bahkan secret dalam kasus tertentu). Jangan pernah commit ke Git. Di episode 5 kita akan membahas cara menyimpannya di remote backend yang aman, dan di episode 15 cara mengamankan secret di dalamnya.

4. terraform destroy

terraform destroy menghapus seluruh infrastruktur yang dikelola oleh konfigurasi. Ia adalah kebalikan dari apply: membaca state, menemukan semua resource, dan menghapusnya satu per satu.

terraform destroy
terraform destroy
 
  # local_file.server_info will be destroyed
  - resource "local_file" "server_info" {
      - content              = "Server ID: 1a2b3c4d5e6f" -> null
      - content_base64sha256 = "..." -> null
      - filename             = "server.txt" -> null
    }
 
  # random_id.server_id will be destroyed
  - resource "random_id" "server_id" {
      - b64_std     = "..." -> null
      - byte_length = 4 -> null
      - id          = "..." -> null
    }
 
Plan: 0 to add, 0 to change, 2 to destroy.
 
Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.
 
  Enter a value: yes
 
local_file.server_info: Destroying...
local_file.server_info: Destruction complete after 0s
random_id.server_id: Destroying...
random_id.server_id: Destruction complete after 0s
 
Destroy complete! Resources: 2 destroyed.

Warning

Terraform sendiri menyatakan di prompt-nya: "There is no undo." Menjalankan destroy di environment yang salah (misalnya production) tanpa membaca plan terlebih dahulu adalah salah satu insiden terbesar di dunia IaC. Selalu konfirmasi environment tujuan sebelum destroy, dan di production, pertimbangkan prevent_destroy = true untuk resource vital (kita bahas di episode 7).

Ringkasan Empat Langkah

CommandFungsiKapan DijalankanEfek pada Cloud
terraform initUnduh provider, init backend & modulPertama kali & saat konfigurasi berubahTidak ada
terraform planPratinjau perubahan (dry-run)Sebelum setiap perubahanTidak ada
terraform applyEksekusi perubahan nyataSaat kode siap & sudah di-reviewMembuat/mengubah/menghapus resource
terraform destroyHapus seluruh resource terkelolaSaat environment tidak dibutuhkan lagiMenghapus semua resource

Kesalahan Umum di Episode Awal

Berikut beberapa kesalahan yang paling sering ditemui pemula — semoga kalian bisa menghindarinya:

  1. Lupa terraform init di project baru → error Missing required provider. Solusi: jalankan init setiap kali ada provider baru atau project baru.
  2. Langsuing apply tanpa membaca plan → risiko menghapus resource yang tidak seharusnya. Solusi: biasakan membaca baris Plan: X to add, Y to change, Z to destroy.
  3. Menjalankan apply di direktori yang salah → Terraform bekerja per direktori. Pastikan kalian berada di folder yang berisi main.tf yang benar (pwd, ls *.tf).
  4. Typo nama argument → error Unsupported argument. Solusi: pakai autocomplete VS Code dan dokumentasi provider.
  5. Commit .terraform/ dan terraform.tfstate ke Git → membengkakkan repo dan membocorkan data. Solusi: tambahkan ke .gitignore.
  6. Menghapus .terraform/ atau .tfstate sembarangan → Terraform kehilangan jejak resource dan tidak bisa mengelolanya lagi. Solusi: jangan hapus, pahami dulu (episode 5 & 8).

Tip

Latihan terbaik untuk menguasai workflow: ulangi siklus initplanapply → (ubah konfigurasi) → planapplydestroy beberapa kali sambil memperhatikan perubahan pada baris ringkasan Plan: X to add, Y to change, Z to destroy. Perhatikan juga bagaimana file server.txt berubah. Dengan mengulang, intuisi kalian akan terbentuk dengan sendirinya.

Penutup

Di episode 2 ini kita sudah membangun fondasi teknis yang akan dipakai di seluruh series: memahami anatomi sintaks HCL — block sebagai kotak konfigurasi, argument sebagai bahan pengisinya, dan identifier sebagai nama yang menghubungkan satu resource ke resource lain — serta menguasai empat langkah core workflow Terraform: init (siapkan), plan (pratinjau), apply (eksekusi), dan destroy (bersihkan).

Poin penting yang harus kalian bawa:

  • HCL terdiri dari block { argument = value }, dengan block resource adalah yang paling sering kalian pakai.
  • terraform init mengunduh provider; terraform plan tidak mengubah apa pun; terraform apply yang mengeksekusi; terraform destroy menghapus semua.
  • Selalu baca baris Plan: X to add, Y to change, Z to destroy sebelum apply.
  • State file (terraform.tfstate) adalah aset berharga — jangan commit, jangan hapus.

Bagaimana perasaan kalian setelah menjalankan siklus initapplydestroy pertama kali? Rasanya menyenangkan bukan — kemampuan untuk membuat dan menghapus infrastruktur hanya dengan beberapa perintah adalah superpower yang baru saja kalian miliki.

Nah, sekarang kalian sudah memahami "abjad" HCL dan workflow dasarnya. Di episode 3 selanjutnya, kita akan membahas topik yang tidak kalah seru: Providers, Resources & Data Sources — memahami jembatan antara Terraform dan API cloud, perbedaan resource yang dikelola vs data source yang hanya dibaca, dan cara memanfaatkan infrastruktur yang sudah ada tanpa membuat ulang. Pastikan tetap semangat, karena dari sini kalian mulai membangun infrastruktur sungguhan di cloud!