1. Konsep Infrastructure as Code
Infrastructure as Code (IaC) adalah pendekatan pengelolaan infrastruktur IT melalui kode yang dapat dibaca manusia, bukan melalui konfigurasi manual melalui web console. Dengan IaC, Anda bisa membuat, memodifikasi, dan menghapus infrastruktur cloud secara konsisten dan reproducible.
Terraform adalah tool IaC open-source yang dikembangkan oleh HashiCorp. Terraform menggunakan bahasa deklaratif bernama HCL (HashiCorp Configuration Language) untuk mendeskripsikan infrastruktur yang diinginkan, lalu menghitung dan menjalankan langkah-langkah yang diperlukan untuk mencapai state tersebut.
Mengapa Terraform?
| Keunggulan | Penjelasan |
|---|---|
| Multi-Cloud | Bisa mengelola infrastruktur di AWS, GCP, Azure, dan 1000+ provider lainnya |
| Declarative | Cukup deskripsikan akhir state yang diinginkan, Terraform menangani cara mencapainya |
| Version Control | Infrastruktur di-version sebagai kode di Git β bisa track perubahan dan rollback |
| Reusable | Modul bisa digunakan kembali di berbagai project dan environment |
| Planning | Fitur terraform plan menunjukkan perubahan sebelum diterapkan |
| State Tracking | Terraform melacak state aktual infrastruktur dan membandingkannya dengan desired state |
| Dependency Graph | Secara otomatis menentukan urutan pembuatan resource berdasarkan dependency |
IaC vs Manual Provisioning
| Aspek | Manual (Console) | IaC (Terraform) |
|---|---|---|
| Kecepatan | π΄ Lambat, satu per satu | π’ Cepat, sekaligus |
| Konsistensi | π΄ Rentan human error | π’ Identik setiap kali |
| Dokumentasi | π΄ Dokumentasi terpisah | π’ Kode = dokumentasi |
| Reproduksi | π΄ Sulit mengulang | π’ Jalankan ulang kapan saja |
| Collaboration | π΄ Satu orang tahu | π’ Semua orang bisa baca kode |
| Rollback | π΄ Manual dan rumit | π’ terraform apply versi sebelumnya |
| Scalability | π΄ Tidak practical | π’ Scale dengan mudah |
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β TERRAFORM WORKFLOW β β β β ββββββββββββ ββββββββββββ ββββββββββββ β β β 1. Write βββββΆβ 2. Plan βββββΆβ 3. Apply β β β β Code β β β β β β β β (.tf) β β Preview β β Execute β β β ββββββββββββ β Changes β β Changes β β β β ββββββββββββ ββββββββββββ β β β β β β β βΌ βΌ βΌ β β ββββββββββββ ββββββββββββ ββββββββββββ β β β HCL β β Diff: β β API β β β β Config β β Current β β Calls to β β β β Files β β vs β β Cloud β β β β β β Desired β β Provider β β β ββββββββββββ ββββββββββββ ββββββββββββ β β β β β βΌ β β ββββββββββββ β β β State β β β β File β β β β (tfstate)β β β ββββββββββββ β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Install Terraform
# βββ macOS (Homebrew) βββ brew tap hashicorp/tap brew install hashicorp/tap/terraform # βββ Ubuntu/Debian βββ wget -O- https://apt.releases.hashicorp.com/gpg | \ sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \ sudo tee /etc/apt/sources.list.d/hashicorp.list sudo apt update && sudo apt install terraform # βββ Windows (Chocolatey) βββ choco install terraform # βββ Verifikasi instalasi βββ terraform version # Terraform v1.10.x on linux_amd64 # βββ Setup autocomplete (opsional) βββ terraform -install-autocomplete
Terraform tersedia dalam versi open-source (gratis) dan Terraform Cloud/Enterprise (berbayar). Untuk belajar dan proyek kecil, versi open-source sudah sangat cukup. Terraform Cloud menambahkan fitur team collaboration, remote state management, dan policy enforcement.
2. HCL Syntax
HCL (HashiCorp Configuration Language) adalah bahasa deklaratif yang digunakan oleh Terraform untuk mendeskripsikan infrastruktur. HCL dirancang agar mudah dibaca manusia sekaligus bisa diproses oleh mesin.
Dasar HCL
# βββ Struktur dasar HCL βββ
# block_type "label" "label" {
# key = value
# nested_block {
# key = value
# }
# }
# βββ Tipe Data βββ
# String
app_name = "beebane-api"
# Number
instance_count = 3
# Boolean
enable_monitoring = true
# List
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
# Map
tags = {
Environment = "production"
Project = "beebane"
ManagedBy = "terraform"
}
# βββ Variable Declarations βββ
variable "region" {
description = "AWS region untuk deployment"
type = string
default = "ap-southeast-1" # Singapore
}
variable "instance_type" {
description = "Tipe EC2 instance"
type = string
default = "t3.micro"
}
variable "enable_ssl" {
description = "Aktifkan SSL certificate"
type = bool
default = true
}
variable "allowed_ports" {
description = "Daftar port yang diizinkan"
type = list(number)
default = [80, 443, 22]
}
variable "environment_config" {
description = "Konfigurasi per environment"
type = map(object({
instance_type = string
min_size = number
max_size = number
}))
default = {
dev = {
instance_type = "t3.micro"
min_size = 1
max_size = 2
}
staging = {
instance_type = "t3.small"
min_size = 1
max_size = 3
}
production = {
instance_type = "t3.medium"
min_size = 2
max_size = 10
}
}
}
# βββ Output Declarations βββ
output "instance_public_ip" {
description = "Public IP dari EC2 instance"
value = aws_instance.web_server.public_ip
}
output "database_endpoint" {
description = "Endpoint database RDS"
value = aws_db_instance.main.endpoint
sensitive = true # Tidak ditampilkan di terminal
}
# βββ Locals β computed values βββ
locals {
common_tags = {
Project = var.project_name
Environment = var.environment
ManagedBy = "terraform"
CreatedAt = timestamp()
}
name_prefix = "${var.project_name}-${var.environment}"
}
Expressions & Functions
# βββ Conditional Expressions βββ
instance_type = var.environment == "production" ? "t3.medium" : "t3.micro"
# βββ For Expressions βββ
# Create list dari transformation
instance_ids = [for instance in aws_instance.server : instance.id]
# Create map dari list
instance_map = { for az in var.availability_zones : az => "${az}-instance" }
# Filter
public_instances = [for i in aws_instance.server : i if i.public_ip != ""]
# βββ Splat Expression βββ
# Shortcut untuk [for x in list : x.attribute]
instance_ids = aws_instance.server[*].id
# βββ String Interpolation βββ
name_tag = "${var.project_name}-${var.environment}-server"
# βββ Built-in Functions βββ
# String functions
upper("hello") # "HELLO"
lower("WORLD") # "world"
format("Hello, %s!", var.name) # "Hello, Budi!"
join(", ", ["a", "b", "c"]) # "a, b, c"
split(",", "a,b,c") # ["a", "b", "c"]
replace("hello-world", "-", "_") # "hello_world"
trimspace(" hello ") # "hello"
# Number functions
max(5, 12, 9) # 12
min(5, 12, 9) # 5
ceil(4.2) # 5
floor(4.8) # 4
# Collection functions
length(["a", "b", "c"]) # 3
contains(["a", "b"], "a") # true
flatten([["a", "b"], ["c"]]) # ["a", "b", "c"]
distinct(["a", "b", "a"]) # ["a", "b"]
merge({a=1}, {b=2}) # {a=1, b=2}
lookup({a=1, b=2}, "a", 0) # 1
# File functions
file("${path.module}/config.json")
templatefile("${path.module}/init.tpl", { name = "server1" })
filebase64("${path.module}/cert.pem")
# Crypto functions
md5("hello")
sha256("hello")
bcrypt("password")
# Date/Time
timestamp() # "2026-06-25T10:00:00Z"
formatdate("DD MMM YYYY", timestamp()) # "25 Jun 2026"
# IP functions
cidrsubnet("10.0.0.0/16", 8, 1) # "10.0.1.0/24"
cidrhost("10.0.1.0/24", 5) # "10.0.1.5"
Terraform mendukung dua format file: .tf (HCL) dan .tf.json (JSON). HCL lebih mudah dibaca dan merupakan format yang direkomendasikan. JSON berguna untuk programmatically generate config, tetapi jauh lebih verbose dan sulit dibaca.
3. Providers
Provider adalah plugin Terraform yang berinteraksi dengan API cloud provider, SaaS, atau service lainnya. Provider meng-ekspose resource dan data source yang bisa Anda gunakan dalam konfigurasi Terraform. Terraform memiliki 3000+ provider dari berbagai vendor.
Provider Configuration
# βββ providers.tf βββ
# Required providers β mendefinisikan provider yang dibutuhkan
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
# Remote state storage (S3)
backend "s3" {
bucket = "beebane-terraform-state"
key = "prod/terraform.tfstate"
region = "ap-southeast-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
# βββ AWS Provider βββ
provider "aws" {
region = var.aws_region
profile = "beebane"
default_tags {
tags = {
Environment = var.environment
ManagedBy = "terraform"
Project = "beebane"
}
}
}
# βββ Google Cloud Provider βββ
provider "google" {
project = var.gcp_project_id
region = var.gcp_region
}
# βββ Azure Provider βββ
provider "azurerm" {
features {}
subscription_id = var.azure_subscription_id
}
# βββ Multiple AWS Regions βββ
# Untuk deploy ke beberapa region sekaligus
provider "aws" {
alias = "us_east"
region = "us-east-1"
}
provider "aws" {
alias = "eu_west"
region = "eu-west-1"
}
Install & Manage Providers
# βββ Inisialisasi Terraform (download providers) βββ terraform init # Output: # Initializing the backend... # Initializing provider plugins... # - Finding hashicorp/aws versions matching "~> 5.0"... # - Installing hashicorp/aws v5.82.2... # Terraform has been successfully initialized! # βββ Upgrade provider ke versi terbaru (sesuai constraint) βββ terraform init -upgrade # βββ Format kode HCL agar konsisten βββ terraform fmt terraform fmt -recursive # Termasuk sub-folder # βββ Validasi konfigurasi βββ terraform validate # βββ Lihat daftar provider yang digunakan βββ terraform providers # βββ Lihat dependency tree βββ terraform graph | dot -Tpng > graph.png
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β TERRAFORM PROVIDER ECOSYSTEM β β β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β Terraform Core β β β β β’ HCL Parser β’ State Manager β β β β β’ Plan/Apply β’ Dependency Graph β β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β β β βββββββββββββββββββΌββββββββββββββββββ β β βΌ βΌ βΌ β β ββββββββββββ ββββββββββββ ββββββββββββββββ β β β AWS β β Google β β Kubernetes β β β β Providerβ β Cloud β β Provider β β β β β β Providerβ β β β β β β’ EC2 β β β’ GCE β β β’ Pods β β β β β’ S3 β β β’ GKE β β β’ Services β β β β β’ RDS β β β’ Cloud β β β’ Deploymentsβ β β β β’ VPC β β SQL β β β’ Ingress β β β β β’ Lambda β β β’ Cloud β β β β β β β’ EKS β β Run β β β β β ββββββββββββ ββββββββββββ ββββββββββββββββ β β β β 3000+ Providers tersedia di registry.terraform.io β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Gunakan version constraint untuk menghindari breaking changes. Tanda ~> 5.0 berarti "gunakan versi 5.x terbaru, tetapi jangan upgrade ke 6.0". Tanda = 5.82.2 berarti "gunakan persis versi ini". Untuk production, selalu pin versi dengan ketat.
4. Resources & Data Sources
Resource adalah blok yang mendeskripsikan satu atau lebih infrastruktur objects β seperti EC2 instance, VPC, S3 bucket, atau DNS record. Data source memungkinkan Anda mengambil data dari provider yang sudah ada (bukan membuat baru) untuk digunakan dalam konfigurasi.
Resource Blocks
# βββ main.tf β AWS EC2 Instance βββ
# VPC β Virtual Private Cloud
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${local.name_prefix}-vpc"
}
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${local.name_prefix}-igw"
}
}
# Public Subnet
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet("10.0.0.0/16", 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${local.name_prefix}-public-${count.index + 1}"
Tier = "public"
}
}
# Private Subnet
resource "aws_subnet" "private" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet("10.0.0.0/16", 8, count.index + 10)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${local.name_prefix}-private-${count.index + 1}"
Tier = "private"
}
}
# Security Group
resource "aws_security_group" "web" {
name = "${local.name_prefix}-web-sg"
description = "Security group untuk web server"
vpc_id = aws_vpc.main.id
# Allow HTTP
ingress {
description = "HTTP"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Allow HTTPS
ingress {
description = "HTTPS"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Allow SSH (hanya dari IP tertentu)
ingress {
description = "SSH"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.admin_ip]
}
# Allow all outbound
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${local.name_prefix}-web-sg"
}
}
# EC2 Instance
resource "aws_instance" "web_server" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
subnet_id = aws_subnet.public[0].id
vpc_security_group_ids = [aws_security_group.web.id]
key_name = var.ssh_key_name
root_block_device {
volume_size = 30
volume_type = "gp3"
encrypted = true
}
user_data = base64encode(templatefile("${path.module}/scripts/init.sh", {
app_name = var.project_name
}))
tags = {
Name = "${local.name_prefix}-web-server"
}
lifecycle {
create_before_destroy = true
prevent_destroy = false
}
}
Data Sources
# βββ Data Sources β Mengambil informasi dari provider βββ
# Ambil daftar availability zones
data "aws_availability_zones" "available" {
state = "available"
}
# Ambil AMI Ubuntu terbaru
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# Ambil informasi caller (current AWS account)
data "aws_caller_identity" "current" {}
# Ambil IP publik saat ini (untuk SSH access)
data "http" "my_ip" {
url = "https://api.ipify.org"
}
# Menggunakan data source
output "account_id" {
value = data.aws_caller_identity.current.account_id
}
output "ubuntu_ami_id" {
value = data.aws_ami.ubuntu.id
}
output "my_public_ip" {
value = data.http.my_ip.response_body
}
# Data source dari Terraform state lain
data "terraform_remote_state" "network" {
backend = "s3"
config = {
bucket = "beebane-terraform-state"
key = "network/terraform.tfstate"
region = "ap-southeast-1"
}
}
Terraform Lifecycle & Meta-Arguments
# βββ count β Membuat multiple resource βββ
resource "aws_instance" "server" {
count = var.instance_count
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
subnet_id = aws_subnet.public[count.index % length(aws_subnet.public)]
tags = {
Name = "${local.name_prefix}-server-${count.index + 1}"
}
}
# βββ for_each β Membuat resource dari map/set βββ
resource "aws_s3_bucket" "buckets" {
for_each = toset(["logs", "assets", "backups"])
bucket = "${local.name_prefix}-${each.key}"
tags = {
Name = "${local.name_prefix}-${each.key}"
Type = each.value
}
}
# βββ depends_on β Explicit dependency βββ
resource "aws_instance" "app" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
depends_on = [
aws_internet_gateway.main,
aws_security_group.web,
]
}
# βββ lifecycle β Control resource behavior βββ
resource "aws_db_instance" "main" {
engine = "postgres"
engine_version = "16"
instance_class = "db.t3.micro"
allocated_storage = 20
db_name = "beebane"
username = var.db_username
password = var.db_password
skip_final_snapshot = false
final_snapshot_identifier = "${local.name_prefix}-db-final-snapshot"
lifecycle {
prevent_destroy = true # JANGAN HAPUS database ini!
ignore_changes = [password] # Abaikan perubahan password
}
}
Gunakan count untuk membuat N resource yang identik. Gunakan for_each ketika resource memiliki nama/konfigurasi yang berbeda satu sama lain. Peringatan: Hindari menggunakan count dengan list yang bisa berubah urutan β ini bisa menyebabkan resource yang tidak seharusnya berubah jadi di-replace.
5. State Management
State adalah file JSON yang berisi mapping antara konfigurasi Terraform dan resource aktual di infrastruktur. State memungkinkan Terraform mengetahui resource apa saja yang sudah dibuat, atributnya, dan dependency-nya. Tanpa state, Terraform tidak bisa menentukan perubahan apa yang perlu dilakukan.
Local vs Remote State
# βββ Local State (default) βββ
# File: terraform.tfstate di direktori kerja
# β οΈ JANGAN commit ke Git β bisa mengandung secrets!
# β οΈ Tidak aman untuk team collaboration
# βββ Remote State β S3 Backend (recommended) βββ
terraform {
backend "s3" {
bucket = "beebane-terraform-state"
key = "production/terraform.tfstate"
region = "ap-southeast-1"
dynamodb_table = "terraform-locks" # State locking
encrypt = true # Enkripsi at rest
}
}
# βββ Remote State β Terraform Cloud βββ
terraform {
cloud {
organization = "beebane-labs"
workspaces {
name = "production"
}
}
}
# βββ State Locking (menghindari race condition) βββ
# Saat menggunakan S3 backend, DynamoDB table diperlukan:
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
Terraform CLI Commands
# βββ WORKFLOW: init β plan β apply β destroy βββ # 1. Initialize β Download providers dan backend terraform init # 2. Format β Rapihkan kode terraform fmt -recursive # 3. Validate β Cek syntax terraform validate # 4. Plan β Preview perubahan yang akan dilakukan terraform plan terraform plan -out=tfplan # Simpan plan ke file terraform plan -var="instance_type=t3.medium" # Override variable # 5. Apply β Terapkan perubahan ke infrastruktur terraform apply terraform apply tfplan # Apply dari file plan terraform apply -auto-approve # Skip confirmation prompt terraform apply -target=aws_instance.web_server # Target spesifik # 6. Destroy β Hapus semua resource (GUNAKAN DENGAN HATI-HATI!) terraform destroy terraform destroy -target=aws_instance.web_server # Target spesifik # βββ STATE COMMANDS βββ # Lihat state list terraform state list # Lihat detail resource terraform state show aws_instance.web_server # Import existing resource ke Terraform state terraform import aws_instance.web_server i-1234567890abcdef0 # Remove resource dari state (tanpa menghapus resource aktual) terraform state rm aws_instance.web_server # Move resource dalam state (rename) terraform state mv aws_instance.old_name aws_instance.new_name # Refresh state dari infrastructure aktual terraform refresh # Taint β Tandai resource untuk di-replace saat apply berikutnya terraform taint aws_instance.web_server # (deprecated, gunakan -replace flag) terraform apply -replace=aws_instance.web_server # βββ WORKSPACE COMMANDS βββ terraform workspace list terraform workspace new staging terraform workspace select production
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β STATE MANAGEMENT ARCHITECTURE β β β β ββββββββββββ ββββββββββββββββββββ β β β .tf ββββββββββΆβ Terraform β β β β Config β β Engine β β β ββββββββββββ ββββββββ¬ββββββββββββ β β β β β ββββββββββΌβββββββββββ β β β State File β β β β (tfstate) β β β β β β β β β’ Resource IDs β β β β β’ Attributes β β β β β’ Dependencies β β β β β’ Outputs β β β ββββββββββ¬βββββββββββ β β β β β ββββββββββΌβββββββββββ β β β Remote Backend β β β β (S3 + DynamoDB) β β β β β β β β Encrypted β β β β Locked β β β β Shared β β β ββββββββββββββββββββ β β β β β οΈ JANGAN edit state file secara manual! β β β οΈ Selalu gunakan remote backend untuk production! β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- JANGAN commit
*.tfstateke Git β file ini bisa berisi password, API keys, dan secrets - Tambahkan
*.tfstatedan*.tfstate.backupke.gitignore - Gunakan remote backend (S3, GCS, Terraform Cloud) dengan enkripsi untuk production
- Aktifkan state locking (DynamoDB) untuk menghindari race condition saat banyak orang apply
- Gunakan
sensitive = truepada output yang mengandung data sensitif
6. Modules
Module adalah kumpulan file Terraform (.tf) yang dikemas bersama untuk digunakan kembali. Module memungkinkan Anda mengorganisir kode, membagikannya ke tim, dan menghindari duplikasi. Setiap direktori yang berisi file .tf adalah sebuah module.
Root Module vs Child Module
# βββ STRUKTUR DIREKTORI βββ
#
# project/
# βββ main.tf β Root module (panggil child modules)
# βββ variables.tf
# βββ outputs.tf
# βββ providers.tf
# βββ modules/
# βββ vpc/
# β βββ main.tf
# β βββ variables.tf
# β βββ outputs.tf
# βββ ec2/
# β βββ main.tf
# β βββ variables.tf
# β βββ outputs.tf
# βββ rds/
# βββ main.tf
# βββ variables.tf
# βββ outputs.tf
# βββ modules/vpc/main.tf β Child Module βββ
resource "aws_vpc" "this" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.name_prefix}-vpc"
Environment = var.environment
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.this.id
cidr_block = var.public_subnets[count.index]
availability_zone = var.availability_zones[count.index]
tags = {
Name = "${var.name_prefix}-public-${count.index + 1}"
}
}
resource "aws_subnet" "private" {
count = length(var.private_subnets)
vpc_id = aws_vpc.this.id
cidr_block = var.private_subnets[count.index]
availability_zone = var.availability_zones[count.index]
tags = {
Name = "${var.name_prefix}-private-${count.index + 1}"
}
}
# βββ modules/vpc/variables.tf βββ
variable "vpc_cidr" {
type = string
default = "10.0.0.0/16"
}
variable "name_prefix" { type = string }
variable "environment" { type = string }
variable "availability_zones" { type = list(string) }
variable "public_subnets" { type = list(string) }
variable "private_subnets" { type = list(string) }
# βββ modules/vpc/outputs.tf βββ
output "vpc_id" {
value = aws_vpc.this.id
}
output "public_subnet_ids" {
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
value = aws_subnet.private[*].id
}
Using Modules
# βββ Menggunakan Local Module βββ
module "vpc" {
source = "./modules/vpc"
name_prefix = local.name_prefix
environment = var.environment
vpc_cidr = "10.0.0.0/16"
availability_zones = ["ap-southeast-1a", "ap-southeast-1b"]
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnets = ["10.0.10.0/24", "10.0.11.0/24"]
}
module "ec2" {
source = "./modules/ec2"
name_prefix = local.name_prefix
environment = var.environment
subnet_ids = module.vpc.public_subnet_ids
# Menggunakan output dari module VPC!
}
# βββ Menggunakan Remote Module (Terraform Registry) βββ
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.1.2"
name = "${local.name_prefix}-vpc"
cidr = "10.0.0.0/16"
azs = ["ap-southeast-1a", "ap-southeast-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
tags = {
Environment = var.environment
ManagedBy = "terraform"
}
}
# βββ Output dari Module βββ
output "vpc_id" {
value = module.vpc.vpc_id
}
output "public_subnets" {
value = module.vpc.public_subnet_ids
}
Best Practices untuk Modules
- Single Responsibility β Setiap module menangani satu concern (VPC, EC2, RDS)
- Parameterize β Gunakan variable untuk input yang berbeda, bukan hardcode
- Document β Tulis README.md untuk setiap module dengan usage example
- Version β Gunakan version pinning untuk remote modules
- Test β Gunakan
terratestatautflintuntuk testing module - Output β Ekspose semua informasi yang dibutuhkan caller melalui outputs
- Terraform Registry β Publish module yang reusable ke registry untuk sharing
# βββ tflint β Terraform Linter βββ # Install brew install tflint # Run tflint --init tflint --recursive # βββ terraform validate βββ terraform validate # Success! The configuration is valid. # βββ checkov β Security scanning βββ pip install checkov checkov -d . # βββ terraform-docs β Generate documentation βββ brew install terraform-docs terraform-docs markdown table ./modules/vpc > ./modules/vpc/README.md
Kunjungi registry.terraform.io untuk menemukan ribuan module dan provider yang sudah dibuat komunitas. Module populer seperti terraform-aws-modules/vpc sudah digunakan oleh ribuan perusahaan dan sangat teruji. Jangan reinvent the wheel β gunakan module yang sudah ada jika memungkinkan.
7. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Terraform dan Infrastructure as Code: