Declarative Infrastructure: Manajemen Multi-Cloud Skala Besar Menggunakan Terraform dan Ansible
1. Konteks Industri & Analisis Akar Masalah
Dalam lanskap enterprise modern, manajemen infrastruktur secara manual (manual clickops) melalui konsol cloud vendor (AWS, GCP, Azure) telah menjadi anti-pattern yang berbahaya. Ketika sebuah perusahaan web skala besar mengandalkan sysadmin untuk membuat instance virtual machine secara manual, mengatur konfigurasi Nginx, menanam kunci SSL Let's Encrypt, dan menyiapkan klaster database secara ad-hoc, bencana operasional tinggal menunggu waktu. Masalah utama yang sering muncul meliputi Configuration Drift (ketidaksesuaian antara dokumentasi dan kenyataan di server), Human Error (lupa membuka port firewall, salah mengetik record DNS), serta lambatnya waktu pemulihan (Mean Time to Recovery / MTTR) saat terjadi bencana.
Sebelum adopsi infrastruktur deklaratif berbasis Terraform dan Ansible, sebuah tim infrastruktur menghadapi masalah serius:
- Inkonsistensi Lingkungan: Lingkungan Staging menggunakan versi PHP-FPM dan ekstensi yang berbeda dengan Production, menyebabkan bug yang lolos dari pengujian QA.
- Skalabilitas Terbatas: Menambah 10 node web server baru untuk menghadapi lonjakan traffic Flash Sale membutuhkan waktu berjam-jam karena harus dikonfigurasi satu persatu melalui SSH.
- Auditabilitas Buruk: Sulit melacak siapa yang mengubah rule WAF Fail2ban atau parameter
innodb_buffer_pool_sizedi MySQL pada tengah malam.
Setelah menerapkan pipeline infrastruktur deklaratif dengan Terraform (sebagai Provisioner) dan Ansible (sebagai Configuration Management), seluruh siklus hidup infrastruktur berubah menjadi code. State sistem didefinisikan secara eksplisit, dapat direproduksi (reproducible), dan diuji sebelum diterapkan. Perubahan pada topologi jaringan, DNS (Record A, MX, SPF, DKIM, DMARC), CDN Cloudflare, hingga setup queue Supervisor dan Redis dapat digulirkan secara otomatis, aman, dan zero-downtime.
2. Konsep Inti & Deep Dive Arsitektur
Infrastruktur deklaratif memisahkan apa yang diinginkan (desired state) dari bagaimana cara mencapainya (imperative steps). Dalam ekosistem ini, Terraform bertanggung jawab pada lapisan orkestrasi resource cloud fundamental (VPC, Subnet, EC2, Load Balancer, Security Group, Managed Database), sementara Ansible mengambil alih pada lapisan in-host configuration (install web server Nginx, konfigurasi PHP-FPM, setup Postfix relay, penataan direktori S3/MinIO mount, dan eksekusi skrip migrasi database MySQL).
Berikut adalah ilustrasi aliran data dan eksekusi arsitektur multi-cloud provisioning:
+------------------------------------------------------------------------+
| Developer / Git Repository |
| (Terraform HCL & Ansible Playbooks) |
+------------------------------------------------------------------------+
|
v
+------------------------------------------------------------------------+
| CI/CD Pipeline (GitHub Actions) |
| 1. terraform plan & apply -> Provision Cloud Resources |
| 2. Dynamic Inventory Generation -> Fetch Server IPs |
| 3. ansible-playbook -> Configure Web/DB/Cache Nodes |
+------------------------------------------------------------------------+
|
+----------------------------+----------------------------+
| |
v v
+-------------------------------+ +-------------------------------+
| Cloud Provider A | | Cloud Provider B |
| - VPC / Subnet / IGW | | - Cloudflare DNS (A, MX, TXT)|
| - EC2 / Compute Instances | | - AWS S3 / MinIO Storage |
| - RDS MySQL / MariaDB Cluster| | - Redis Cache Cluster |
+-------------------------------+ +-------------------------------+
| |
+----------------------------+----------------------------+
|
v
+------------------------------------------------------------------------+
| Target Web Infrastructure |
| Nginx -> PHP-FPM -> Go/Node Backend -> MySQL/Redis -> Fail2ban/WAF |
+------------------------------------------------------------------------+
Alur kerja dimulai dari commit kode ke Git. Pipeline CI/CD menjalankan terraform apply untuk membangun infrastruktur dasar. Terraform menghasilkan dynamic inventory yang langsung dikonsumsi oleh Ansible. Ansible kemudian melakukan koneksi SSH ke node-node baru secara paralel, menginstal paket web server, mengonfigurasi sertifikat SSL, memasang skrip Supervisor untuk queue worker, dan memastikan seluruh layanan berjalan dalam keadaan idempotent.
3. Perbandingan Komparatif / Analisis Pendekatan
Untuk memahami mengapa kombinasi Terraform dan Ansible menjadi standar industri, berikut adalah tabel komparasi mendalam dengan pendekatan alternatif:
| Parameter Komparasi | Terraform + Ansible (Direkomendasikan) | Pure Bash/Shell Scripts | AWS CloudFormation + SSM | Kubernetes + Helm Charts |
|---|---|---|---|---|
| Cakupan Multi-Cloud | Sangat Luas (AWS, GCP, Azure, Cloudflare) | Terbatas & Kustom | Terikat kuat pada satu vendor (AWS) | Agnostik Cloud, namun kompleksitas tinggi |
| Idempotensi | Tinggi (Terraform State & Ansible Modules) | Rendah (Sering merusak sistem jika dijalankan ulang) | Sedang (Bergantung pada template CloudFormation) | Tinggi (Declarative K8s Manifests) |
| Kurva Belajar | Moderat (HCL & YAML) | Rendah di awal, tinggi di pemeliharaan | Tinggi (Sintaks JSON/YAML yang masif) | Sangat Tinggi (Kube-apiserver, CNI, CSI) |
| Penggunaan Resource CPU/RAM | Minimal (dijalankan di CI/CD atau local) | Minimal | Dikelola oleh AWS Control Plane | Tinggi (Butuh resource master & worker node besar) |
| Cocok Untuk | Arsitektur Web Tradisional & Hybrid Cloud | Setup skala kecil / lokal | Ekosistem 100% AWS | Arsitektur Microservices berskala masif |
| Manajemen Konfigurasi File (Nginx/PHP) | Sangat Handal (Ansible Templates Jinja2) | Rentan Error | Terbatas (harus pakai cfn-init) | Menggunakan ConfigMap & Secrets |
[!TIP] Gunakan Terraform murni untuk manajemen Infrastructure as a Service (IaaS) dan Ansible untuk Configuration as a Service (CaaS). Jangan pernah menggunakan Terraform untuk memodifikasi file konfigurasi aplikasi di dalam server karena melanggar prinsip pemisahan tanggung jawab.
4. Prasyarat Sistem & Persiapan Lingkungan
Sebelum memulai implementasi, pastikan environment lokal atau runner CI/CD Anda memenuhi spesifikasi teknis berikut:
- OS: Linux Ubuntu 22.04 LTS / Debian 12 / macOS Ventura+
- Terraform: Versi >= 1.5.0
- Ansible: Versi >= 2.15
- Cloud Access: Akun AWS / GCP / Cloudflare dengan hak akses administratif (IAM Policy yang sesuai).
- SSH Key: Kunci RSA/Ed25519 untuk akses komunikasi aman ke instance.
Verifikasi instalasi dengan perintah terminal:
terraform --version
ansible --version
aws --version
Struktur direktori proyek yang akan kita bangun:
infra-enterprise/
├── terraform/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ └── terraform.tfvars
└── ansible/
├── inventory/
│ └── dynamic_aws_ec2.yml
├── playbooks/
│ ├── site.yml
│ └── roles/
│ ├── common/
│ ├── webserver/
│ ├── database/
│ └── security/
└── ansible.cfg
5. Panduan Implementasi Langkah demi Langkah
Langkah 1: Konfigurasi Terraform untuk Provisioning Cloud Infrastructure
Buat file terraform/main.tf untuk mendefinisikan provider AWS, VPC, Subnet, Security Group, dan EC2 Instance untuk web server.
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
}
}
provider "aws" {
region = var.aws_region
}
provider "cloudflare" {
api_token = var.cloudflare_api_token
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "enterprise-vpc"
}
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = true
tags = {
Name = "enterprise-public-subnet"
}
}
resource "aws_security_group" "web_sg" {
name = "enterprise-web-sg"
description = "Allow HTTP, HTTPS, and SSH"
vpc_id = aws_vpc.main.id
ingress {
description = "HTTP from anywhere"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTPS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "SSH from Admin IP"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.admin_ip]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "web_server" {
ami = "ami-0c7217cdde317cfec" # Ubuntu 22.04 LTS
instance_type = "t3.medium"
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web_sg.id]
key_name = var.ssh_key_name
tags = {
Name = "enterprise-web-node"
Environment = "production"
Role = "webserver"
}
}
resource "cloudflare_record" "web" {
zone_id = var.cloudflare_zone_id
name = "app"
value = aws_instance.web_server.public_ip
type = "A"
ttl = 300
proxied = true
}
output "web_public_ip" {
value = aws_instance.web_server.public_ip
}
Langkah 2: Variabel Terraform (terraform/variables.tf)
variable "aws_region" {
type = string
default = "ap-southeast-1"
}
variable "admin_ip" {
type = string
default = "203.0.113.50/32"
}
variable "ssh_key_name" {
type = string
default = "enterprise-deploy-key"
}
variable "cloudflare_api_token" {
type = string
sensitive = true
}
variable "cloudflare_zone_id" {
type = string
}
Langkah 3: Konfigurasi Ansible untuk Zero-Downtime Provisioning
Buat struktur Ansible Playbook untuk menginstal Nginx, PHP-FPM 8.2, Redis, dan Fail2ban.
File ansible/ansible.cfg:
[defaults]
inventory = inventory/dynamic_aws_ec2.yml
remote_user = ubuntu
private_key_file = ~/.ssh/enterprise-deploy-key.pem
host_key_checking = False
retry_files_enabled = False
File ansible/playbooks/site.yml:
---
- name: Provision Enterprise Web Servers
hosts: tag_Role_webserver
become: yes
roles:
- common
- security
- webserver
- database_client
File ansible/playbooks/roles/webserver/tasks/main.yml:
---
- name: Add Ondrej PHP PPA repository
apt_repository:
repo: ppa:ondrej/php
state: present
- name: Install Nginx, PHP-FPM, and Redis extensions
apt:
name:
- nginx
- php8.2-fpm
- php8.2-cli
- php8.2-mysql
- php8.2-redis
- php8.2-mbstring
- php8.2-xml
- redis-server
state: present
update_cache: yes
- name: Configure Nginx virtual host for web application
template:
src: nginx_vhost.j2
dest: /etc/nginx/sites-available/enterprise_app
owner: root
group: root
mode: '0644'
notify: Restart Nginx
- name: Enable Nginx virtual host
file:
src: /etc/nginx/sites-available/enterprise_app
dest: /etc/nginx/sites-enabled/enterprise_app
state: link
notify: Restart Nginx
- name: Remove default Nginx site
file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Restart Nginx
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
File ansible/playbooks/roles/webserver/templates/nginx_vhost.j2:
server {
listen 80;
server_name app.example.com;
root /var/www/enterprise/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php index.html index.htm;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
File ansible/playbooks/roles/security/tasks/main.yml:
---
- name: Install Fail2ban for brute-force protection
apt:
name: fail2ban
state: present
- name: Configure Fail2ban jail for SSH and Nginx
copy:
dest: /etc/fail2ban/jail.local
content: |
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
[sshd]
enabled = true
[nginx-http-auth]
enabled = true
notify: Restart Fail2ban
handlers:
- name: Restart Fail2ban
service:
name: fail2ban
state: restarted
6. Bedah Kode & Penjelasan Detail Baris Kunci
enable_dns_hostnames = true(Terraform VPC): Memastikan instance EC2 menerima DNS hostname internal AWS, krusial untuk komunikasi antar layanan backend berbasis cluster.proxied = true(Cloudflare Record): Mengaktifkan Cloudflare Orange Cloud (CDN & WAF Layer). Traffic web tidak langsung menghantam IP server asli, melindungi server dari serangan DDoS Layer 7.apt_repository: ppa:ondrej/php(Ansible): Memastikan server production menjalankan versi PHP enterprise terbaru yang didukung patch keamanan jangka panjang, terlepas dari versi bawaan repositori Ubuntu.fastcgi_pass unix:/var/run/php/php8.2-fpm.sock(Nginx Vhost): Menggunakan Unix Domain Socket alih-alih TCP port (127.0.0.1:9000) untuk komunikasi antara Nginx dan PHP-FPM. Ini memangkas network overhead dan meningkatkan throughput request web secara signifikan.
7. Skenario Produksi & Studi Kasus Dunia Nyata
[!IMPORTANT] Dalam skenario high-traffic (misalnya 50,000 concurrent requests saat peluncuran produk e-commerce), instance tunggal akan kolaps. Gunakan Terraform untuk membuat Auto Scaling Group (ASG) di belakang Application Load Balancer (ALB), dan arahkan Ansible untuk mengonfigurasi Shared Session Storage menggunakan Redis Cluster.
Studi Kasus: Perusahaan Fintech "PayFast" membutuhkan infrastruktur zero-downtime saat deploy pembaruan kode backend Go dan PHP. Mereka menggunakan pipeline Terraform + Ansible dengan tahapan:
- Terraform menduplikasi EC2 instance di target Availability Zone baru (Blue/Green Deployment).
- Ansible mengeksekusi playbook untuk instalasi dependensi pada node Green.
- Cloudflare DNS dialihkan secara otomatis menggunakan Terraform API dari node Blue ke node Green.
- Node Blue dimusnahkan (
terraform destroy) setelah traffic sepenuhnya beralih.
8. Common Pitfalls, Anti-Patterns & Solusi
- Anti-Pattern 1: Menyimpan Terraform State di Mesin Lokal. Solusi: Selalu gunakan Remote Backend terenkripsi seperti AWS S3 dengan State Locking via DynamoDB untuk mencegah korupsi state saat dikerjakan oleh tim.
- Anti-Pattern Playbook Ansible yang Tidak Idempotent.
Solusi: Hindari penggunaan modul
shellataucommandmentah. Selalu gunakan modul bawaan Ansible sepertitemplate,apt,service, danfileyang secara inheren bersifat idempotent. - Kesalahan Konfigurasi DNS TTL. Solusi: Sebelum melakukan migrasi infrastruktur besar, turunkan TTL DNS record Cloudflare ke 60 detik (Low TTL) minimal 24 jam sebelumnya agar propagasi berjalan instan.
9. Benchmark, Metrik Kinerja & Tuning Performa
Lakukan pengujian beban (load testing) menggunakan tool wrk untuk mengukur performa Nginx dan PHP-FPM setelah dikonfigurasi oleh Ansible:
wrk -t12 -c400 -d30s http://app.example.com/
Tuning parameter tingkat lanjut pada sistem operasi Linux (/etc/sysctl.conf) untuk menangani koneksi TCP masif:
# Tingkatkan batas file descriptor
fs.file-max = 2097152
# Optimasi TCP Socket Buffer
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# Reuse TIME_WAIT sockets untuk koneksi tinggi
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
Terapkan perubahan sysctl dengan perintah: sudo sysctl -p.
10. Checklist Penerapan Produksi & Kesimpulan
Sebelum merilis infrastruktur ke production, pastikan checklist berikut terpenuhi:
- Terraform Remote Backend dengan enkripsi S3 & DynamoDB Lock aktif.
- Seluruh variabel sensitif (API Token, Password DB) dikelola melalui Terraform Vault / Environment Variables.
- Ansible Playbook telah diuji pada Staging Environment menggunakan Dry Run (
--check). - Firewall (AWS SG & Fail2ban) dikonfigurasi ketat; tutup port yang tidak perlu.
- Record DNS (A, MX, SPF, DKIM, DMARC) terverifikasi valid di Cloudflare.
- Monitoring, logging (ELK / Prometheus + Grafana), dan backup otomatis aktif.
Dengan menguasai pendekatan deklaratif menggunakan Terraform dan Ansible ini, tim engineering Anda memiliki kekuatan penuh untuk mengelola ratusan server lintas cloud dengan presisi tinggi, keamanan terjamin, dan efisiensi operasional mutlak.