Apa itu Module? #
Bayangkan kamu perlu membuat infrastruktur yang sama — VPC dengan subnet publik dan privat, NAT gateway, dan routing yang benar — untuk environment dev, staging, dan production. Tanpa module, kamu menulis konfigurasi yang hampir identik tiga kali, lalu berjuang menjaga ketiganya tetap konsisten setiap kali ada perubahan. Module menyelesaikan ini dengan membungkus konfigurasi yang bisa dipakai ulang ke dalam satu unit yang bisa dipanggil berkali-kali dengan parameter yang berbeda, persis seperti memanggil fungsi dalam pemrograman.
Apa yang Dimaksud Module #
Module adalah direktori yang berisi satu atau lebih file konfigurasi Terraform (.tf). Setiap direktori Terraform adalah module — termasuk direktori tempat kamu bekerja sekarang, yang disebut root module. Yang membedakan adalah child module: direktori terpisah yang dipanggil dari module lain dengan blok module.
TANPA MODULE — konfigurasi diulang:
environments/
├── dev/
│ ├── main.tf ← vpc + subnet + igw + nat + routing (duplikat)
│ ├── variables.tf
│ └── outputs.tf
├── staging/
│ ├── main.tf ← vpc + subnet + igw + nat + routing (duplikat)
│ ├── variables.tf
│ └── outputs.tf
└── production/
├── main.tf ← vpc + subnet + igw + nat + routing (duplikat)
├── variables.tf
└── outputs.tf
DENGAN MODULE — konfigurasi dipanggil:
modules/
└── vpc/ ← satu konfigurasi VPC yang benar
├── main.tf
├── variables.tf
└── outputs.tf
environments/
├── dev/
│ └── main.tf ← module "vpc" { source = "../../modules/vpc" }
├── staging/
│ └── main.tf ← module "vpc" { source = "../../modules/vpc" }
└── production/
└── main.tf ← module "vpc" { source = "../../modules/vpc" }
Anatomi Module #
Sebuah module terdiri dari tiga komponen utama yang bekerja bersama.
modules/vpc/
├── main.tf ← Resource yang dibuat module ini
├── variables.tf ← Input yang diterima module (parameter)
└── outputs.tf ← Nilai yang diekspor module ke pemanggilnya
# modules/vpc/variables.tf — "parameter" module
variable "cidr_block" {
description = "CIDR block untuk VPC"
type = string
}
variable "environment" {
description = "Nama environment"
type = string
}
variable "public_subnet_count" {
description = "Jumlah public subnet yang dibuat"
type = number
default = 2
}
variable "private_subnet_count" {
description = "Jumlah private subnet yang dibuat"
type = number
default = 2
}
# modules/vpc/main.tf — implementasi internal module
resource "aws_vpc" "this" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.environment}-vpc"
Environment = var.environment
}
}
resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.this.id
tags = {
Name = "${var.environment}-igw"
Environment = var.environment
}
}
# ... subnet, routing table, NAT gateway, dll.
# modules/vpc/outputs.tf — nilai yang diekspor ke pemanggil
output "vpc_id" {
description = "ID VPC yang dibuat"
value = aws_vpc.this.id
}
output "public_subnet_ids" {
description = "List ID public subnet"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "List ID private subnet"
value = aws_subnet.private[*].id
}
Memanggil Module #
Module dipanggil dari root module atau module lain menggunakan blok module.
# environments/production/main.tf
module "vpc" {
source = "../../modules/vpc" # Path ke direktori module
# Input variable module — sesuai dengan variables.tf di module
cidr_block = "10.0.0.0/16"
environment = "production"
public_subnet_count = 3
private_subnet_count = 3
}
module "vpc_dev" {
source = "../../modules/vpc" # Module yang SAMA dipanggil dengan nilai berbeda
cidr_block = "10.1.0.0/16"
environment = "dev"
public_subnet_count = 1
private_subnet_count = 1
}
# Mengakses output module: module.<nama>.<output_name>
resource "aws_eks_cluster" "main" {
name = "production-eks"
vpc_config {
subnet_ids = module.vpc.private_subnet_ids # Output dari module vpc
}
}
Module adalah Abstraksi #
Keunggulan terbesar module bukan hanya reusabilitas — tapi abstraksi. Pemangil module tidak perlu tahu bagaimana VPC dibuat, hanya apa yang perlu diberikan dan apa yang akan diterima kembali.
DARI SUDUT PANDANG PEMANGGIL:
module "vpc" {
source = "../../modules/vpc"
cidr_block = "10.0.0.0/16" ← Input: yang perlu diberikan
environment = "production"
}
module.vpc.vpc_id ← Output: yang diterima kembali
module.vpc.private_subnet_ids
# Pemanggil tidak perlu tahu:
# - Berapa subnet yang dibuat secara internal
# - Bagaimana routing dikonfigurasi
# - Di AZ mana resource ditempatkan
# - Semua detail implementasi tersembunyi di dalam module
Ini membuat tim bisa bekerja di level abstraksi yang berbeda: tim platform menulis module, tim aplikasi menggunakan module tanpa perlu memahami detail jaringan.
Kapan Menulis Module #
Tidak semua konfigurasi perlu dibungkus dalam module. Ada sinyal yang menunjukkan sudah saatnya membuat module.
SUDAH SAATNYA MEMBUAT MODULE JIKA:
✓ Konfigurasi yang sama dipakai di lebih dari satu tempat
(minimal 2-3 kali penggunaan sebelum abstraksi layak)
✓ Ada sekelompok resource yang selalu dibuat bersama
dan punya makna sebagai satu unit (VPC + subnet + IGW + NAT)
✓ Tim lain butuh menggunakan infrastruktur yang sama
tanpa perlu memahami detail implementasinya
✓ Konfigurasi mengandung logic kompleks yang ingin disembunyikan
BELUM PERLU MODULE JIKA:
✗ Konfigurasi hanya dipakai di satu tempat
✗ Resource tidak ada hubungannya satu sama lain
✗ Hanya ingin "mengorganisir" file — gunakan file terpisah
di direktori yang sama (networking.tf, compute.tf, dll.)
✗ Module akan punya hanya 1-2 resource
Ringkasan #
- Module adalah direktori berisi file
.tf— setiap konfigurasi Terraform sudah berupa module, yang membedakan adalah apakah ia dipanggil sebagai child module.- Tiga komponen module:
variables.tf(input),main.tf(implementasi),outputs.tf(apa yang diekspor).- Module adalah abstraksi — pemanggil hanya perlu tahu input dan output, bukan detail implementasi di dalamnya.
- Panggil dengan blok
moduledan akses output denganmodule.<nama>.<output>.- Module yang sama bisa dipanggil berkali-kali dengan nilai yang berbeda — ini yang membuat konfigurasi multi-environment efisien.
- Buat module saat ada kebutuhan nyata (minimal 2-3 penggunaan) — jangan abstraksi prematur hanya karena terasa “lebih rapi”.
← Sebelumnya: Anti-Pattern Datasource Berikutnya: Struktur →