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.0di source URL.versionconstraint 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 initbisa mendapat versi berbeda.- Upgrade major version secara bertahap — test di dev/staging dulu, baca output plan dengan cermat, gunakan
movedblock jika ada rename resource internal.
← Sebelumnya: Root vs Child Module Berikutnya: Interface Design →