Versioning #

Module tanpa versioning adalah module yang tidak bisa dipercaya untuk production. Bayangkan dua tim menggunakan module VPC yang sama — tim A di-apply hari ini, tim B apply minggu depan. Jika di antara itu ada perubahan di module yang breaking, tim B akan mendapat hasil yang berbeda dari tim A tanpa ada peringatan apapun. Versioning adalah mekanisme yang memastikan setiap pemanggil mendapat versi module yang sama dengan yang mereka pilih, sampai mereka memutuskan untuk upgrade.

Mengapa Module Perlu Versi #

TANPA VERSIONING:

Team A: terraform apply hari Senin
  → Menggunakan module VPC versi "terbaru"
  → Berhasil, infrastruktur berjalan

Developer module: commit perubahan ke module (Selasa)
  → Mengubah output dari "subnet_id" ke "subnet_ids" (breaking change)

Team B: terraform apply hari Rabu
  → Menggunakan module VPC versi "terbaru" (yang berbeda!)
  → ERROR: "module.vpc.subnet_id" tidak ada
  → Team B bingung — konfigurasi mereka tidak berubah

DENGAN VERSIONING:

module "vpc" {
  source  = "git::https://github.com/org/tf-module-vpc.git?ref=v1.2.0"
}

Team A dan Team B keduanya menggunakan v1.2.0 → hasil yang sama.
Developer module rilis v2.0.0 dengan breaking change.
Team B tidak akan terdampak sampai mereka memutuskan upgrade ke v2.0.0.

Semantic Versioning untuk Module #

Module Terraform mengikuti konvensi semantic versioning (semver): MAJOR.MINOR.PATCH.

SEMANTIC VERSIONING:

v1.2.3
│ │ │
│ │ └── PATCH: Bug fix, tidak ada perubahan interface
│ │         v1.2.3 → v1.2.4: Fix bug di security group rule
│ │
│ └──── MINOR: Fitur baru, backward compatible
│           v1.2.0 → v1.3.0: Tambah support untuk IPv6 (opsional)
│           Pengguna v1.2.0 tidak terpengaruh
│
└────── MAJOR: Breaking change
            v1.x.x → v2.0.0: Rename output "subnet_id" → "subnet_ids"
            Semua pengguna v1.x.x harus update konfigurasi sebelum upgrade

CONTOH CHANGELOG YANG BAIK:

v2.0.0 (Breaking Change)
  BREAKING: Output "subnet_id" diganti menjadi "subnet_ids" (list)
  BREAKING: Variable "az_count" dihapus, gunakan "subnet_count"
  NEW: Support untuk NAT Gateway per-AZ

v1.3.0
  NEW: Tambah variable "enable_ipv6" (default: false)
  NEW: Output "ipv6_cidr_block" ditambahkan
  FIX: Security group tidak menghapus rule lama saat update

v1.2.4
  FIX: Subnet CIDR kalkulasi error saat VPC CIDR lebih kecil dari /16

Membuat Rilis Module di Git #

Untuk module yang disimpan di Git repository, versi ditentukan oleh Git tag.

# Workflow rilis module:

# 1. Pastikan semua perubahan sudah di-commit dan di-test
git add -A
git commit -m "feat: tambah support NAT Gateway per-AZ"

# 2. Buat tag dengan format v<MAJOR>.<MINOR>.<PATCH>
git tag v1.3.0

# 3. Push tag ke remote
git push origin v1.3.0

# 4. Opsional: buat GitHub Release dengan changelog
# (bisa lewat UI atau GitHub CLI)
gh release create v1.3.0 \
  --title "v1.3.0 — NAT Gateway per-AZ" \
  --notes "NEW: Support NAT Gateway per-AZ via variable enable_nat_per_az"
# Pemanggil menggunakan tag sebagai referensi versi
module "vpc" {
  source = "git::https://github.com/org/terraform-module-vpc.git?ref=v1.3.0"

  cidr_block  = "10.0.0.0/16"
  environment = var.environment
}

Versioning di Terraform Registry #

Untuk module yang dipublikasikan ke Terraform Registry (public atau private), versioning lebih formal dan menggunakan argumen version.

# Terraform Registry — versi dikontrol dengan version constraint
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.1"
  # ~> 5.1 = >=5.1.0, <6.0.0

  name = "production-vpc"
  cidr = "10.0.0.0/16"
}

# Constraint yang lebih ketat untuk production
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "= 20.2.1"
  # Pin ke versi exact — tidak ada surprise update
}
# ANTI-PATTERN: Tanpa version constraint di Registry module
module "vpc" {
  source = "terraform-aws-modules/vpc/aws"
  # Tidak ada version — setiap terraform init bisa mendapat versi berbeda!
}

Strategi Upgrade yang Aman #

Mengupgrade versi module, terutama untuk MAJOR version, perlu dilakukan dengan hati-hati.

# WORKFLOW UPGRADE MODULE:

# 1. Baca CHANGELOG versi baru — cari breaking change
# 2. Test di environment dev/staging dulu
# 3. Jalankan terraform plan setelah update versi

# Perubahan di konfigurasi:
# Dari:
# source = "git::...?ref=v1.2.0"
# Ke:
# source = "git::...?ref=v2.0.0"

# 4. Baca output plan dengan cermat
terraform plan
# Perhatikan resource mana yang akan di-replace
# Breaking change di module sering menyebabkan resource di-replace

# 5. Jika ada replace yang tidak diinginkan, pertimbangkan:
#    - Apakah perlu moved block untuk rename resource?
#    - Apakah perlu tahap migrasi sebelum upgrade penuh?
# Contoh: module merename resource internal dari v1 ke v2
# Tanpa moved block, Terraform akan destroy + create

# Di konfigurasi root (bukan di module):
moved {
  from = module.vpc.aws_subnet.public
  to   = module.vpc.aws_subnet.public_tier  # Nama baru di module v2
}

Mengelola Breaking Change sebagai Penulis Module #

# STRATEGI 1: Deprecation dengan backward compatibility sementara
# Beri masa transisi sebelum benar-benar hapus variable/output lama

variable "subnet_id" {
  description = "DEPRECATED: Gunakan subnet_ids. Akan dihapus di v3.0."
  type        = string
  default     = null

  validation {
    condition     = var.subnet_id == null
    error_message = "subnet_id sudah deprecated, gunakan subnet_ids (list)."
    # Atau biarkan berjalan tapi log warning via null_resource
  }
}

variable "subnet_ids" {
  description = "List ID subnet. Gantikan subnet_id yang deprecated."
  type        = list(string)
  default     = []
}

locals {
  # Kompatibilitas backward: jika subnet_id diisi, jadikan list
  effective_subnet_ids = (
    length(var.subnet_ids) > 0
    ? var.subnet_ids
    : var.subnet_id != null ? [var.subnet_id] : []
  )
}

Ringkasan #

  • Versioning adalah kebutuhan, bukan pilihan — tanpa versi, dua tim yang apply di waktu berbeda bisa mendapat hasil yang berbeda.
  • Semantic versioning: PATCH untuk bug fix, MINOR untuk fitur backward-compatible, MAJOR untuk breaking change.
  • Git tag sebagai versi untuk module di Git repo — ?ref=v1.2.0 di source URL.
  • version constraint di Terraform Registry — gunakan ~> untuk fleksibilitas patch/minor, = untuk pin ketat di production.
  • Jangan pernah module tanpa version constraint untuk source dari Registry — setiap terraform init bisa mendapat versi berbeda.
  • Upgrade major version secara bertahap — test di dev/staging dulu, baca output plan dengan cermat, gunakan moved block jika ada rename resource internal.

← Sebelumnya: Root vs Child Module   Berikutnya: Interface Design →

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