L
Infrastructure as Code (IaC) • Literally Web ID

Automasi Infrastruktur Multi-Cloud Immutable Menggunakan Terraform dan Ansible di AWS

⏱️ 22 menit baca • 📅 14 Oct 2026 • 👁️ 1 views
Automasi Infrastruktur Multi-Cloud Immutable Menggunakan Terraform dan Ansible di AWS

1. Konteks Industri & Analisis Akar Masalah

Di era komputasi modern, pengelolaan infrastruktur web yang bergantung pada Configuration Drift (penyimpangan konfigurasi) secara manual adalah bom waktu. Pendekatan tradisional di mana administrator sistem melakukan SSH langsung ke instans AWS EC2 untuk memperbarui paket, memodifikasi direktori /etc/nginx/nginx.conf, atau menambal modul PHP-FPM menciptakan lingkungan yang rapuh, tidak dapat direproduksi, dan rentan terhadap kegagalan senyap (silent failure).

Masalah mendasar ini memicu munculnya arsitektur infrastruktur immutable (tidak dapat diubah). Dalam paradigma immutable, instans server tidak pernah diperbarui secara in-place. Jika ada perubahan pada sistem operasi, dependensi runtime Go/Node.js, atau konfigurasi web server Nginx, instans lama dihancurkan dan diganti dengan instans baru yang dibangun dari golden image atau dipProvisioning ulang secara otomatis.

Sebelum penerapan automasi penuh menggunakan Terraform dan Ansible:

  • Waktu Pemulihan (MTTR): Membutuhkan waktu berjam-jam untuk men-debug server yang rusak akibat pembaruan dependensi yang gagal di tengah malam.
  • Konsistensi Lingkungan: Lingkungan staging sering kali berbeda dengan production, menyebabkan bug yang lolos ke produksi (works on my machine).
  • Keamanan: Kunci SSH tersebar di antara banyak insinyur, meningkatkan permukaan serangan (attack surface) terhadap infrastruktur kritis.

Setelah penerapan automasi infrastruktur berbasis Terraform dan Ansible:

  • Reproduksibilitas 100%: Seluruh topografi jaringan VPC, subnet, route table, hingga keamanan WAF dan SSL didefinisikan sebagai kode (Infrastructure as Code).
  • Zero-Downtime Deployment: Pembaruan instans backend (PHP-FPM, Node.js, Go) dilakukan melalui mekanisme Blue-Green atau Rolling Update yang dikoordinasikan secara presisi.
  • Auditabilitas Tinggi: Setiap perubahan infrastruktur tercatat dalam riwayat Git, memungkinkan rollback instan dalam hitungan detik jika terjadi anomali performa.

2. Konsep Inti & Deep Dive Arsitektur

Arsitektur yang kita bangun memadukan orkestrasi infrastruktur tingkat rendah (AWS VPC, Subnet, EC2, S3 Remote State) dengan manajemen konfigurasi tingkat tinggi (Ansible Playbook untuk instalasi Nginx, PHP-FPM, MySQL client, Redis, Supervisor, dan Fail2ban).

+-----------------------------------------------------------------------------------+
|                                   AWS Cloud                                       |
|                                                                                   |
|  +-----------------------------------------------------------------------------+  |
|  |                                  VPC (10.0.0.0/16)                          |  |
|  |                                                                             |  |
|  |  +-----------------------+                         +---------------------+  |  |
|  |  | Public Subnet (AZ-a)  |                         | Public Subnet (AZ-b)|  |  |
|  |  |                       |                         |                     |  |  |
|  |  |  +-----------------+  |                         |  +---------------+  |  |  |
|  |  |  | Application     |  | <--- Dynamic Inventory  |  | Application   |  |  |  |
|  |  |  | EC2 Instance    |  | <--- Ansible Provision  |  | EC2 Instance  |  |  |  |
|  |  |  +-----------------+  |                         |  +---------------+  |  |  |
|  |  +-----------------------+                         +---------------------+  |  |
|  |              ^                                                ^             |  |
|  |              |--------------------+---------------------------|             |  |
|  |                                   |                                         |  |
|  |                                   v                                         |  |
|  |                      +--------------------------+                           |  |
|  |                      | Internet Gateway (IGW)   |                           |  |
|  |                      +--------------------------+                           |  |
|  |                                                                             |  |
|  +-----------------------------------------------------------------------------+  |
+-----------------------------------------------------------------------------------+

Alur kerja eksekusi (Workflow Execution) sistem ini berjalan secara sekuensial namun terintegrasi:

  1. Inisialisasi Terraform: Terraform mengunduh provider AWS, membaca konfigurasi remote state dari Amazon S3, dan mengunci state menggunakan DynamoDB.
  2. Provisioning Infrastruktur: Terraform membuat VPC, Internet Gateway, Route Tables, Security Groups, dan meluncurkan instans EC2 menggunakan Cloud-Init dasar.
  3. Dynamic Inventory Discovery: Ansible memanfaatkan plugin AWS EC2 (aws_ec2) untuk mendeteksi IP publik dan privat dari instans yang baru saja dibuat secara dinamis tanpa hardcode.
  4. Konfigurasi Server: Ansible mengeksekusi playbooks untuk memasang Nginx, mengonfigurasi PHP-FPM / Go binary, menyetel izin direktori web, memasang Fail2ban, dan memastikan layanan sistem berjalan stabil.

3. Perbandingan Komparatif / Analisis Pendekatan

Parameter Komparasi Pendekatan Tradisional (Manual SSH + Bash Script) Pendekatan Modern (Terraform + Ansible Immutable) Dampak pada Sumber Daya
Waktu Provisioning 45 - 90 menit per server 3 - 5 menit otomatis penuh Efisiensi CPU/RAM saat setup meningkat drastis.
Manajemen State Tidak ada (manual tracking di spreadsheet) Terpusat di AWS S3 dengan State Locking DynamoDB Mencegah konflik race condition saat tim bekerja bersama.
Keamanan Akses Sering menggunakan SSH Password & Shared Keys Kunci SSH sementara (Ephemeral keys) / AWS SSM Session Manager Mengurangi risiko kebocoran kredensial root.
Skalabilitas Sulit dan rawan error saat skala > 10 server Skalabilitas linear tanpa batas (Horizontal Scaling) Beban latensi jaringan terdistribusi secara optimal.

[!IMPORTANT] Jangan pernah menyimpan file terraform.tfstate di penyimpanan lokal komputer pengembang saat bekerja dalam tim. Gunakan Remote Backend S3 + DynamoDB untuk mencegah korupsi state dan memastikan konsistensi locking.

4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum menjalankan kode di bawah ini, pastikan mesin lokal atau lingkungan CI/CD Anda memiliki dependensi berikut:

  • Terraform CLI: Versi >= 1.5.0
  • Ansible: Versi >= 2.15 dengan koleksi amazon.aws terpasang.
  • AWS CLI v2: Terkonfigurasi dengan kredensial yang memiliki hak akses penuh ke layanan VPC, EC2, S3, dan IAM.
  • Kunci SSH lokal: Berada di ~/.ssh/id_rsa.pub untuk akses bootstrap awal.

Verifikasi instalasi dengan perintah berikut di terminal:

terraform version
ansible --version
aws sts get-caller-identity

5. Panduan Implementasi Langkah demi Langkah

Langkah 1: Konfigurasi Remote Backend & Provider Terraform

Buat struktur direktori proyek:

mkdir -p terraform-ansible-aws/{terraform/modules/vpc,terraform/modules/ec2,ansible/playbooks,ansible/inventory}
cd terraform-ansible-aws

Buat file terraform/backend.tf:

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
  backend "s3" {
    bucket         = "prod-infrastructure-state-bucket-unique-xyz"
    key            = "web-cluster/terraform.tfstate"
    region         = "ap-southeast-1"
    dynamodb_table = "terraform-lock-table"
    encrypt        = true
  }
}

provider "aws" {
  region = var.aws_region
}

Langkah 2: Implementasi Modul VPC

Buat file terraform/modules/vpc/variables.tf:

variable "vpc_cidr" {
  type    = string
  default = "10.0.0.0/16"
}

variable "public_subnet_cidrs" {
  type    = list(string)
  default = ["10.0.1.0/24", "10.0.2.0/24"]
}

variable "availability_zones" {
  type    = list(string)
  default = ["ap-southeast-1a", "ap-southeast-1b"]
}

Buat file terraform/modules/vpc/main.tf:

resource "aws_vpc" "main" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "production-vpc"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "production-igw"
  }
}

resource "aws_subnet" "public" {
  count                   = length(var.public_subnet_cidrs)
  vpc_id                  = aws_vpc.main.id
  cidr_block              = var.public_subnet_cidrs[count.index]
  availability_zone       = var.availability_zones[count.index]
  map_public_ip_on_launch = true

  tags = {
    Name = "production-public-subnet-${count.index + 1}"
  }
}

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 = "production-public-rt"
  }
}

resource "aws_route_table_association" "public" {
  count          = length(var.public_subnet_cidrs)
  subnet_id      = aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}

Buat file terraform/modules/vpc/outputs.tf:

output "vpc_id" {
  value = aws_vpc.main.id
}

output "public_subnet_ids" {
  value = aws_subnet.public[*].id
}

Langkah 3: Implementasi Modul EC2 & Security Groups

Buat file terraform/modules/ec2/variables.tf:

variable "vpc_id" {
  type = string
}

variable "public_subnet_ids" {
  type = list(string)
}

variable "instance_type" {
  type    = string
  default = "t3.medium"
}

variable "ssh_public_key" {
  type = string
}

Buat file terraform/modules/ec2/main.tf:

resource "aws_security_group" "web_sg" {
  name        = "production-web-sg"
  description = "Allow HTTP, HTTPS, and SSH"
  vpc_id      = var.vpc_id

  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "HTTPS"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "production-web-sg"
  }
}

resource "aws_key_pair" "deployer" {
  key_name   = "production-deployer-key"
  public_key = var.ssh_public_key
}

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" {
  count                  = 2
  ami                    = data.aws_ami.ubuntu.id
  instance_type          = var.instance_type
  subnet_id              = var.public_subnet_ids[count.index % length(var.public_subnet_ids)]
  vpc_security_group_ids = [aws_security_group.web_sg.id]
  key_name               = aws_key_pair.deployer.key_name

  tags = {
    Name = "production-web-node-${count.index + 1}"
    Role = "webserver"
  }
}

Buat file terraform/modules/ec2/outputs.tf:

output "web_instance_public_ips" {
  value = aws_instance.web[*].public_ip
}

Langkah 4: Root Terraform Configuration

Buat file terraform/main.tf:

variable "aws_region" {
  type    = string
  default = "ap-southeast-1"
}

variable "ssh_public_key" {
  type    = string
  default = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQD..." # Ganti dengan public key Anda
}

module "vpc" {
  source             = "./modules/vpc"
  vpc_cidr           = "10.100.0.0/16"
  public_subnet_cidrs = ["10.100.1.0/24", "10.100.2.0/24"]
  availability_zones = ["ap-southeast-1a", "ap-southeast-1b"]
}

module "ec2" {
  source            = "./modules/ec2"
  vpc_id            = module.vpc.vpc_id
  public_subnet_ids = module.vpc.public_subnet_ids
  instance_type     = "t3.medium"
  ssh_public_key    = var.ssh_public_key
}

output "cluster_public_ips" {
  value = module.ec2.web_instance_public_ips
}

Langkah 5: Konfigurasi Ansible Dynamic Inventory & Playbooks

Buat file ansible/inventory/aws_ec2.yml untuk integrasi otomatis inventaris AWS:

plugin: amazon.aws.aws_ec2
regions:
  - ap-southeast-1
filters:
  tag:Role: webserver
  instance-state-name: running
keyed_groups:
  - key: tags.Role
    prefix: role
host_key_checking: false

Buat file ansible/playbooks/site.yml untuk konfigurasi penuh Nginx, PHP-FPM, dan keamanan server:

---
- hosts: role_webserver
  become: yes
  vars:
    php_version: "8.2"
  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: Install essential packages
      apt:
        name:
          - curl
          - git
          - ufw
          - fail2ban
          - software-properties-common
        state: present

    - name: Add PPA for PHP
      apt_repository:
        repo: ppa:ondrej/php
        state: present

    - name: Install Nginx and PHP-FPM
      apt:
        name:
          - nginx
          - php{{ php_version }}-fpm
          - php{{ php_version }}-cli
          - php{{ php_version }}-mysql
          - php{{ php_version }}-redis
          - php{{ php_version }}-mbstring
          - php{{ php_version }}-xml
          - php{{ php_version }}-curl
        state: present

    - name: Start and enable Nginx
      service:
        name: nginx
        state: started
        enabled: yes

    - name: Start and enable PHP-FPM
      service:
        name: php{{ php_version }}-fpm
        state: started
        enabled: yes

    - name: Configure Nginx default virtual host
      copy:
        dest: "/etc/nginx/sites-available/default"
        content: |
          server {
              listen 80 default_server;
              listen [::]:80 default_server;
              root /var/www/html;
              index index.php index.html index.htm;
              server_name _;

              location / {
                  try_files $uri $uri/ /index.php?$query_string;
              }

              location ~ \.php$ {
                  include snippets/fastcgi-php.conf;
                  fastcgi_pass unix:/var/run/php/php{{ php_version }}-fpm.sock;
              }

              location ~ /\.ht {
                  deny all;
              }
          }
      notify: Restart Nginx

    - name: Ensure web root directory exists
      file:
        path: /var/www/html
        state: directory
        owner: www-data
        group: www-data
        mode: '0755'

    - name: Deploy index.php test file
      copy:
        dest: "/var/www/html/index.php"
        content: "<?php echo '<h1>Infrastruktur Immutable Aktif - AWS Terraform Ansible</h1><p>PHP Version: ' . phpversion() . '</p>'; ?>"
        owner: www-data
        group: www-data
        mode: '0644'

  handlers:
    - name: Restart Nginx
      service:
        name: nginx
        state: restarted

[!TIP] Jalankan ansible-inventory -i ansible/inventory/aws_ec2.yml --graph untuk memverifikasi bahwa Ansible berhasil mendeteksi instans EC2 yang baru saja dibuat oleh Terraform melalui API AWS sebelum menjalankan playbook.

6. Bedah Kode & Penjelasan Detail Baris Kunci

  • enable_dns_hostnames = true pada VPC: Parameter ini krusial dalam arsitektur web modern agar instans EC2 mendapatkan nama DNS publik yang dapat diresolusi secara otomatis oleh AWS DNS Resolver. Tanpa ini, komunikasi internal antar-layanan berbasis nama host akan gagal.
  • count.index % length(var.public_subnet_cidrs) pada EC2: Logika modulus ini memastikan bahwa jika Anda meluncurkan 5 instans web namun hanya memiliki 2 Availability Zone/Subnet, instans akan didistribusikan secara merata (round-robin) di antara subnet yang tersedia guna menjaga tinggi ketersediaan (High Availability).
  • Plugin amazon.aws.aws_ec2 di Ansible: Memungkinkan Ansible bertindak sebagai klien AWS API yang cerdas. Alih-alih merawat file hosts statis yang mudah usang, Ansible melakukan query langsung ke tag AWS (tag:Role: webserver) secara real-time.

7. Skenario Produksi & Studi Kasus Dunia Nyata

Dalam skenario lalu lintas tinggi (high concurrency e-commerce flash sale), infrastruktur di atas harus diperluas dengan penambahan Application Load Balancer (ALB) di depan instans EC2 dan Auto Scaling Group (ASG).

Untuk mengintegrasikan Ansible dengan arsitektur Auto Scaling, pendekatan standar adalah membangun Golden AMI menggunakan Packer sebelum Terraform dijalankan. Packer akan menjalankan skrip Ansible di atas AMI kosong, membuat snapshot AMI baru, dan Terraform kemudian meluncurkan instans menggunakan AMI siap pakai tersebut tanpa perlu menunggu Ansible melakukan instalasi saat booting server.

8. Common Pitfalls, Anti-Patterns & Solusi

  • Anti-Pattern 1: Hardcoding IP Address di Ansible Inventory.
    • Solusi: Selalu gunakan dynamic inventory berbasis tag AWS seperti yang dicontohkan di atas agar skalabilitas horizontal tidak terhalang oleh perubahan IP instans.
  • Anti-Pattern 2: Melakukan terraform destroy tanpa mencadangkan database eksternal.
    • Solusi: Gunakan atribut lifecycle { prevent_destroy = true } pada sumber daya penyimpanan kritis seperti database RDS atau S3 bucket utama untuk mencegah penghapusan yang tidak sengaja.
  • Pitfalls 3: Timeout SSH saat Ansible pertama kali berjalan.
    • Solusi: Tambahkan jeda waktu tunggu (sleep) atau blok tunggu koneksi SSH di Cloud-Init agar daemon SSH benar-benar siap menerima koneksi sebelum Ansible mulai mengeksekusi tugas.

9. Benchmark, Metrik Kinerja & Tuning Performa

Untuk menguji performa server web Nginx + PHP-FPM yang baru diprovisioning, jalankan benchmark menggunakan tool wrk dari mesin penguji terpisah:

wrk -t12 -c400 -d30s http://<AWS_EC2_PUBLIC_IP>/

Parameter Tuning Lanjutan pada /etc/sysctl.conf untuk menangani 10.000+ koneksi konkuren (C10K problem):

net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535

Terapkan perubahan ini menggunakan perintah:

sudo sysctl -p

10. Checklist Penerapan Produksi & Kesimpulan

Sebelum meluncurkan sistem ke lingkungan produksi publik, pastikan checklist berikut terpenuhi:

  • State Terraform disimpan di S3 dengan enkripsi KMS dan penguncian DynamoDB diaktifkan.
  • Kunci SSH akses root dinonaktifkan di /etc/ssh/sshd_config, digantikan dengan autentikasi berbasis kunci publik yang aman.
  • Aturan Security Group AWS membatasi port SSH (22) hanya untuk rentang IP kantor atau Bastion Host VPN internal.
  • Fail2ban dikonfigurasi untuk memblokir alamat IP penyerang setelah 3 kali kegagalan autentikasi SSH atau HTTP.
  • Sertifikat SSL/TLS HTTPS terpasang melalui Let's Encrypt dengan pembaruan otomatis via Cron.

Dengan memadukan ketepatan deklaratif Terraform dan fleksibilitas konfigurasi prosedural Ansible, Anda telah membangun fondasi infrastruktur web enterprise yang tahan banting, aman, dan siap menghadapi lonjakan traffic ekstrem tanpa rasa khawatir.

🏷️ Tags: #Devops #Terraform #Ansible #Aws #Infrastructure As Code