Automasi Infrastruktur Skala Enterprise Menggunakan Terraform dan Ansible di AWS
1. Konteks Industri & Analisis Akar Masalah
Dalam lanskap enterprise modern, ketersediaan tinggi (high availability), skalabilitas elastis, dan tata kelola infrastruktur yang dapat diaudit (auditable infrastructure) bukanlah sekadar opsi mewah, melainkan syarat mutlak kelangsungan bisnis. Bayangkan sebuah ekosistem web skala enterprise: arsitektur web modern yang melayani jutaan request HTTP, backend multi-bahasa (PHP, Go, Node.js) yang ditenagai web server berkinerja tinggi seperti Nginx dan PHP-FPM, sistem DNS yang kompleks dengan catatan SPF, DKIM, dan DMARC untuk integritas email, edge caching melalui Cloudflare CDN, lapisan WAF (Web Application Firewall) yang ketat, hingga sistem penyimpanan terdistribusi (S3/MinIO), antrean pesan (RabbitMQ/Redis), dan manajemen database relasional (MySQL/MariaDB) berdampingan dengan Redis cache.
Secara historis, mengelola seluruh komponen ini secara manual melalui AWS Management Console atau skrip bash ad-hoc (pendekatan imperatif) menciptakan momok yang dikenal sebagai "Configuration Drift". Kondisi Sebelum penerapan Infrastructure as Code (IaC) ditandai oleh:
- Manajemen State Manual: Tidak ada catatan terpusat tentang siapa yang mengubah apa dan kapan. Server produksi menjadi "pet-like" di mana perbaikan dilakukan langsung di atas instance (SSH dan
apt-get), membuatnya rapuh dan tidak dapat direproduksi. - Waktu Setup Lambat: Pembuatan lingkungan staging atau disaster recovery memakan waktu berhari-hari bahkan berminggu-minggu, rentan terhadap human error.
- Keamanan Inkonsisten: Aturan Security Group atau konfigurasi SSL/TLS Let's Encrypt sering terlewat pada node baru, meninggalkan celah eksploitasi.
Sebaliknya, setelah penerapan otomatisasi penuh menggunakan Terraform untuk provisioning infrastruktur dasar dan Ansible untuk konfigurasi server (pendekatan deklaratif), organisasi mencapai titik "Immutable Infrastructure". Infrastruktur diperlakukan sebagai kode yang dapat versioning (Git), diuji melalui CI/CD pipeline, dan dihancurkan serta dibangun kembali dalam hitungan menit tanpa kehilangan data state berharga yang disimpan secara aman di AWS S3 dengan penguncian DynamoDB.
[!WARNING] Jangan pernah melakukan modifikasi manual (hotfix SSH) pada server produksi yang dikelola oleh Ansible atau Terraform. Setiap perubahan manual akan ditimpa pada eksekusi playbook berikutnya atau menyebabkan state drift yang memicu kegagalan deployment.
2. Konsep Inti & Deep Dive Arsitektur
Untuk memahami cara kerja Terraform dan Ansible secara sinergis, kita harus melihat pembagian tugas yang jelas:
- Terraform (Declarative Provisioning): Berfokus pada "apa" yang ingin dibangun di level cloud provider (AWS). Terraform berkomunikasi dengan AWS API untuk membuat VPC, Subnet, Internet Gateway, Route Table, EC2 Instance, Security Group, dan RDS MySQL.
- Ansible (Imperative/Declarative Configuration Management): Berfokus pada "bagaimana" mengonfigurasi perangkat lunak di dalam instance EC2 yang telah disediakan oleh Terraform. Ansible menggunakan arsitektur agentless berbasis SSH, mengeksekusi playbook YAML untuk menginstal Nginx, PHP-FPM, Redis, mengonfigurasi fail2ban, mengatur Postfix relay, hingga memasang sertifikat SSL.
+-------------------------------------------------------------------------+
| CI/CD Pipeline / Engineer |
+-------------------------------------------------------------------------+
| |
v v
+-------------------+ +-------------------+
| Terraform | | Ansible |
| (Provisioning) | | (Configuration) |
+-------------------+ +-------------------+
| |
| (API Calls) | (SSH / WinRM)
v v
+-------------------------------------------------------------------------+
| AWS Cloud |
| +-------------------------------------------------------------------+ |+
| | VPC (Virtual Private Cloud) | |||
| | +---------------------+ +----------------------------------+ | ||
| | | Public Subnet | | Private Subnet | | ||
| | | - Nginx / Caddy |-->| - Go / Node / PHP-FPM Backend | | ||
| | | - Cloudflare WAF | | - MySQL RDS / Redis Cache | | ||
| | +---------------------+ +----------------------------------+ | ||
| +-------------------------------------------------------------------+ ||
+-------------------------------------------------------------------------+
Alur eksekusi end-to-end:
- Developer menjalankan
terraform apply. Terraform membaca file.tf, membandingkannya dengan state terpusat di S3, lalu memanggil AWS API. - Terraform membuat instance EC2 dan secara otomatis menghasilkan Dynamic Inventory atau menuliskan IP publik instance ke dalam file
hosts.iniAnsible. - Terraform memicu null_resource atau runner eksternal untuk menjalankan
ansible-playbookterhadap IP instance baru. - Ansible masuk via SSH, memperbarui sistem operasi, menginstal paket web server, mengonfigurasi Supervisor untuk background worker, menyetel Redis, dan memastikan seluruh keamanan dasar (UFW/Fail2ban) aktif.
3. Perbandingan Komparatif / Analisis Pendekatan
Berikut adalah analisis mendalam perbandingan pendekatan manajemen infrastruktur untuk membantu arsitek menentukan strategi optimal.
| Parameter | Manual Console / Skrip Bash | Terraform Saja (Cloud-Init) | Terraform + Ansible (Hybrid Enterprise) |
|---|---|---|---|
| Pendekatan | Imperative (Langkah demi langkah) | Declarative (Keadaan akhir) | Declarative (Cloud) + Imperative/Declarative (OS) |
| Reproduksibilitas | Rendah (Sangat bergantung pada memori admin) | Sedang (Terbatas pada parameter cloud-init) | Tinggi (Infrastruktur dan software OS identik) |
| Kompleksitas Skala Besar | Sangat Tinggi (Rentan kekeliruan) | Sedang (Sulit untuk manajemen software di dalam OS) | Optimal (Pembagian tugas yang bersih) |
| State Management | Tidak ada | S3 + DynamoDB Locking | S3 + DynamoDB (Terraform) / Stateless (Ansible) |
| Keamanan & Audit | Hampir tidak ada | Sangat Baik (Terraform Plan & State) | Sangat Baik (Version Control pada Playbook) |
| Latensi Deployment | Cepat di awal, lambat dalam jangka panjang | Cepat | Sedang (Membutuhkan waktu provisioning + provisioning OS) |
[!TIP] Menggunakan Terraform murni untuk manajemen konfigurasi internal OS (seperti menginstal modul Nginx atau menulis konfigurasi PHP-FPM via
user_data) sering kali berujung pada kerumitan debugging. Kombinasi Terraform untuk infrastruktur dasar dan Ansible untuk konfigurasi OS adalah industry gold standard untuk enterprise.
4. Prasyarat Sistem & Persiapan Lingkungan
Sebelum menyelam ke dalam kode implementasi, pastikan lingkungan kerja lokal atau server CI/CD Anda memenuhi spesifikasi berikut:
- Terraform CLI: Versi >= 1.5.0
- Ansible Core: Versi >= 2.15.0
- AWS CLI v2: Terkonfigurasi dengan profil IAM yang memiliki hak akses administrator penuh (atau minimal izin IAM untuk VPC, EC2, RDS, S3, dan DynamoDB).
- Kunci SSH: Telah dibuat pasangan kunci SSH di AWS (
aws_key_pair) dengan namaenterprise-prod-key.
Struktur direktori proyek enterprise yang direkomendasikan:
infra-root/
├── terraform/
│ ├── backend.tf
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ └── terraform.tfvars
└── ansible/
├── ansible.cfg
├── inventory/
│ └── aws_ec2.yml
├── playbooks/
│ └── site.yml
└── roles/
├── common/
├── nginx/
├── php-fpm/
└── redis/
5. Panduan Implementasi Langkah demi Langkah
Langkah 1: Konfigurasi Terraform Backend & Provider (terraform/backend.tf)
Kita mulai dengan mendefinisikan state backend yang aman menggunakan AWS S3 dan DynamoDB untuk state locking agar tidak terjadi konflik saat beberapa engineer atau pipeline berjalan bersamaan.
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "enterprise-terraform-state-bucket-prod"
key = "core-infra/terraform.tfstate"
region = "ap-southeast-1"
dynamodb_table = "enterprise-terraform-locks"
encrypt = true
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = "Production"
ManagedBy = "Terraform"
Project = "EnterpriseWebPlatform"
}
}
}
Langkah 2: Definisi Infrastruktur Utama (terraform/main.tf)
File ini mengatur VPC, Subnet publik dan privat, Internet Gateway, serta instance EC2 dan RDS MySQL.
variable "aws_region" {
type = string
default = "ap-southeast-1"
}
resource "aws_vpc" "main" {
cidr_block = "10.100.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "enterprise-vpc"
}
}
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "enterprise-igw"
}
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.100.1.0/24"
map_public_ip_on_launch = true
availability_zone = "ap-southeast-1a"
tags = {
Name = "enterprise-public-subnet"
}
}
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 = "enterprise-public-rt"
}
}
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
resource "aws_security_group" "web" {
name = "enterprise-web-sg"
description = "Security group for web servers"
vpc_id = aws_vpc.main.id
ingress {
description = "Allow HTTP from anywhere"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "Allow HTTPS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "Allow SSH from corporate VPN / Admin IP"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["203.0.113.50/32"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "enterprise-web-sg"
}
}
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_instance" "web_server" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.medium"
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web.id]
key_name = "enterprise-prod-key"
root_block_device {
volume_size = 50
volume_type = "gp3"
encrypted = true
delete_on_termination = false
}
tags = {
Name = "enterprise-web-node-01"
Environment = "Production"
}
}
output "web_instance_ip" {
value = aws_instance.web_server.public_ip
description = "Public IP of the web server for Ansible configuration"
}
Langkah 3: Eksekusi Provisioning Terraform
Jalankan perintah berikut di terminal:
cd terraform
terraform init
terraform plan -out=tfplan
terraform apply tfplan
Langkah 4: Konfigurasi Dinamis Ansible Inventory (ansible/inventory/aws_ec2.yml)
Alih-alih menulis IP secara manual, gunakan plugin dinamis AWS EC2 Ansible agar secara otomatis mendeteksi instance yang baru dibuat berdasarkan tag.
plugin: amazon.aws.aws_ec2
regions:
- ap-southeast-1
filters:
tag:Environment: Production
instance-state-name: running
hostnames:
- public-ip-address
keyed_groups:
- key: tags.Name
prefix: web
Langkah 5: Ansible Playbook Utama (ansible/playbooks/site.yml)
Playbook ini akan mengeksekusi peran (roles) untuk memperbarui sistem, menginstal Nginx, PHP-FPM 8.2, dan Redis.
---
- hosts: all
become: yes
gather_facts: yes
roles:
- common
- nginx
- php-fpm
- redis
Langkah 6: Ansible Role Nginx (ansible/roles/nginx/tasks/main.yml)
---
- name: Install Nginx web server
apt:
name: nginx
state: present
update_cache: yes
- name: Ensure Nginx is started and enabled
service:
name: nginx
state: started
enabled: yes
- name: Deploy custom enterprise nginx configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: restart nginx
Definisikan handler restart Nginx di ansible/roles/nginx/handlers/main.yml:
---
- name: restart nginx
service:
name: nginx
state: restarted
Langkah 7: Menjalankan Ansible Playbook
Eksekusi Ansible menggunakan inventory dinamis AWS:
cd ansible
ansible-playbook -i inventory/aws_ec2.yml playbooks/site.yml --private-key=~/.ssh/enterprise-prod-key.pem -u ubuntu
6. Bedah Kode & Penjelasan Detail Baris Kunci
encrypt = truepada Terraform S3 Backend: Sangat krusial untuk mencegah kebocoran informasi sensitif (seperti password RDS yang tidak sengaja tercetak dalam bentuk plain text di dalam state file).root_block_devicedenganvolume_type = "gp3"danencrypted = true: Menggunakan SSD General Purpose generasi ketiga di AWS memberikan performa IOPS yang konsisten tanpa biaya tambahan, serta enkripsi disk tingkat hardware sesuai dengan standar kepatuhan PCI-DSS dan ISO 27001.become: yespada Ansible: Memungkinkan eksekusi perintah sebagairootmelaluisudo, memastikan hak akses penuh untuk menginstal paket sistem dan mengubah konfigurasi daemon web server.
7. Skenario Produksi & Studi Kasus Dunia Nyata
Dalam skenario high-concurrency (misalnya platform e-commerce saat flash sale), arsitektur di atas dikembangkan lebih lanjut dengan menambahkan AWS Auto Scaling Group (ASG) dan Application Load Balancer (ALB) di depan instance web.
Ketika Terraform mendefinisikan ASG, Ansible tidak lagi menargetkan IP statis, melainkan diintegrasikan melalui Lifecycle Hooks atau di-bake langsung ke dalam bentuk Golden AMI menggunakan Packer. Dengan pendekatan Golden AMI, setiap instance yang diciptakan oleh ASG otomatis sudah terkonfigurasi Nginx, PHP, dan Redis tanpa perlu menunggu Ansible berjalan saat booting, memangkas waktu cold start dari 5 menit menjadi kurang dari 30 detik.
8. Common Pitfalls, Anti-Patterns & Solusi
- Anti-Pattern: Menyimpan Secrets di dalam Kode Terraform/Ansible
- Solusi: Selalu gunakan AWS Secrets Manager atau Parameter Store, lalu ambil nilainya secara dinamis menggunakan data sources Terraform (
data.aws_secretsmanager_secret_version) atau Ansible lookup plugins (lookup('amazon.aws.aws_secret', ...)).
- Solusi: Selalu gunakan AWS Secrets Manager atau Parameter Store, lalu ambil nilainya secara dinamis menggunakan data sources Terraform (
- Pitfalls: State Lock Terkunci Permanen (Stuck Lock)
- Solusi: Jika proses
terraform applyterputus mendadak, DynamoDB akan mengunci state. Gunakan perintahterraform force-unlock <LOCK_ID>dengan hati-hati setelah memastikan tidak ada proses lain yang sedang berjalan.
- Solusi: Jika proses
- Anti-Pattern: Hardcode IP Address di Ansible Inventory
- Solusi: Menggunakan Inventory Plugins dinamis (
aws_ec2) memastikan perubahan infrastruktur otomatis tercermin tanpa intervensi manual.
- Solusi: Menggunakan Inventory Plugins dinamis (
9. Benchmark, Metrik Kinerja & Tuning Performa
Untuk memastikan server Nginx + PHP-FPM siap menghadapi beban tinggi, lakukan pengujian beban menggunakan k6 atau wrk.
Contoh skrip uji beban sederhana menggunakan wrk:
wrk -t12 -c400 -d30s http://<WEB_INSTANCE_IP>/
Tuning parameter sistem Linux (/etc/sysctl.conf) yang wajib diterapkan melalui Ansible role common untuk performa jaringan berkecepatan tinggi:
# Meningkatkan batas maksimal file descriptor
fs.file-max = 2097152
# Optimasi TCP backlog dan socket buffers
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.ip_local_port_range = 1024 65535
# Mengaktifkan TCP Reuse & Recycling
net.ipv4.tcp_tw_reuse = 1
10. Checklist Penerapan Produksi & Kesimpulan
Sebelum meluncurkan infrastruktur ini ke lingkungan produksi live, pastikan Anda telah melewati checklist berikut:
- State Terraform di-enkripsi dan dilindungi oleh DynamoDB Locking.
- Semua Security Group mengikuti prinsip Least Privilege (port 22 hanya dibuka dari IP bastion host/VPN internal).
- Sertifikat SSL/TLS otomatis terkonfigurasi melalui Certbot/Let's Encrypt.
- Backup otomatis RDS MySQL diaktifkan dengan retensi minimal 7 hari.
- Monitoring dan Alerting (CloudWatch / Prometheus / Grafana) terpasang untuk memantau penggunaan CPU, RAM, Disk I/O, dan HTTP 5xx Error Rate.
Dengan menggabungkan kekuatan deklaratif Terraform dan fleksibilitas konfigurasi Ansible, organisasi Anda memiliki fondasi infrastruktur cloud yang tangguh, mudah diaudit, dan siap diskalakan secara masif tanpa rasa cemas.