L
Infrastructure as Code (IaC) • Literally Web ID

Deklarasi Infrastruktur Skala Masif Menggunakan Terraform dan AWS EKS

⏱️ 18 menit baca • 📅 14 Oct 2026 • 👁️ 1 views
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:

  1. Drift Konfigurasi: Perubahan manual pada konsol AWS membuat Terraform state tidak sinkron, berujung pada kegagalan apply berikutnya atau inkonsistensi lingkungan.
  2. State Management yang Rapuh: Penyimpanan file terraform.tfstate secara lokal atau pada backend tanpa locking yang memadai menyebabkan race condition dan korupsi state saat dikelola oleh tim multidisiplin.
  3. 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.
  4. 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:

  1. Terraform CLI: >= 1.5.0
  2. AWS CLI: >= 2.13.0
  3. Kubectl: Versi yang selaras dengan minor version EKS (misal v1.28)
  4. 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_config pada aws_eks_cluster: Baris ini mengaktifkan enkripsi envelope menggunakan AWS KMS untuk objek secrets Kubernetes. 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. Mengganti 0.0.0.0/0 dengan 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:

  1. 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.
  2. 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.

🏷️ Tags: #Devops #Kubernetes #Terraform #Cloud Architecture #Aws Eks