L
Infrastructure as Code (IaC) • Literally Web ID

Membangun Infrastruktur Immutable Menggunakan Terraform dan Ansible di AWS

⏱️ 18 menit baca • 📅 14 Oct 2026 • 👁️ 1 views
Membangun Infrastruktur Immutable Menggunakan Terraform dan Ansible di AWS

1. Konteks Industri & Analisis Akar Masalah

Dalam lanskap pengembangan web dan infrastruktur modern, pengelolaan server tradisional berbasis Mutable Infrastructure (infrastruktur yang dapat diubah secara langsung) telah lama menjadi sumber utama kegagalan sistem di lingkungan produksi. Ketika sebuah aplikasi web skala enterprise mengalami lonjakan trafik, atau ketika sebuah patch keamanan kritis untuk Nginx, PHP-FPM, atau kernel Linux harus diterapkan, pendekatan konvensional biasanya melibatkan proses SSH ke dalam server produksi dan menjalankan perintah manual seperti apt update, systemctl restart, atau mengubah konfigurasi secara langsung (hot-patching).

Pendekatan ini melahirkan fenomena klasik yang dikenal sebagai Configuration Drift (penyimpangan konfigurasi). Seiring waktu, tidak ada dua server di dalam satu pool kluster yang memiliki konfigurasi identik. Hal ini memicu bug yang sulit direproduksi ("it works on my staging server, but fails in production"), waktu pemulihan insiden (Recovery Time Objective) yang lama, serta kerentanan keamanan yang terlewatkan akibat inkonsistensi environment.

Sebaliknya, Immutable Infrastructure membalikkan paradigma ini sepenuhnya. Dalam model immutable, server tidak pernah diperbarui (patched) secara langsung. Setiap perubahan—mulai dari versi kode Go/Node.js, pembaruan aturan firewall UFW, konfigurasi VirtualHost Nginx, hingga parameter PHP-FPM—diperlakukan sebagai build artefak baru. Server lama dihancurkan (terminated) dan digantikan sepenuhnya oleh instance baru yang bersih dari golden image.

Kondisi Sebelum vs Sesudah Penerapan

Aspek Mutable Infrastructure (Tradisional) Immutable Infrastructure (Terraform & Ansible) Dampak Bisnis / Operasional
Deploy & Patch SSH manual, git pull, composer install di server live. Automasi penuh, Golden Image (AMI) baru, Zero-downtime rolling replacement. Meniadakan human error, mempercepat rilis dari hari ke menit.
Configuration Drift Tinggi. Konfigurasi antar server berbeda karena patch manual. Nol. Seluruh node diinisialisasi dari basis AMI yang identik. Stabilitas sistem meningkat drastis, debugging lebih cepat.
Disaster Recovery Lambat. Harus membangun ulang server dari awal secara manual. Instan. Terraform mendestroy dan mereprovisioning infrastruktur dalam hitungan menit. RTO (Recovery Time Objective) turun drastis dari jam ke menit.
Auditabilitas Rendah. Jejak perubahan hilang di dalam log terminal sysadmin. Tinggi. Semua infrastruktur didefinisikan secara deklaratif dalam bentuk kode (IaC). Kepatuhan terhadap standar keamanan (SOC2, ISO27001) lebih mudah dipenuhi.

[!WARNING] Jangan pernah melakukan SSH-driven development atau mengubah file konfigurasi di server produksi. Segala perubahan manual akan hilang saat instance di-recycle dan merusak integritas Infrastructure as Code Anda.


2. Konsep Inti & Deep Dive Arsitektur

Arsitektur infrastruktur immutable yang robust mengandalkan kombinasi dua pilar utama: Terraform untuk Orkestrasi dan Provisioning lapisan fondasi (VPC, Subnet, Security Group, IAM, EC2 Instance, EBS Volume, Load Balancer) secara deklaratif, dan Ansible untuk Konfigurasi Manajemen (instalasi Runtime Go/Node/PHP, konfigurasi Web Server Nginx, pengaturan SSL Let's Encrypt, optimasi Redis dan MySQL, serta manajemen service Supervisor).

Alur kerja end-to-end (pipeline execution flow) dari pembuatan infrastruktur hingga aplikasi siap melayani pengguna dapat divisualisasikan melalui diagram arsitektur berikut:

+-------------------------------------------------------------------------+
|                        Developer Workstation                            |
|  +--------------------+             +--------------------+              |
|  |  Terraform Apply   | ----------> |   Ansible Playbook |              |
|  +--------------------+             +--------------------+              |
+-----------------------------------------------|-------------------------+
                                                | (Provision & Configure)
                                                v
+-------------------------------------------------------------------------+
|                                AWS Cloud                                |
|                                                                         |
|  +-------------------------------------------------------------------+  |
|  |                             VPC (10.0.0.0/16)                     |  |
|  |                                                                   |  |
|  |  +-----------------------+           +-------------------------+  |  |
|  |  | Public Subnet (ALB)   |           | Private Subnet (Web/App)|  |  |
|  |  | 10.0.1.0/24           |           | 10.0.10.0/24            |  |  |
|  |  |                       |           |                         |  |  |
|  |  |  [Application Load    | --------> |  [EC2: Nginx + PHP-FPM] |  |  |
|  |  |       Balancer]       |           |  [Go / Node.js Backend] |  |  |
|  |  +-----------------------+           +-------------------------+  |  |
|  |                                                   |               |  |
|  |                                                   v               |  |
|  |                                       +-------------------------+  |  |
|  |                                       | Database Subnet         |  |  |
|  |                                       | 10.0.20.0/24            |  |  |
|  |                                       | [MySQL / MariaDB + Redis|  |  |
|  |                                       +-------------------------+  |  |
|  |___________________________________________________________________|  |
+-------------------------------------------------------------------------+

Alur Eksekusi Data & Eksekusi:

  1. Inisialisasi Fondasi (Terraform): Terraform membaca file konfigurasi .tf, membuat jaringan privat virtual (VPC), subnet publik/privat, route table, internet gateway, security group, serta memprovisikan instance EC2.
  2. Konfigurasi Software (Ansible): Setelah instance EC2 berstatus running, Terraform secara otomatis (melalui remote-exec atau trigger inventory dinamis) memanggil Ansible Playbook.
  3. Eksekusi Playbook: Ansible terhubung ke instance melalui SSH, menginstal paket sistem operasi, mendownload source code aplikasi web, mengkonfigurasi Nginx, menyetel izin file (permissions), mengaktifkan supervisor untuk queue worker, dan mengamankan SSL via Certbot.
  4. Edge & Traffic Routing (Cloudflare & ALB): Trafik publik masuk melalui Cloudflare (WAF & CDN), diteruskan ke AWS Application Load Balancer, lalu didistribusikan secara aman ke instans EC2 di Private Subnet.

3. Perbandingan Komparatif / Analisis Pendekatan

Dalam membangun sistem otomatisasi cloud, terdapat beberapa pendekatan populer selain kombinasi Terraform + Ansible. Berikut adalah analisis mendalam untuk membantu Anda memilih arsitektur yang paling tepat berdasarkan kebutuhan enterprise:

Kriteria Penilaian Terraform + Ansible (Hybrid) AWS CloudFormation + AWS Systems Manager Packer + Terraform + AWS Auto Scaling Pulumi + Python/TypeScript
Bahasa Deklarasi HCL (Terraform) & YAML (Ansible) JSON / YAML (CloudFormation) HCL + JSON (Packer) TypeScript, Python, Go, C#
Cloud Agnostic Ya (Multi-cloud: AWS, GCP, Azure) Tidak (Eksklusif AWS) Ya (Multi-cloud AMI/Image builder) Ya (Multi-cloud)
Kecepatan Deploy Menengah (Provisioning + Config time) Lambat hingga Menengah Sangat Cepat (Karena menggunakan pre-baked AMI) Cepat
Kompleksitas Kurva Belajar Menengah (Menguasai dua tool berbeda) Rendah hingga Menengah Tinggi (Manajemen siklus image) Tinggi (Butuh pemahaman OOP/Functional)
Manajemen State Remote State (S3 + DynamoDB Lock) Dikelola sepenuhnya oleh AWS Stack S3 / Terraform Cloud State Pulumi Service / S3 Backend

[!TIP] Kombinasi Terraform + Ansible adalah standar industri paling fleksibel. Terraform sangat unggul dalam manajemen infrastruktur cloud abstrak, sementara Ansible adalah raja dalam konfigurasi sistem operasi tingkat lanjut dan manajemen software stack.


4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum menjalankan kode implementasi, pastikan workstation atau CI/CD Runner Anda telah terinstal dependensi berikut dengan versi minimum yang disarankan:

  • Terraform: Versi >= 1.5.0
  • Ansible: Versi >= 2.15.0
  • AWS CLI: Versi >= 2.13.0 yang sudah dikonfigurasi dengan kredensial (aws configure) yang memiliki hak akses penuh (AdministratorAccess atau policy kustom VPC/EC2/IAM).
  • SSH Key Pair: Key pair lokal yang didaftarkan ke AWS untuk akses Ansible (~/.ssh/id_rsa.pub).

Verifikasi instalasi melalui terminal:

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

5. Panduan Implementasi Langkah demi Langkah

Struktur direktori proyek enterprise Anda harus dirancang secara modular seperti berikut:

infrastructure-project/
├── terraform/
│   ├── main.tf
│   ├── variables.tf
│   ├── outputs.tf
│   └── terraform.tfvars
└── ansible/
    ├── playbook.yml
    └── inventory.ini

Langkah 1: Provisioning Infrastruktur dengan Terraform

Buat file terraform/main.tf untuk mendefinisikan VPC, subnet, security group, dan instance EC2 web server.

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
}

# 1. Virtual Private Cloud (VPC)
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name        = "enterprise-vpc"
    Environment = var.environment
  }
}

# 2. Internet Gateway
resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.main.id

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

# 3. Public Subnet
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  map_public_ip_on_launch = true
  availability_zone       = "ap-southeast-1a"

  tags = {
    Name = "enterprise-public-subnet"
  }
}

# 4. Route Table Public
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
}

# 5. Security Group untuk Web Server
resource "aws_security_group" "web_sg" {
  name        = "web-server-sg"
  description = "Allow HTTP, HTTPS and SSH"
  vpc_id      = aws_vpc.main.id

  ingress {
    description = "Allow SSH from Admin IP"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = [var.admin_ip]
  }

  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"]
  }

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

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

# 6. Key Pair AWS
resource "aws_key_pair" "deployer" {
  key_name   = "enterprise-deployer-key"
  public_key = file(var.ssh_public_key_path)
}

# 7. EC2 Instance Web Server
resource "aws_instance" "web_server" {
  ami                    = var.ubuntu_ami_id
  instance_type          = var.instance_type
  subnet_id              = aws_subnet.public.id
  vpc_security_group_ids = [aws_security_group.web_sg.id]
  key_name               = aws_key_pair.deployer.key_name

  root_block_device {
    volume_size           = 40
    volume_type           = "gp3"
    delete_on_termination = true
  }

  tags = {
    Name        = "enterprise-web-node-01"
    Environment = var.environment
  }
}

Buat file terraform/variables.tf:

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

variable "environment" {
  type    = string
  default = "production"
}

variable "admin_ip" {
  type        = string
  description = "Your office/VPN CIDR for SSH access"
}

variable "ssh_public_key_path" {
  type    = string
  default = "~/.ssh/id_rsa.pub"
}

variable "ubuntu_ami_id" {
  type        = string
  description = "Ubuntu 22.04 LTS AMI ID for ap-southeast-1"
  default     = "ami-060e277c0d4cce553"
}

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

Buat file terraform/outputs.tf untuk mengekspor IP publik instance:

output "web_server_public_ip" {
  value       = aws_instance.web_server.public_ip
  description = "Public IP address of the web server for Ansible inventory"
}

Buat file terraform/terraform.tfvars:

aws_region          = "ap-southeast-1"
environment         = "production"
admin_ip            = "203.0.113.50/32"
ssh_public_key_path = "~/.ssh/id_rsa.pub"
instance_type       = "t3.medium"

Inisialisasi dan jalankan Terraform:

cd terraform
terraform init
terraform plan -out=tfplan
terraform apply tfplan

Langkah 2: Konfigurasi Software Stack dengan Ansible Playbooks

Setelah Terraform selesai dan mengeluarkan IP publik server, buat file inventory Ansible ansible/inventory.ini. Anda dapat memasukkan IP output Terraform secara otomatis atau manual:

[webservers]
<MASUKKAN_PUBLIC_IP_TERRAFOM_DISINI> ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsa

Buat file ansible/playbook.yml yang mencakup instalasi Nginx, PHP-FPM, Redis, konfigurasi Firewall UFW, penyiapan direktori web, dan VirtualHost Nginx produksi:

---
- name: Provision and Configure Web Server Stack
  hosts: webservers
  become: yes
  vars:
    app_user: "www-data"
    php_version: "8.2"

  tasks:
    - name: Update apt cache and upgrade packages
      apt:
        update_cache: yes
        cache_valid_time: 3600

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

    - name: Add PPA for PHP (Ondrej Sury)
      apt_repository:
        repo: "ppa:ondrej/php"
        state: present

    - name: Install Nginx, PHP-FPM, and Database Client
      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
          - redis-server
        state: present
        update_cache: yes

    - name: Configure UFW Firewall
      ufw:
        rule: allow
        port: "{{ item }}"
        proto: tcp
      loop:
        - "22"
        - "80"
        - "443"

    - name: Enable UFW
      ufw:
        state: enabled
        policy: deny

    - name: Ensure Nginx is running and enabled
      service:
        name: nginx
        state: started
        enabled: yes

    - name: Ensure PHP-FPM is running and enabled
      service:
        name: "php{{ php_version }}-fpm"
        state: started
        enabled: yes

    - name: Ensure Redis is running and enabled
      service:
        name: redis-server
        state: started
        enabled: yes

    - name: Create web application root directory
      file:
        path: /var/www/html/public
        state: directory
        owner: "{{ app_user }}"
        group: "{{ app_user }}"
        mode: '0755'

    - name: Deploy Production Nginx VirtualHost Configuration
      copy:
        dest: "/etc/nginx/sites-available/default"
        content: |
          server {
              listen 80;
              server_name _;
              root /var/www/html/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;
              }

              error_page 404 /index.php;

              location ~ \.php$ {
                  fastcgi_pass unix:/var/run/php/php{{ php_version }}-fpm.sock;
                  fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
                  include fastcgi_params;
              }

              location ~ /\.(?!well-known).* {
                  deny all;
              }
          }
      notify:
        - Restart Nginx

    - name: Create a sample PHP info file for validation
      copy:
        dest: "/var/www/html/public/index.php"
        content: "<?php echo '<h1>Enterprise Immutable Infrastructure Node Operational</h1>'; phpinfo(); ?>"
        owner: "{{ app_user }}"
        group: "{{ app_user }}"
        mode: '0644'

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

Jalankan Ansible Playbook:

cd ansible
ansible-playbook -i inventory.ini playbook.yml

6. Bedah Kode & Penjelasan Detail Baris Kunci

Mari kita bedah beberapa parameter krusial dalam file konfigurasi yang telah kita bangun:

  1. delete_on_termination = true pada Blok EBS (terraform/main.tf): Parameter ini memastikan bahwa ketika instance EC2 dihancurkan (misalnya saat proses rolling update), volume disk root EBS ikut terhapus secara otomatis. Hal ini mencegah akumulasi penyimpanan yatim piatu (orphan volume) yang dapat membengkakkan tagihan AWS cloud Anda.

  2. try_files $uri $uri/ /index.php?$query_string; pada Nginx VirtualHost (ansible/playbook.yml): Baris ini sangat vital untuk arsitektur web modern berbasis Front Controller (seperti Laravel, Symfony, atau SPA router). Jika file atau direktori fisik tidak ditemukan di server, Nginx akan mengalihkan seluruh request ke index.php secara mulus tanpa mencetak error 404 Not Found.

  3. UFW Default Policy deny dengan Allowlist Eksplisit: Di dalam Ansible task, kami menerapkan kebijakan ketat menolak seluruh trafik masuk secara default (policy: deny), kecuali port SSH (22), HTTP (80), dan HTTPS (443). Ini adalah lini pertahanan pertama untuk mencegah akses ilegal dari bot scanner internet.


7. Skenario Produksi & Studi Kasus Dunia Nyata

Dalam skenario produksi nyata berbeaya tinggi (misalnya menangani flash sale e-commerce dengan 50.000 concurrent users), arsitektur single instance di atas perlu ditingkatkan menjadi Auto Scaling Group (ASG) di balik Application Load Balancer (ALB) dengan AWS RDS (Relational Database Service).

Alih-alih mengkonfigurasi EC2 mentah menggunakan Ansible secara langsung pada instance runtime, pendekatan enterprise terbaik adalah menggunakan HashiCorp Packer. Packer menggunakan skrip Ansible yang sama untuk membangun Golden AMI (Amazon Machine Image). Ketika ada pembaruan kode aplikasi:

  1. CI/CD Pipeline (GitHub Actions / GitLab CI) memicu Packer untuk membuat AMI baru yang sudah berisi kode terbaru.
  2. Terraform memperbarui launch_template di ASG dengan AMI terbaru tersebut.
  3. Terraform memicu perintah aws autoscaling start-instance-refresh, yang secara otomatis melakukan rolling update (mengganti instance lama dengan instance baru satu per satu tanpa downtime).

8. Common Pitfalls, Anti-Patterns & Solusi

Berikut adalah kesalahan fatal yang sering dilakukan oleh engineer pemula hingga menengah saat mengimplementasikan Terraform dan Ansible:

  • Anti-Pattern 1: Menyimpan Terraform State File secara Lokal (terraform.tfstate)
    • Dampak: Jika dua orang engineer menjalankan terraform apply dari komputer lokal berbeda, state file akan korup dan terjadi konflik resource.
    • Solusi: Selalu gunakan Remote Backend seperti AWS S3 dengan enkripsi aktif dan DynamoDB untuk State Locking.
  • Anti-Pattern 2: Menggunakan Ansible untuk Mengubah Infrastruktur Cloud
    • Dampak: Menggunakan Ansible untuk membuat VPC atau Security Group di AWS. Ini adalah pelanggaran batas tanggung jawab (separation of concerns).
    • Solusi: Serahkan seluruh provisioning infrastruktur cloud kepada Terraform, dan gunakan Ansible khusus untuk manajemen konfigurasi di dalam sistem operasi (OS Configuration).
  • Anti-Pattern 3: Hardcoding Kredensial Sensitif di dalam Playbook atau TFVars
    • Dampak: Kebocoran password database atau secret key di public repository GitHub.
    • Solusi: Manfaatkan AWS Secrets Manager, Parameter Store, atau variabel lingkungan sensitif (environment variables).

9. Benchmark, Metrik Kinerja & Tuning Performa

Setelah infrastruktur immutable berdiri, lakukan pengujian beban (load testing) untuk memastikan server Nginx dan PHP-FPM mampu menangani konkurensi tinggi. Gunakan tool benchmarking modern seperti k6 atau Apache Bench (ab).

Contoh skrip uji beban sederhana menggunakan ab untuk 10.000 request dengan 100 konkurensi paralel:

ab -n 10000 -c 100 http://<YOUR_WEB_SERVER_PUBLIC_IP>/

Tuning Performa Lanjutan di Nginx & PHP-FPM:

  1. Nginx Worker Processes: Sesuaikan worker_processes auto; di file /etc/nginx/nginx.conf agar Nginx menggunakan seluruh inti CPU (vCPU) yang tersedia pada instance t3.medium.
  2. PHP-FPM Process Manager: Pada /etc/php/8.2/fpm/pool.d/www.conf, ubah dari pm = dynamic menjadi pm = static dengan jumlah pm.max_children = 50 (tergantung alokasi RAM instance) untuk menghindari overhead pembuatan proses baru saat lonjakan trafik mendadak.

10. Checklist Penerapan Produksi & Kesimpulan

Sebelum meluncurkan infrastruktur immutable Anda ke lingkungan live/production, pastikan seluruh item dalam checklist berikut telah terpenuhi:

  • Remote state Terraform diamankan di S3 dengan enkripsi AES-256 dan penguncian DynamoDB.
  • SSH key root dinonaktifkan atau dibatasi ketat melalui pembatasan IP CIDR pada Security Group AWS.
  • Seluruh file konfigurasi sensitif dikelola melalui enkripsi (Ansible Vault atau AWS Secrets Manager).
  • Monitoring dan log centralizer (seperti CloudWatch Agent atau Prometheus/Grafana) telah terpasang di dalam Ansible Playbook.
  • Uji coba Disaster Recovery (menghancurkan dan membangun ulang seluruh stack dari nol) telah berhasil dilakukan tanpa kendala.

Dengan mengintegrasikan Terraform dan Ansible secara disiplin dalam paradigma infrastruktur immutable, organisasi Anda tidak hanya mencapai otomatisasi penuh, tetapi juga membangun ketahanan sistem yang luar biasa, keamanan tingkat tinggi, dan skalabilitas tanpa batas di ekosistem AWS.

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