Struktur #
Module yang ditulis dengan baik bukan hanya soal kode yang benar — tapi soal kode yang mudah dipahami dan dipakai orang lain. Struktur file yang konsisten, README yang informatif, dan penamaan yang jelas adalah perbedaan antara module yang langsung dipercaya dan dipakai, dengan module yang membuat orang ragu dan akhirnya menulis ulang sendiri. Artikel ini membahas konvensi struktural yang diterima luas di komunitas Terraform.
Struktur File Standar #
Komunitas Terraform dan HashiCorp sendiri merekomendasikan struktur minimal yang konsisten untuk setiap module.
modules/vpc/
├── main.tf ← Resource utama — isi utama module
├── variables.tf ← Semua input variable dengan deskripsi lengkap
├── outputs.tf ← Semua output dengan deskripsi penggunaan
├── versions.tf ← Terraform dan provider version constraints
└── README.md ← Dokumentasi: penggunaan, input, output, contoh
File tambahan yang mungkin dibutuhkan untuk module yang lebih kompleks:
modules/vpc/
├── main.tf
├── variables.tf
├── outputs.tf
├── versions.tf
├── README.md
├── locals.tf ← Local values yang dipakai di seluruh module
├── data.tf ← Data source yang dibutuhkan module
└── examples/ ← Contoh penggunaan yang bisa langsung dijalankan
├── basic/
│ ├── main.tf
│ └── README.md
└── complete/
├── main.tf
└── README.md
versions.tf — Version Constraints Module #
Setiap module sebaiknya mendefinisikan versi Terraform dan provider minimum yang dibutuhkan. Ini mencegah module dijalankan di versi yang tidak kompatibel.
# modules/vpc/versions.tf
terraform {
required_version = ">= 1.3.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
# Gunakan >= bukan ~> di module — biarkan root module yang pin versi spesifik
# Module yang terlalu ketat soal versi menyulitkan pengguna
}
}
}
Di module, gunakan constraint>=(minimal version) bukan~>(pessimistic constraint). Root module yang bertanggung jawab memilih versi spesifik — module hanya perlu menyatakan versi minimum yang dibutuhkan agar fitur yang digunakan tersedia.
README.md yang Berguna #
README adalah hal pertama yang dilihat seseorang sebelum memutuskan apakah mau menggunakan module. README yang baik menjawab tiga pertanyaan: apa yang dilakukan module ini, bagaimana cara menggunakannya, dan apa yang akan didapat.
# Module: VPC
Module ini membuat VPC standar dengan public dan private subnet,
Internet Gateway, NAT Gateway, dan routing table yang dikonfigurasi
dengan benar untuk setiap tier.
## Penggunaan
```hcl
module "vpc" {
source = "../../modules/vpc"
cidr_block = "10.0.0.0/16"
environment = "production"
public_subnet_count = 3
private_subnet_count = 3
}
Input #
| Nama | Deskripsi | Tipe | Default | Wajib |
|---|---|---|---|---|
cidr_block | CIDR block untuk VPC | string | — | Ya |
environment | Nama environment | string | — | Ya |
public_subnet_count | Jumlah public subnet | number | 2 | Tidak |
private_subnet_count | Jumlah private subnet | number | 2 | Tidak |
Output #
| Nama | Deskripsi |
|---|---|
vpc_id | ID VPC yang dibuat |
public_subnet_ids | List ID public subnet |
private_subnet_ids | List ID private subnet |
Requirements #
| Nama | Versi |
|---|---|
| terraform | >= 1.3.0 |
| aws | >= 5.0 |
---
## Pengorganisasian Module dalam Repository
Ada dua pendekatan umum untuk mengorganisasi module: monorepo dan multirepo. Untuk tim yang baru memulai, monorepo adalah titik awal yang lebih sederhana.
MONOREPO — semua module dalam satu repository:
infrastructure/ ├── modules/ │ ├── vpc/ │ │ ├── main.tf │ │ ├── variables.tf │ │ ├── outputs.tf │ │ └── README.md │ ├── eks/ │ │ └── … │ ├── rds/ │ │ └── … │ └── iam-role/ │ └── … └── environments/ ├── dev/ │ └── main.tf ← source = “../../modules/vpc” ├── staging/ │ └── main.tf └── production/ └── main.tf
MULTIREPO — setiap module dalam repository terpisah:
github.com/org/terraform-module-vpc/ ├── main.tf ├── variables.tf ├── outputs.tf └── README.md
github.com/org/terraform-module-eks/ └── …
Pemanggil menggunakan Git URL sebagai source: #
module “vpc” { source = “git::https://github.com/org/terraform-module-vpc.git?ref=v2.1.0”
… #
}
---
## Konvensi Penamaan Internal Module
Di dalam module, ada konvensi penamaan yang membantu konsistensi dan keterbacaan.
```hcl
# KONVENSI: Gunakan "this" untuk resource utama di module single-purpose
# (module yang dibuat untuk satu jenis resource utama)
resource "aws_vpc" "this" { # Bukan "main" atau nama spesifik
cidr_block = var.cidr_block
}
resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.this.id
}
# Output menggunakan nama yang deskriptif dari perspektif pemanggil
output "vpc_id" {
value = aws_vpc.this.id # Bukan "this_id" — lebih jelas untuk pemanggil
}
# KONVENSI: Prefix resource dengan nama module jika ada ambiguitas
# (module yang membuat beberapa jenis resource)
resource "aws_security_group" "web" { # "web" lebih deskriptif dari "this"
name = "${var.name}-web-sg"
}
resource "aws_security_group" "db" {
name = "${var.name}-db-sg"
}
Struktur Module yang Kompleks #
Untuk module yang lebih besar, pertimbangkan memisahkan logik ke beberapa file berdasarkan komponen.
modules/eks-cluster/
├── main.tf ← EKS cluster resource utama
├── node-groups.tf ← Node group resources
├── iam.tf ← IAM roles dan policies
├── security-groups.tf ← Security group resources
├── addons.tf ← EKS add-ons (CoreDNS, kube-proxy, dll.)
├── variables.tf ← Semua input variable
├── outputs.tf ← Semua output
├── locals.tf ← Local values dan kalkulasi
├── data.tf ← Data sources (AZ, AMI, dll.)
├── versions.tf ← Version constraints
└── README.md
Ringkasan #
- Struktur minimal module:
main.tf,variables.tf,outputs.tf,versions.tf, danREADME.md— konsistensi ini membuat siapapun langsung orientasi.versions.tfdi module menggunakan>=bukan~>— biarkan root module yang pin versi spesifik, module hanya nyatakan minimum.- README adalah dokumentasi utama — jawab tiga pertanyaan: apa yang dilakukan, bagaimana cara pakai, dan apa yang didapat (tabel input/output).
- Gunakan
thissebagai nama resource utama di module single-purpose — mengurangi ambiguitas saat pemanggil membaca output module.- Monorepo untuk memulai — lebih mudah dikelola, refactoring lebih mudah, discovery lebih mudah sebelum ada kebutuhan multirepo.
- Pisah file berdasarkan komponen untuk module yang kompleks —
iam.tf,security-groups.tf,node-groups.tflebih mudah dinavigasi dari satumain.tfraksasa.
← Sebelumnya: Apa itu Module? Berikutnya: Root vs Child Module →