Implementasi Infrastructure as Code Menggunakan Terraform dan Ansible untuk Multi-Cloud Enterprise
1. Konteks Industri & Analisis Akar Masalah
Dalam lanskap enterprise modern, kebutuhan untuk mendistribusikan beban kerja secara lintas penyedia layanan cloud (multi-cloud strategy) bukan lagi sekadar opsi pencegahan vendor lock-in, melainkan keharusan arsitektural demi mencapai ketersediaan tinggi (High Availability), pemulihan bencana (Disaster Recovery), dan kepatuhan regulasi data (data residency compliance). Namun, kompleksitas operasional melonjak drastis ketika arsitek infrastruktur harus mengelola server web Nginx/Apache, runtime Go/Node.js/PHP, database MySQL/MariaDB berkinerja tinggi, sistem caching Redis, edge caching Cloudflare, DNS enterprise, hingga konfigurasi keamanan SSL/TLS dan WAF secara manual di berbagai lingkungan cloud seperti AWS, Google Cloud Platform (GCP), dan Azure.
Secara historis, pendekatan manajemen infrastruktur yang mengandalkan skrip shell manual atau klik pada konsol web cloud (ClickOps) mengakibatkan apa yang disebut sebagai Infrastructure Driftβperbedaan kondisi sistem yang tidak terdokumentasi antara server staging dan produksi. Bottleneck performa dan celah keamanan sering kali muncul akibat inkonsistensi pengaturan firewall (Security Groups), manajemen akses SSH yang buruk, konfigurasi direktori storage S3/MinIO yang terbuka, serta lambatnya respons terhadap lonjakan traffic tinggi.
Perbandingan kondisi Sebelum vs Sesudah penerapan Infrastructure as Code (IaC) terintegrasi (Terraform + Ansible):
| Metrik / Aspek | Sebelum (Manual / ClickOps / Skrip Ad-hoc) | Sesudah (Terraform + Ansible Terintegrasi) |
|---|---|---|
| Waktu Provisioning | Hitungan hari hingga minggu; rentan kesalahan manusia. | Hitungan menit; otomatis, repetitif, dan konsisten. |
| Infrastruktur Drift | Tinggi; perubahan manual tidak terlacak di version control. | Nol; seluruh status infrastruktur dideklarasikan dalam file kode (Git). |
| Keamanan & Kepatuhan | Audit lambat, port terbuka tidak sengaja, konfigurasi SSL manual. | Kebijakan keamanan ditegakkan di level kode (Policy as Code). |
| Manajemen Secret | Berisiko tinggi (plaintext di file konfigurasi atau environment variable). | Aman melaluiintegrasi HashiCorp Vault, AWS Secrets Manager, atau Ansible Vault. |
| Multi-Cloud Portability | Sangat sulit; setiap cloud memiliki konsol dan API yang berbeda. | Abstraksi melalui Terraform Providers dan Ansible Collections yang seragam. |
[!WARNING] Mengandalkan variabel lokal atau file
.envplaintext untuk menyimpan kredensial database MySQL atau API key Cloudflare pada skrip deployment manual adalah pelanggaran fatal standar keamanan enterprise (ISO 27001 / SOC 2). Gunakan manajemen secret terpusat.
2. Konsep Inti & Deep Dive Arsitektur
Arsitektur otomasi infrastruktur enterprise yang solid memisahkan tanggung jawab secara tegas antara Provisioning dan Configuration Management:
- Terraform: Bertindak sebagai engine deklaratif untuk membangun fondasi infrastruktur (Compute Instances, VPC, Subnets, DNS Records, Load Balancers, S3 Buckets, Managed Database). Terraform bekerja berdasarkan State File yang mencatat peta kondisi nyata infrastruktur saat ini terhadap kode deklaratif.
- Ansible: Bertindak sebagai engine imperatif/konvergen untuk mengkonfigurasi sistem operasi di dalam instance yang telah di-provision oleh Terraform (Instalasi Nginx/Caddy, konfigurasi PHP-FPM, tuning sysctl untuk performa jaringan berkecepatan tinggi, setup Postfix relay, penataan direktori web HTML/CSS/JS, serta deployment backend Go/Node.js).
Alur eksekusi end-to-end dapat divisualisasikan melalui diagram ASCII berikut:
+-----------------------+ Terraform Apply +-------------------------+
| Git Repository | --------------------------> | AWS / GCP / Azure |
| (HCL Code & Modules) | | (VPC, VMs, S3, DNS) |
+-----------------------+ +-------------------------+
| |
| (Dynamic Inventory Generation) | IP Outputs
v v
+-----------------------+ Ansible Playbook +-------------------------+
| Ansible Control Node | --------------------------> | Target Enterprise VMs |
| (Roles, Vault, Tasks)| (SSH / WinRM) | (Nginx, Go, Node, MySQL) |
+-----------------------+ +-------------------------+
Alur Kerja Data di Balik Layar:
- Inisialisasi State: Terraform melakukan remote locking pada backend (misalnya AWS S3 + DynamoDB) untuk mencegah race condition antar engineer.
- Dynamic Inventory: Setelah Terraform berhasil mem-provision VM, output IP address dialirkan secara otomatis ke Ansible melalui file inventory dinamis atau plugin terraform-inventory.
- Konvergensi Playbook: Ansible mengeksekusi task secara idempotentβartinya playbook dapat dijalankan berkali-kali tanpa merusak atau mengubah sistem jika kondisi server sudah sesuai dengan state yang diinginkan.
3. Perbandingan Komparatif / Analisis Pendekatan
Untuk arsitek infrastruktur, pemilihan tool tidak boleh didasarkan pada tren semata, melainkan analisis mendalam terhadap konsumsi sumber daya dan karakteristik eksekusi.
| Fitur / Parameter | Terraform (HashiCorp) | Ansible (Red Hat) | Pulumi | Chef / Puppet |
|---|---|---|---|---|
| Paradigma | Deklaratif (HCL) | Imperatif/Konvergen (YAML) | Imperatif (TypeScript/Python) | Deklaratif / Domain DSL |
| Fokus Utama | Infrastructure Provisioning | Configuration Management | Infrastructure & App Code | Configuration Management |
| State Management | Wajib (Remote State File) | Stateless (In-memory / fakta dinamis) | Wajib (Managed Service/Storage) | Agent-based (Central Server) |
| Footprint di Target | Agentless (Cloud API) | Agentless (SSH/Python di target) | Agentless (Cloud API) | Membutuhkan Agent terinstal |
| Kurva Pembelajaran | Menengah (HCL mudah dipahami) | Rendah-Menengah (YAML) | Tinggi (Butuh mahir bahasa pemrograman) | Tinggi (DSL khusus) |
[!TIP] Kombinasi terbaik di dunia enterprise adalah menggunakan Terraform untuk memanajemen aset cloud layer bawah (IaaS) dan Ansible untuk manajemen sistem operasi dan aplikasi layer atas (PaaS/SaaS internal). Hindari menggunakan Terraform untuk menginstal paket aplikasi rumit di dalam OS, karena hal tersebut memperlambat siklus plan & apply.
4. Prasyarat Sistem & Persiapan Lingkungan
Sebelum mulai menulis kode, pastikan workstation atau CI/CD runner memiliki dependensi dengan versi minimum berikut:
- Terraform: Versi
>= 1.6.0 - Ansible: Versi
>= 2.15.0 - Python: Versi
>= 3.10(pada control node dan target node untuk modul Ansible) - Git: Versi
>= 2.40 - Cloud CLI: AWS CLI v2 / Google Cloud SDK / Azure CLI terautentikasi.
Struktur direktori repository proyek enterprise harus diorganisasikan dengan rapi:
enterprise-infra/
βββ .gitignore
βββ terraform/
β βββ main.tf
β βββ variables.tf
β βββ outputs.tf
β βββ backend.tf
β βββ modules/
β βββ vpc/
β βββ compute/
βββ ansible/
βββ ansible.cfg
βββ inventory/
β βββ dynamic_aws_ec2.yml
βββ group_vars/
β βββ all.yml
βββ host_vars/
βββ playbooks/
βββ site.yml
βββ roles/
βββ common/
βββ webserver/
βββ database/
5. Panduan Implementasi Langkah demi Langkah
Langkah 1: Konfigurasi Terraform Backend & Provider (AWS & GCP Multi-Cloud)
Buat file terraform/backend.tf untuk menyimpan state secara aman dan terdistribusi.
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "enterprise-terraform-state-prod-xyz"
key = "multi-cloud/production/terraform.tfstate"
region = "ap-southeast-1"
dynamodb_table = "terraform-lock-table"
encrypt = true
}
}
provider "aws" {
region = "ap-southeast-1"
default_tags {
tags {
Environment = "Production"
ManagedBy = "Terraform"
Project = "EnterpriseWeb"
}
}
}
provider "google" {
project = "enterprise-prod-gcp-9921"
region = "asia-southeast2"
zone = "asia-southeast2-a"
}
Buat file terraform/main.tf untuk mem-provision instance web server di AWS dan database di GCP secara simultan.
resource "aws_vpc" "main" {
cidr_block = "10.100.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "enterprise-aws-vpc"
}
}
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-aws-subnet-public"
}
}
resource "aws_security_group" "web_sg" {
name = "enterprise-web-sg"
description = "Allow HTTP, HTTPS, and SSH"
vpc_id = aws_vpc.main.id
ingress {
description = "TLS from Internet"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTP from Internet"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "SSH from Corporate VPN"
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"]
}
}
resource "aws_instance" "web_server" {
ami = "ami-0551577439003c40f" # 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 = "enterprise-deploy-key"
root_block_device {
volume_size = 50
volume_type = "gp3"
encrypted = true
delete_on_termination = false
}
tags = {
Name = "enterprise-web-node-01"
}
}
resource "google_compute_network" "vpc_gcp" {
name = "enterprise-gcp-vpc"
auto_create_subnetworks = true
}
resource "google_compute_firewall" "db_firewall" {
name = "allow-mysql-internal"
network = google_compute_network.vpc_gcp.name
allow {
protocol = "tcp"
ports = ["3306"]
}
source_ranges = ["10.100.0.0/16"]
}
resource "google_compute_instance" "db_server" {
name = "enterprise-db-node-01"
machine_type = "e2-standard-4"
zone = "asia-southeast2-a"
boot_disk {
initialize_params {
image = "ubuntu-os-cloud/ubuntu-2204-lts"
size = 100
}
}
network_interface {
network = google_compute_network.vpc_gcp.name
access_config {
// Ephemeral public IP
}
}
tags = ["database", "production"]
}
output "aws_web_public_ip" {
value = aws_instance.web_server.public_ip
description = "Public IP address of the AWS Web Server"
}
output "gcp_db_public_ip" {
value = google_compute_instance.db_server.network_interface[0].access_config[0].nat_ip
description = "Public IP address of the GCP Database Server"
}
Langkah 2: Konfigurasi Ansible Playbook untuk Konvergensi Sistem Web & Database
Buat file konfigurasi ansible/ansible.cfg:
[defaults]
inventory = ./inventory/hosts.ini
remote_user = ubuntu
private_key_file = ~/.ssh/enterprise-deploy-key.pem
host_key_checking = False
retry_files_enabled = False
roles_path = ./playbooks/roles
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False
Buat file inventory statis/dinamis ansible/inventory/hosts.ini (pada praktiknya dapat di-generate otomatis oleh Terraform):
[webservers]
54.254.120.15 ansible_host=54.254.120.15
[databases]
34.101.55.20 ansible_host=34.101.55.20
Buat playbook utama ansible/playbooks/site.yml:
---
- name: Konvergensi Menyeluruh Infrastruktur Enterprise
hosts: all
gather_facts: yes
roles:
- common
- name: Konfigurasi High-Performance Web Server (Nginx + PHP-FPM + Node.js)
hosts: webservers
gather_facts: yes
roles:
- webserver
- name: Konfigurasi Enterprise Database (MariaDB + Redis Caching)
hosts: databases
gather_facts: yes
roles:
- database
Buat Ansible Role untuk Web Server: ansible/playbooks/roles/webserver/tasks/main.yml
---
- name: Update apt cache dan install dependensi dasar web
apt:
update_cache: yes
cache_valid_time: 3600
state: present
name:
- curl
- git
- ufw
- fail2ban
- nginx
- certbot
- python3-certbot-nginx
- name: Tuning parameter kernel Linux sysctl untuk high concurrency network
sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
sysctl_set: yes
state: present
reload: yes
loop:
- { key: 'fs.file-max', value: '2097152' }
- { key: 'net.core.somaxconn', value: '65535' }
- { key: 'net.ipv4.tcp_max_syn_backlog', value: '8192' }
- { key: 'net.ipv4.ip_local_port_range', value: '10240 65535' }
- name: Deploy file konfigurasi virtual host Nginx enterprise
template:
src: enterprise_nginx.conf.j2
dest: /etc/nginx/sites-available/enterprise.conf
owner: root
group: root
mode: '0644'
notify: Restart Nginx
- name: Aktifkan virtual host Nginx dan hapus default
file:
src: /etc/nginx/sites-available/enterprise.conf
dest: /etc/nginx/sites-enabled/enterprise.conf
state: link
notify: Restart Nginx
- name: Hapus konfigurasi default Nginx
file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Restart Nginx
- name: Pastikan service Nginx aktif dan berjalan saat booting
systemd:
name: nginx
state: started
enabled: yes
handlers:
- name: Restart Nginx
systemd:
name: nginx
state: restarted
Buat template file Nginx ansible/playbooks/roles/webserver/templates/enterprise_nginx.conf.j2:
# Konfigurasi Nginx Enterprise Teroptimasi
user www-data;
worker_processes auto;
worker_rlimit_nofile 65535;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 10240;
use epoll;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging Format Terstruktur
log_format enterprise_json escape=json
'{"time_local":"$time_local",'"
'"remote_addr":"$remote_addr","request":"$request",'
'"status":"$status","body_bytes_sent":"$body_bytes_sent",'
'"request_time":$request_time,"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent\