Locking #

Bayangkan dua engineer menjalankan terraform apply secara bersamaan terhadap state yang sama. Tanpa locking, kedua proses bisa membaca state yang sama, membuat perubahan yang saling bertentangan, dan menimpa satu sama lain — menghasilkan state yang tidak konsisten dengan kondisi aktual infrastruktur. State locking mencegah ini dengan memastikan hanya satu proses yang bisa memodifikasi state pada satu waktu.

Mengapa Locking Diperlukan #

flowchart TD
    subgraph "Tanpa Locking"
        A1["Engineer A\nterraform apply"] --> R1["Baca state v1"]
        A2["Engineer B\nterraform apply"] --> R2["Baca state v1"]
        R1 --> W1["Tulis state v2\n(create instance-X)"]
        R2 --> W2["Tulis state v3\n(create instance-Y)"]
        W1 -.->|"Ditimpa"| LOST["Perubahan A\nhilang!"]
        W2 --> STATE3["State v3\nHanya instance-Y"]
    end

    subgraph "Dengan Locking"
        B1["Engineer A\nterraform apply"] --> LOCK["LOCK acquired"]
        B2["Engineer B\nterraform apply"] --> WAIT["Tunggu lock\nrelease..."]
        LOCK --> DONE1["Apply selesai\nLock release"]
        DONE1 --> LOCK2["LOCK acquired\noleh B"]
        LOCK2 --> DONE2["Apply selesai\nLock release"]
    end

    style LOST fill:#ffebee,stroke:#c62828
    style STATE3 fill:#ffebee,stroke:#c62828
    style DONE2 fill:#e8f5e9,stroke:#2e7d32
TANPA LOCKING — APA YANG BISA TERJADI:

  T+0s  Engineer A: terraform apply (baca state, rencanakan +3 resource)
  T+1s  Engineer B: terraform apply (baca state yang SAMA, rencanakan +2 resource)
  T+10s Engineer A: selesai apply, tulis state dengan 3 resource baru
  T+12s Engineer B: selesai apply, tulis state dengan 2 resource baru
  T+12s → State sekarang hanya punya 2 resource B, 3 resource A HILANG dari state
  T+12s → Resource A masih ada di cloud tapi Terraform tidak tahu
  T+12s → Terraform state tidak konsisten dengan realita

DENGAN LOCKING:

  T+0s  Engineer A: terraform apply → LOCK acquired ✅
  T+1s  Engineer B: terraform apply → Error: state is locked ❌
  T+10s Engineer A: selesai → LOCK released
  T+11s Engineer B: terraform apply → LOCK acquired ✅ (state sudah up-to-date)

Cara Kerja Locking #

State locking bekerja dengan prinsip yang sama di semua backend — hanya mekanisme penyimpanan lock-nya yang berbeda.

flowchart TD
    A["terraform apply\natau terraform plan"] --> B["Coba acquire\nstate lock"]
    B --> C{"Lock\nberhasil?"}
    C -->|"Ya"| D["Baca state\nHitung perubahan\nApply"]
    D --> E["Tulis state baru\nRelease lock"]
    C -->|"Tidak"| F["Error:\nError acquiring the state lock"]
    F --> G{"Lock\nstale?"}
    G -->|"Ya"| H["terraform force-unlock\n<LOCK_ID>"]
    G -->|"Tidak"| I["Tunggu atau\nbatalkan operasi"]

    style E fill:#e8f5e9,stroke:#2e7d32
    style F fill:#ffebee,stroke:#c62828
BackendMekanisme Locking
S3 + DynamoDBDynamoDB table — item dengan conditional write
Azure BlobBlob lease — 30 detik default
GCSGCS object — generation number
Terraform CloudBuilt-in — managed oleh platform
ConsulKey-value lock session
Local.tfstate.lock.info file

Locking dengan S3 Backend (DynamoDB) #

# S3 backend dengan DynamoDB locking
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/network/terraform.tfstate"
    region         = "ap-southeast-1"
    dynamodb_table = "terraform-locks"  # Tabel DynamoDB untuk locking
    encrypt        = true
  }
}
# Tabel DynamoDB yang dibutuhkan
resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

Error: State Locked #

# Error yang muncul saat state sedang di-lock oleh proses lain
$ terraform apply

Error: Error acquiring the state lock

Error message: ConditionalCheckFailedException: The conditional request
failed
Lock Info:
  ID:        a1b2c3d4-e5f6-7890-abcd-ef1234567890
  Path:      my-terraform-state/prod/network/terraform.tfstate
  Operation: OperationTypeApply
  Who:       engineer@hostname
  Version:   1.7.0
  Created:   2024-01-15 10:30:00.000000000 +0000

Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again.

Force Unlock #

terraform force-unlock digunakan untuk melepas lock yang tersisa dari proses yang gagal atau crash. Gunakan dengan hati-hati.

# Cek dulu apakah proses lain benar-benar sudah selesai/crash
# JANGAN force-unlock jika proses lain masih berjalan!

# Force unlock dengan ID dari error message
terraform force-unlock a1b2c3d4-e5f6-7890-abcd-ef1234567890

# Force unlock dengan auto-approve (skip konfirmasi)
terraform force-unlock -force a1b2c3d4-e5f6-7890-abcd-ef1234567890
Hati-hati dengan force-unlock. Hanya gunakan ketika kamu yakin tidak ada proses Terraform lain yang sedang berjalan. Melepak lock saat proses lain aktif bisa menyebabkan state corruption — masalah yang jauh lebih burah daripada lock yang tersisa. Selalu cek dengan tim sebelum melakukan force-unlock.

Best Practice untuk Locking #

CI/CD PIPELINE:
  ✓ Pastikan setiap pipeline menggunakan backend dengan locking aktif
  ✓ Jangan jalankan multiple pipeline untuk state yang sama secara paralel
  ✓ Gunakan pipeline stages yang sequential untuk environment yang sama
  ✓ Set timeout pada pipeline — lock tidak boleh ditahan terlalu lama

TIM KOLABORATIF:
  ✓ Gunakan remote backend dengan locking (S3+DynamoDB, TF Cloud, dll)
  ✓ Tidak ada alasan untuk menggunakan local backend di tim > 1 orang
  ✓ Komunikasikan siapa yang sedang melakukan apply di channel tim
  ✓ Hindari terraform force-unlock tanpa koordinasi

LOCK STALE:
  ✓ Lock dianggap stale jika proses yang mengambilnya sudah crash
  ✓ Cek apakah proses Terraform masih berjalan sebelum force-unlock
  ✓ Di CI/CD, pastikan pipeline di-cancel dengan SIGINT (bukan SIGKILL)
    agar Terraform bisa release lock secara graceful


Locking Best Practices #

# Selalu gunakan locking untuk state di lingkungan tim
# Backend S3: wajib konfigurasi dynamodb_table
# Backend GCS: locking built-in
# Terraform Cloud: locking built-in

# Konfigurasi lock timeout untuk CI/CD
terraform apply -lock-timeout=5m

# Monitor lock usage di DynamoDB
aws dynamodb scan --table-name terraform-state-lock
# DynamoDB table untuk locking
resource "aws_dynamodb_table" "terraform_lock" {
  name         = "terraform-state-lock"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

Troubleshooting Lock Issues #

Lock issues adalah salah satu masalah yang paling sering dihadapi dalam tim.

# Masalah: "Error: Error acquiring the state lock"
# Artinya: ada proses lain yang sedang menggunakan state

# 1. Cek siapa yang pegang lock
aws dynamodb get-item \
  --table-name terraform-state-lock \
  --key '{"LockID":{"S":"my-bucket/env:/terraform.tfstate"}}'

# Output berisi info siapa yang lock:
# {
#   "LockID": {"S": "my-bucket/env:/terraform.tfstate"},
#   "Info": {"S": "{"who":"hostname","version":"1.6.3","created":"2024-01-15T10:30:00Z"}"}
# }

# 2. Jika lock stuck (process sudah mati), force unlock
terraform force-unlock LOCK_ID
# LOCK_ID bisa dilihat dari error message atau DynamoDB

# 3. HATI-HATI: force-unlock saat ada process lain berjalan
# = state corruption! Pastikan tidak ada yang sedang apply

# 4. Pencegahan: gunakan lock timeout
terraform apply -lock-timeout=30s
flowchart TD
    A["terraform apply"] --> B{"Lock
available?"}
    B -->|"Ya"| C["Acquire lock
& proceed"]
    B -->|"Tidak"| D["Tunggu
(lock timeout)"]
    D --> E{"Timeout
expired?"}
    E -->|"Belum"| B
    E -->|"Ya"| F["Error: cannot
acquire lock"]
    F --> G{"Stuck
lock?"}
    G -->|"Ya"| H["terraform
force-unlock"]
    G -->|"Tidak"| I["Tunggu process
lain selesai"]

    style A fill:#e3f2fd,stroke:#1565c0
    style C fill:#e8f5e9,stroke:#2e7d32
    style F fill:#ffebee,stroke:#c62828
    style H fill:#fff3e0,stroke:#e65100

Lock Monitoring di Production #

# Script monitoring lock status
#!/bin/bash
TABLE="terraform-state-lock"

echo "=== Active Terraform Locks ==="
aws dynamodb scan --table-name $TABLE --output table

# Alerting: kirim notifikasi jika lock terlalu lama
LOCK_ITEMS=$(aws dynamodb scan --table-name $TABLE --output json)
LOCK_COUNT=$(echo $LOCK_ITEMS | jq '.Items | length')

if [ "$LOCK_COUNT" -gt 0 ]; then
  echo "WARNING: $LOCK_COUNT active lock(s) found!"
  # Kirim alert ke Slack/PagerDuty
fi

State Locking Internals #

Terraform menggunakan conditional writes untuk memastikan atomicity dari operasi lock.

LOCK MECHANISM DETAIL:

1. terraform apply dimulai
2. Terraform buat lock entry di backend:
   - LockID: path ke state file
   - Info: JSON {who, version, created, path}
   - TTL: tidak ada expiry (sampai unlock)

3. Semua operasi state dicek lock-nya
4. Jika lock sudah ada → error
5. Setelah selesai → delete lock entry

ATOMICITY GUARANTEE:
- Backend S3 + DynamoDB: DynamoDB conditional put
- Backend GCS: GCS preconditions
- Backend Consul: Consul KV transactions
- Semua memastikan hanya 1 writer
# Backend configuration yang robust
terraform {
  backend "s3" {
    bucket         = "terraform-state-prod"
    key            = "infrastructure/terraform.tfstate"
    region         = "ap-southeast-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
    
    # Recommended: use specific KMS key
    kms_key_id = "arn:aws:kms:ap-southeast-1:123456:key/abc-123"
  }
}

Distributed Locking Patterns #

DISTRIBUTED LOCK PATTERN:

Worker A                  DynamoDB                   Worker B
   |                         |                          |
   |--- AcquireLock -------->|                          |
   |<-- LockGranted ---------|                          |
   |                         |<--- AcquireLock ---------|
   |                         |--- LockDenied ---------->|
   |--- DoWork ------------>|                          |
   |--- ReleaseLock -------->|                          |
   |                         |<--- AcquireLock ---------|
   |                         |--- LockGranted --------->|
# Monitoring lock contention
# CloudWatch alarm untuk DynamoDB throttling
resource "aws_cloudwatch_metric_alarm" "lock_contention" {
  alarm_name          = "terraform-lock-contention"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  metric_name         = "ThrottledRequests"
  namespace           = "AWS/DynamoDB"
  period              = 300
  statistic           = "Sum"
  threshold           = 5
  alarm_description   = "Terraform state lock contention detected"
  dimensions = {
    TableName = "terraform-state-lock"
  }
}
# Diagnostic commands
# Cek siapa yang pegang lock
aws dynamodb get-item   --table-name terraform-state-lock   --key '{"LockID":{"S":"bucket/key/terraform.tfstate"}}'

# Force unlock (HATI-HATI!)
terraform force-unlock <LOCK_ID>
# Hanya gunakan jika 100% yakin tidak ada process lain

Ringkasan #

  • State locking mencegah concurrent write — hanya satu proses yang bisa memodifikasi state pada satu waktu, mencegah state corruption.
  • Backend remote umumnya sudah include locking — S3+DynamoDB, GCS, Azure Blob, dan Terraform Cloud semuanya punya mekanisme locking built-in.
  • Error “state is locked” adalah fitur keamanan — bukan bug. Ini berarti proses lain sedang berjalan.
  • terraform force-unlock dengan hati-hati — hanya gunakan setelah memastikan tidak ada proses lain yang aktif.
  • CI/CD harus sequential untuk state yang sama — jangan jalankan multiple pipeline yang beroperasi pada state yang sama secara bersamaan.
  • Locking + remote backend adalah standar minimum untuk tim yang berkolaborasi — local backend tidak punya perlindungan ini.

← Sebelumnya: Lifecycle   Berikutnya: State →

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