Performance Optimization #

Terraform yang lambat bukan hanya masalah kenyamanan — pipeline CI/CD yang menunggu 20 menit untuk satu plan akan memperlambat seluruh alur kerja tim. Sebagian besar masalah performa Terraform berasal dari satu sumber: terlalu banyak API call ke cloud provider saat refresh state. Memahami di mana waktu habis dan cara menguranginya — tanpa mengorbankan keandalan — adalah keterampilan penting untuk tim yang mengelola infrastruktur besar.

flowchart TD
    A["terraform plan"] --> B["Refresh state\n(API calls)"]
    B --> C["Compare with\nconfig"]
    C --> D["Generate plan"]
    B --> E["100 resources\n= 100+ API calls"]
    E --> F["Slow plan\n~20 min"]

    style A fill:#3b82f6,stroke:#1e40af,color:#fff
    style B fill:#f59e0b,stroke:#d97706,color:#fff
    style C fill:#8b5cf6,stroke:#6d28d9,color:#fff
    style D fill:#10b981,stroke:#059669,color:#fff
    style E fill:#ef4444,stroke:#dc2626,color:#fff
    style F fill:#ef4444,stroke:#dc2626,color:#fff

Mengukur Waktu Sebelum Optimasi #

# Selalu ukur sebelum optimasi — jangan asumsi di mana bottleneck-nya

# Aktifkan logging detail
TF_LOG=INFO terraform plan 2>&1 | grep -E "provider|Refreshing|Reading"

# Atau gunakan timestamp untuk setiap fase
time terraform init
time terraform plan
time terraform apply

# Untuk profiling yang lebih detail (Terraform 1.2+)
TF_LOG=TRACE terraform plan 2>&1 | grep "provider.aws" | tail -50
# Ini menampilkan semua API call ke AWS provider

# Output yang perlu diperhatikan:
# [INFO] provider.aws: Refreshing state... (aws_instance.web)
# → Setiap baris ini adalah satu API call
# → Jika ada ratusan baris, ini sumber lambatnya

-refresh=false: Lewati Refresh State #

# ANTI-PATTERN: Selalu refresh (default)
terraform plan
# → Terraform memanggil API cloud untuk setiap resource di state
# → 200 resource = 200 API call sebelum plan mulai
# → Bisa memakan waktu menit jika banyak resource

# BENAR: Skip refresh jika state sudah diketahui akurat
terraform plan -refresh=false
# → Langsung bandingkan konfigurasi dengan state yang ada
# → Jauh lebih cepat, tapi tidak mendeteksi drift

# Kapan -refresh=false AMAN digunakan:
# ✓ Pipeline CI/CD di mana tidak ada yang bisa ubah infrastruktur di luar Terraform
# ✓ Saat iterasi cepat saat develop konfigurasi baru
# ✓ Setelah apply baru saja dijalankan (state pasti akurat)

# Kapan -refresh=false TIDAK AMAN:
# ✗ Jika ada kemungkinan perubahan manual di cloud
# ✗ Untuk drift detection (justru butuh refresh)
# ✗ Sebelum apply ke production yang sudah lama tidak di-plan

Parallelism: Kontrol Concurrency #

Terraform secara default menjalankan maksimal 10 operasi secara bersamaan. Untuk resource yang independen, meningkatkan angka ini bisa mempercepat apply. Tapi terlalu tinggi bisa menyebabkan API throttling dari cloud provider.

# Default parallelism adalah 10
terraform apply

# Naikkan untuk infrastruktur dengan banyak resource independen
terraform apply -parallelism=20

# Turunkan jika sering kena API rate limit
terraform apply -parallelism=5

# Untuk AWS: rate limit berbeda per service
# EC2: cukup tinggi (bisa parallelism 20+)
# IAM: lebih ketat (tetap di 5-10)
# CloudFormation: sangat ketat (turun ke 3-5)

# Temukan nilai optimal dengan eksperimen:
for p in 5 10 15 20; do
  echo "Testing parallelism=$p"
  time terraform apply -parallelism=$p -auto-approve
done

Optimasi Data Source #

Data source yang tidak perlu adalah salah satu penyebab tersembunyi plan yang lambat — setiap data source menghasilkan setidaknya satu API call.

# ANTI-PATTERN: Data source yang dipanggil terlalu sering
# Setiap resource memanggil data source sendiri-sendiri
resource "aws_instance" "web_1" {
  ami = data.aws_ami.ubuntu.id  # 1 API call
}
resource "aws_instance" "web_2" {
  ami = data.aws_ami.ubuntu.id  # API call yang sama lagi (tapi Terraform cache-nya)
}
# Terraform otomatis cache data source yang sama — ini sebenarnya OK

# Yang BENAR-BENAR bermasalah: data source dengan filter yang berat
data "aws_instances" "all_running" {
  filter {
    name   = "instance-state-name"
    values = ["running"]
  }
  # Ini list SEMUA running instance → mahal jika ada ribuan instance
}

# BENAR: Gunakan filter yang lebih spesifik
data "aws_instances" "web_fleet" {
  filter {
    name   = "tag:Role"
    values = ["web-server"]
  }
  filter {
    name   = "tag:Environment"
    values = ["production"]
  }
  # Filter ketat → API call lebih ringan
}
# ANTI-PATTERN: Data source untuk nilai yang sudah diketahui
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}

# Jika region dan account ID sudah diketahui dan tidak berubah,
# lebih efisien menggunakan variable atau local
locals {
  region     = "ap-southeast-1"
  account_id = "123456789012"
}

# Data source tetap berguna untuk nilai yang memang dinamis
# (AMI terbaru, AZ yang available, dll.)

-target: Operasi Tertentu Saja #

-target memungkinkan kamu menjalankan plan atau apply hanya pada resource tertentu, mengabaikan yang lain.

# Hanya plan resource tertentu
terraform plan -target=aws_instance.web
terraform plan -target=module.database

# Hanya apply resource tertentu
terraform apply -target=aws_security_group.new_rule

# Berguna untuk:
# ✓ Debug — isolasi resource yang bermasalah
# ✓ Bootstrap — buat resource yang dibutuhkan sebelum yang lain
# ✓ Emergency fix — perbaiki satu resource tanpa risiko ke yang lain
-target adalah alat untuk situasi khusus, bukan workflow rutin. Penggunaan berulang bisa menyebabkan state tidak konsisten — dependency graph Terraform tidak dijalankan penuh, sehingga perubahan pada resource yang di-target mungkin tidak mempropagasi ke resource yang bergantung padanya. Setelah menggunakan -target, selalu jalankan terraform plan tanpa target untuk memastikan tidak ada yang tertinggal.

Provider Cache #

Setiap kali terraform init dijalankan, Terraform mendownload provider. Di CI/CD yang sering dijalankan, ini memakan waktu dan bandwidth.

# Setup provider cache (di CI/CD atau lokal)
export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache"
mkdir -p $TF_PLUGIN_CACHE_DIR

# Sekarang terraform init akan cek cache sebelum download
terraform init
# Jika provider sudah di cache → langsung gunakan, tidak download ulang

# Di GitHub Actions: cache provider dengan actions/cache
- name: Cache Terraform Plugins
  uses: actions/cache@v4
  with:
    path: ~/.terraform.d/plugin-cache
    key: ${{ runner.os }}-terraform-${{ hashFiles('**/.terraform.lock.hcl') }}
    restore-keys: |
      ${{ runner.os }}-terraform-

- name: Terraform Init
  run: terraform init
  env:
    TF_PLUGIN_CACHE_DIR: ~/.terraform.d/plugin-cache

Mengoptimalkan terraform init #

# ANTI-PATTERN: terraform init yang download ulang setiap saat
terraform init  # Selalu download dari registry

# BENAR: Gunakan -upgrade hanya saat memang perlu upgrade provider
terraform init          # Gunakan versi yang sudah di-lock
terraform init -upgrade # Hanya saat ingin upgrade ke versi terbaru

# Untuk CI/CD: skip backend init jika tidak perlu
terraform init -backend=false  # Untuk validate saja, tanpa akses state

# Waktu benchmark tipikal:
# terraform init tanpa cache:   30-60 detik (download provider)
# terraform init dengan cache:  2-5 detik (copy dari cache)
# Selisih ini signifikan jika pipeline berjalan puluhan kali sehari

flowchart LR
    A["Split\nstate"] --> B["-target\nspecific"]
    B --> C["Parallel\nexecution"]
    C --> D["Caching\nprovider"]
    D --> E["Fast plan\n~2 min"]

    style A fill:#3b82f6,stroke:#1e40af,color:#fff
    style B fill:#3b82f6,stroke:#1e40af,color:#fff
    style C fill:#8b5cf6,stroke:#6d28d9,color:#fff
    style D fill:#8b5cf6,stroke:#6d28d9,color:#fff
    style E fill:#10b981,stroke:#059669,color:#fff

Parallelism Tuning #

Terraform bisa membuat resource secara paralel. Mengatur parallelism bisa mempercepat apply.

# Default: 10 resource paralel
terraform apply

# Naikkan untuk infrastruktur besar
terraform apply -parallelism=20

# Turunkan jika API rate-limited
terraform apply -parallelism=3

# Untuk provider yang sensitif terhadap concurrent request
# (misalnya: beberapa SaaS API)
terraform apply -parallelism=1
# Monitoring waktu eksekusi
time terraform plan
time terraform apply -auto-approve

# Terraform trace logging untuk debugging performa
TF_LOG=TRACE terraform plan 2>&1 | tee trace.log
# Cari "applyable" untuk melihat resource mana yang lambat

Provider Caching #

# Enable provider plugin caching untuk percepat init
# ~/.terraformrc:
# provider_cache {
#   dir = "$HOME/.terraform.d/plugin-cache"
# }

# Atau set via environment variable
export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache"
terraform init
# Provider hanya di-download sekali, workspace lain pakai cache

# Bersihkan cache jika perlu
rm -rf $TF_PLUGIN_CACHE_DIR/*
# Gunakan data source yang efisien
# BURUK: Mengambil semua instance
data "aws_instances" "all" {}

# BAIK: Filter spesifik
data "aws_instances" "web" {
  filter {
    name   = "tag:Role"
    values = ["web"]
  }
}

Plan Caching #

# Terraform tidak cache plan secara native
# Tapi ada beberapa strategi untuk percepat:

# 1. Simpan plan output dan apply nanti
terraform plan -out=plan.cache
terraform apply plan.cache
# Menghindari re-plan yang bisa memakan waktu

# 2. Targeted refresh (hanya resource yang berubah)
terraform plan -target=aws_instance.web
# Berguna saat development, JANGAN di production

# 3. Reduce data source calls
# Kurangi jumlah data source, gunakan locals caching

# 4. Parallel backend initialization
# Terraform init bisa mendownload provider secara parallel
terraform init -plugin-dir=/shared/plugin-cache

Provider Plugin Caching #

# Cache provider plugins untuk percepat init
mkdir -p ~/.terraform.d/plugin-cache

# ~/.terraformrc
# plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"

# Atau set via environment variable
export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache"

# Di CI/CD: persist cache antara runs
# GitHub Actions:
- uses: actions/cache@v3
  with:
    path: ~/.terraform.d/plugin-cache
    key: terraform-providers-${{ hashFiles('.terraform.lock.hcl') }}
# Shared plugin cache untuk team
# Simpan di shared filesystem atau S3
terraform init -plugin-dir=/shared/terraform/plugins

Ringkasan #

  • Ukur dulu, optimasi kemudian — aktifkan TF_LOG=INFO untuk melihat API call mana yang paling banyak memakan waktu sebelum memutuskan cara optimasi.
  • -refresh=false adalah optimasi terbesar untuk CI/CD yang dikontrol ketat — melewati ratusan API call refresh bisa memotong waktu plan dari menit menjadi detik.
  • Parallelism bisa dinaikkan dari default 10 untuk infrastruktur besar, tapi turunkan jika sering kena API rate limit dari cloud provider.
  • Data source dengan filter longgar adalah bottleneck tersembunyi — filter seketat mungkin agar API response lebih kecil dan cepat.
  • Provider cache memotong waktu terraform init dari 30-60 detik menjadi 2-5 detik — wajib ada di CI/CD yang sering dijalankan.
  • -target untuk situasi khusus saja — setelah digunakan, selalu jalankan plan penuh untuk memastikan tidak ada inconsistency yang tertinggal.

← Sebelumnya: Scale Terraform   Berikutnya: Anti-Pattern: Terraform as CM →

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