Deklarasi Infrastruktur Skala Masif Menggunakan Terraform dan AWS EKS
1. Konteks Industri & Analisis Akar Masalah
Dalam lanskap enterprise modern, orkestrasi infrastruktur berbasis cloud telah bergeser dari pendekatan manual yang rentan kesalahan (imperative configuration) menuju otomatisasi penuh (declarative infrastructure). Penggunaan Terraform bersama Amazon Elastic Kubernetes Service (AWS EKS) menjadi standar emas industri untuk membangun klaster produksi yang scalable, aman, dan repeatable. Namun, mengelola infrastruktur skala masif menghadirkan tantangan kompleks yang sering kali memicu insiden sistemik.
Bottleneck Performa dan Keamanan Konvensional
Di banyak organisasi, kegagalan implementasi EKS berakar dari beberapa faktor krusial:
- Drift Konfigurasi: Perubahan manual pada konsol AWS membuat Terraform state tidak sinkron, berujung pada kegagalan apply berikutnya atau inkonsistensi lingkungan.
- State Management yang Rapuh: Penyimpanan file
terraform.tfstatesecara lokal atau pada backend tanpa locking yang memadai menyebabkan race condition dan korupsi state saat dikelola oleh tim multidisiplin. - Celah Keamanan Sisi Bidang Kontrol (Control Plane): Akses API server yang terbuka ke publik tanpa pembatasan CIDR yang ketat, otorisasi berbasis IAM yang longgar, serta kurangnya enkripsi secret at rest menggunakan KMS kustom.
- Manajemen Beban Kerja Web yang Tidak Optimal: Konfigurasi Ingress Controller (seperti Nginx atau AWS ALB Ingress) yang tidak disetel terhadap parameter keep-alive, worker connections, serta buffer limits untuk menangani high concurrency backend seperti Go/Node.js/PHP-FPM.
Perbandingan Kondisi: Sebelum vs Sesudah Penerapan Terraform & EKS Hardened
| Parameter | Sebelum (Manual / Skrip Bash / Konfigurasi Asal) | Sesudah (Declarative Terraform & Hardened EKS) |
|---|---|---|
| Waktu Provisioning | 3 - 5 Hari (rawan human error) | 15 - 20 Menit (Otomatis & Konsisten) |
| Keamanan Cluster | Endpoint publik terbuka, IAM berlebihan (wildcard) | Private Endpoint, IAM Roles for Service Accounts (IRSA), KMS Encryption |
| Manajemen State | File lokal, sering terjadi konflik tim | S3 Backend terenkripsi dengan DynamoDB State Locking |
| Skalabilitas Web Traffic | Manual scaling, sering down saat spike traffic | Horizontal Pod Autoscaler (HPA) & Cluster Autoscaler terintegrasi |
2. Konsep Inti & Deep Dive Arsitektur
Arsitektur deployment EKS berbasis Terraform memisahkan pengelolaan infrastruktur dasar (VPC, Subnet, IAM, KMS) dari pengelolaan aplikasi (Kubernetes Manifest, Helm Charts). Terraform bertindak sebagai orchestrator bagi AWS Cloud Control API, sementara AWS EKS mengelola Control Plane Kubernetes yang dikelola sepenuhnya oleh AWS.
Alur Eksekusi & State Management
+-----------------------------------------------------------------------+
| Developer / CI/CD |
+-----------------------------------------------------------------------+
|
v (terraform apply)
+-----------------------------------------------------------------------+
| Terraform Local Engine |
+-----------------------------------------------------------------------+
| ^
| (1. Acquire Lock) | (4. Release Lock)
v |
+------------------+ (2. Read/Write State) +---------------------+
| DynamoDB (Lock) |<---------------------------->| S3 Bucket (State) |
+------------------+ +---------------------+
|
v (3. Provision AWS Resources via API)
+-----------------------------------------------------------------------+
| AWS Cloud (VPC, IAM, KMS, EKS Control Plane, Managed Node Groups) |
+-----------------------------------------------------------------------+
Alur kerja dimulai dari inisialisasi modul Terraform, verifikasi state locking di DynamoDB untuk mencegah eksekusi paralel yang merusak data, hingga pengiriman permintaan API ke AWS untuk membentuk VPC terisolasi, IAM Role berhak ases minimum, dan klaster EKS.
3. Perbandingan Komparatif / Analisis Pendekatan
Dalam membangun node worker untuk aplikasi web skala besar (Go backend, Node.js API, PHP-FPM, dan caching Redis), pemilihan tipe instance AWS EC2 sangat menentukan performa dan efisiensi biaya (Cost-Performance Ratio).
| Komparasi Aspek | AWS Managed Node Groups (MNG) | Self-Managed Node Groups via ASG | Karpenter (Auto-Provisioning) |
|---|---|---|---|
| Otomasi Siklus Hidup | Otomatis oleh AWS (Rolling update mulus) | Manual / Skrip kustom diperlukan | Sangat otomatis, berbasis antrian pod |
| Efisiensi Biaya | Moderat (mengikuti tipe instance fix) | Bergantung pada pengelolaan ASG | Tinggi (memanfaatkan Spot Instance optimal) |
| Kompleksitas Setup | Rendah (bawaan modul Terraform EKS) | Tinggi (butuh konfigurasi user-data manual) | Sedang (membutuhkan Controller tambahan) |
| Latency Jaringan Pod | Standar CNI AWS (ENI-based) | Standar CNI AWS | Dioptimalkan dengan CNI kustom/ENI |
[!TIP] Untuk beban kerja enterprise dengan fluktuasi traffic web yang ekstrem (misalnya platform e-commerce saat flash sale), kombinasi AWS Managed Node Groups untuk system core pods dan Karpenter untuk application workload memberikan keseimbangan terbaik antara stabilitas dan efisiensi biaya.
4. Prasyarat Sistem & Persiapan Lingkungan
Sebelum menjalankan skrip Terraform, pastikan perangkat kerja (workstation atau CI/CD runner) memiliki dependensi berikut terinstal dengan versi minimal yang disyaratkan:
- Terraform CLI:
>= 1.5.0 - AWS CLI:
>= 2.13.0 - Kubectl: Versi yang selaras dengan minor version EKS (misal v1.28)
- Helm CLI:
>= 3.12.0
Verifikasi kredensial AWS dan hak akses IAM:
aws sts get-caller-identity
# Pastikan output menunjukkan IAM User/Role yang memiliki otorisasi AdministratorAccess atau policy set yang memadai.
Struktur direktori proyek Terraform yang direkomendasikan:
infra-eks-production/
├── backend.tf
├── provider.tf
├── variables.tf
├── main.tf
├── outputs.tf
└── modules/
├── vpc/
├── iam/
├── kms/
└── eks/
5. Panduan Implementasi Langkah demi Langkah
Langkah 1: Konfigurasi Backend & Provider (backend.tf & provider.tf)
File ini mendefinisikan penyimpanan state terpusat di S3 dengan penguncian DynamoDB.
# backend.tf
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
}
backend "s3" {
bucket = "enterprise-terraform-state-prod-us-east-1"
key = "eks/production/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "enterprise-terraform-locks-prod"
encrypt = true
}
}
# provider.tf
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
ManagedBy = "Terraform"
Project = "Enterprise-Web-Platform"
}
}
}
Langkah 2: Implementasi Modul VPC Utama (modules/vpc/main.tf)
Membuat VPC dengan isolasi Subnet Publik, Privat (untuk Node EKS), dan Database (untuk MySQL/Redis).
# modules/vpc/main.tf
variable "vpc_cidr" { type = string }
variable "environment" { type = string }
variable "availability_zones" { type = list(string) }
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "vpc-${var.environment}"
}
}
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.main.id
tags = { Name = "igw-${var.environment}" }
}
resource "aws_subnet" "public" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index)
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = {
Name = "subnet-public-${count.index}-${var.environment}"
"kubernetes.io/cluster/eks-${var.environment}" = "shared"
"kubernetes.io/role/elb" = "1"
}
}
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index + 4)
availability_zone = var.availability_zones[count.index]
tags = {
Name = "subnet-private-${count.index}-${var.environment}"
"kubernetes.io/cluster/eks-${var.environment}" = "shared"
"kubernetes.io/role/internal-elb" = "1"
}
}
resource "aws_eip" "nat" {
count = length(var.availability_zones)
domain = "vpc"
tags = { Name = "eip-nat-${count.index}-${var.environment}" }
}
resource "aws_nat_gateway" "nat" {
count = length(var.availability_zones)
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
tags = { Name = "nat-gw-${count.index}-${var.environment}" }
depends_on = [aws_internet_gateway.gw]
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}
tags = { Name = "rt-public-${var.environment}" }
}
resource "aws_route_table" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat[count.index].id
}
tags = { Name = "rt-private-${count.index}-${var.environment}" }
}
resource "aws_route_table_association" "public" {
count = length(var.availability_zones)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "private" {
count = length(var.availability_zones)
subnet_id = aws_subnet.private[count.index].id
route_table_id = aws_route_table.private[count.index].id
}
output "vpc_id" { value = aws_vpc.main.id }
output "private_subnet_ids" { value = aws_subnet.private[*].id }
output "public_subnet_ids" { value = aws_subnet.public[*].id }
Langkah 3: Konfigurasi Keamanan KMS & IAM untuk Klaster EKS (modules/iam/main.tf & modules/kms/main.tf)
# modules/kms/main.tf
variable "environment" { type = string }
resource "aws_kms_key" "eks" {
description = "KMS Key untuk Enkripsi Secrets EKS ${var.environment}"
deletion_window_in_days = 30
enable_key_rotation = true
tags = { Name = "kms-eks-${var.environment}" }
}
output "key_arn" { value = aws_kms_key.eks.arn }
# modules/iam/main.tf
variable "environment" { type = string }
resource "aws_iam_role" "cluster" {
name = "eks-cluster-role-${var.environment}"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "eks.amazonaws.com"
}
}]
})
}
resource "aws_iam_role_policy_attachment" "cluster_amazon_eks_cluster_policy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
role = aws_iam_role.cluster.name
}
resource "aws_iam_role" "node" {
name = "eks-node-role-${var.environment}"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}]
})
}
resource "aws_iam_role_policy_attachment" "node_policies" {
for_each = toset([
"arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy",
"arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy",
"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
])
policy_arn = each.value
role = aws_iam_role.node.name
}
output "cluster_role_arn" { value = aws_iam_role.cluster.arn }
output "node_role_arn" { value = aws_iam_role.node.arn }
Langkah 4: Modul Klaster EKS & Managed Node Groups (modules/eks/main.tf)
# modules/eks/main.tf
variable "environment" { type = string }
variable "cluster_version" { type = string }
variable "vpc_id" { type = string }
variable "subnet_ids" { type = list(string) }
variable "cluster_role_arn" { type = string }
variable "node_role_arn" { type = string }
variable "kms_key_arn" { type = string }
resource "aws_security_group" "cluster" {
name = "eks-cluster-sg-${var.environment}"
description = "Security group untuk EKS control plane"
vpc_id = var.vpc_id
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = { Name = "sg-eks-cluster-${var.environment}" }
}
resource "aws_eks_cluster" "main" {
name = "eks-${var.environment}"
version = var.cluster_version
role_arn = var.cluster_role_arn
encryption_config {
provider { key_arn = var.kms_key_arn }
resources = ["secrets"]
}
vpc_config {
subnet_ids = var.subnet_ids
endpoint_private_access = true
endpoint_public_access = true
public_access_cidrs = ["192.0.2.0/24"] # Batasi IP management kantor/bastion
security_group_ids = [aws_security_group.cluster.id]
}
depends_on = [aws_security_group.cluster]
}
resource "aws_eks_node_group" "app" {
cluster_name = aws_eks_cluster.main.name
node_group_name = "app-workers-${var.environment}"
node_role_arn = var.node_role_arn
subnet_ids = var.subnet_ids
instance_types = ["t3.xlarge"]
scaling_config {
desired_size = 3
max_size = 10
min_size = 2
}
update_config {
max_unavailable = 1
}
depends_on = [aws_eks_cluster.main]
}
output "cluster_endpoint" { value = aws_eks_cluster.main.endpoint }
output "cluster_name" { value = aws_eks_cluster.main.name }
Langkah 5: Orkestrasi Utama (main.tf)
# main.tf
variable "aws_region" { default = "us-east-1" }
variable "environment" { default = "production" }
variable "vpc_cidr" { default = "10.100.0.0/16" }
module "vpc" {
source = "./modules/vpc"
environment = var.environment
vpc_cidr = var.vpc_cidr
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
module "kms" {
source = "./modules/kms"
environment = var.environment
}
module "iam" {
source = "./modules/iam"
environment = var.environment
}
module "eks" {
source = "./modules/eks"
environment = var.environment
cluster_version = "1.28"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
cluster_role_arn = module.iam.cluster_role_arn
node_role_arn = module.iam.node_role_arn
kms_key_arn = module.kms.key_arn
}
6. Bedah Kode & Penjelasan Detail Baris Kunci
encryption_configpadaaws_eks_cluster: Baris ini mengaktifkan enkripsi envelope menggunakan AWS KMS untuk objeksecretsKubernetes. Secara default, Kubernetes menyimpan secret dalam bentuk base64-encoded plain text di etcd. Dengan KMS terintegrasi, setiap rahasia database credential atau API key dienkripsi sebelum disimpan secara fisik.public_access_cidrs: Pengaturan ini membatasi alamat IP mana saja yang dapat mengakses API Server EKS publik. Mengganti0.0.0.0/0dengan CIDR IP kantor atau VPN internal (bastion host) mencegah eksploitasi eksternal dari penyerang internet.enable_key_rotation = true: Properti pada modul KMS memastikan kepatuhan regulasi keamanan enterprise dengan merotasi kunci enkripsi secara otomatis setiap tahun tanpa mengganggu akses data eksisting.
7. Skenario Produksi & Studi Kasus Dunia Nyata
Sebuah perusahaan fintech dengan platform berbasis Node.js & Go mengalami lonjakan traffic transaksi sebesar 500% pada jam sibuk (08.00 - 10.00 WIB). Konfigurasi infrastruktur di atas dioptimalkan dengan penambahan:
- Horizontal Pod Autoscaler (HPA) yang memantau metrik CPU utilization pod melampaui 70%. Ketika tercapai, Kubernetes secara otomatis mereplikasi kontainer web server dari 3 pod menjadi 25 pod dalam hitungan detik.
- AWS Application Load Balancer (ALB) Ingress Controller yang mendistribusikan lalu lintas secara merata ke node worker melalui pemanfaatan Target Group dalam mode
ip, memangkas network latency hop internal.
8. Common Pitfalls, Anti-Patterns & Solusi
[!WARNING] Anti-Pattern Berbahaya: Menggunakan satu file state Terraform (
terraform.tfstate) monolitis untuk seluruh infrastruktur global (VPC, EKS, Database RDS, DNS Route53, dan S3 Bucket aset web). Ketika terjadi korupsi state pada salah satu resource, seluruh infrastruktur tertahan (locked).
Solusi: Terapkan state separation dan gunakan direktori atau workspace terpisah (misalnya memisahkan modul VPC, EKS, dan Storage ke dalam root module independen atau state file yang berbeda).
Kesalahan umum lainnya adalah mengabaikan manajemen versi provider AWS tanpa menyematkan operator spesifik (~> 5.0), yang dapat menyebabkan perubahan breaking changes saat Terraform melakukan auto-upgrade modul provider.
9. Benchmark, Metrik Kinerja & Tuning Performa
Untuk memvalidasi kesiapan klaster EKS dalam menangani beban tinggi, lakukan pengujian menggunakan tool benchmarking modern seperti k6.
Skrip uji k6 sederhana (load-test.js):
import http from 'k6/http';
import { sleep, check } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 100 }, // Ramp-up ke 100 virtual users
{ duration: '5m', target: 500 }, // Beban puncak 500 concurrent users
{ duration: '2m', target: 0 }, // Ramp-down
],
};
export default function () {
const res = http.get('https://api.enterprise.internal/v1/health');
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(1);
}
Jalankan perintah:
k6 run load-test.js
Parameter Tuning Lanjutan pada Node Worker Linux (sysctl):
# Optimasi parameter jaringan untuk handle ribuan koneksi web paralel
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=16384
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
10. Checklist Penerapan Produksi & Kesimpulan
Sebelum meluncurkan klaster ke lingkungan live produksi, pastikan seluruh item dalam checklist berikut telah terpenuhi:
- State Terraform diamankan di S3 dengan enkripsi AES-256 dan DynamoDB Locking aktif.
- EKS Control Plane menggunakan Endpoint Privat dan publik dibatasi hanya untuk CIDR tepercaya.
- Enkripsi Secret at Rest menggunakan kunci AWS KMS kustom dengan rotasi aktif.
- Modul VPC memisahkan subnet Publik, Privat (EKS), dan Database secara ketat.
- Kebijakan IAM menerapkan prinsip least-privilege tanpa penggunaan wildcard yang berlebihan.
- Autoscaling (HPA & Cluster Autoscaler / Karpenter) telah diuji dengan simulasi load testing.
Dengan mematuhi panduan komprehensif ini, Anda telah membangun fondasi arsitektur cloud enterprise yang tangguh, aman, dan siap mengakselerasi pertumbuhan sistem web skala masif secara berkelanjutan.