Ansible vs Docker Compose #
Saat kita mulai merancang otomatisasi infrastruktur untuk aplikasi berbasis container, satu pertanyaan arsitektur yang sangat sering muncul adalah: “Mengapa kita harus menggunakan Ansible jika kita sudah bisa mendefinisikan seluruh stack container kita di dalam file docker-compose.yml?” Pertanyaan ini wajar karena kedua alat tersebut memiliki kemampuan untuk menjalankan dan mengelola siklus hidup kontainer.
Namun, mengadu Ansible dan Docker Compose sebagai dua alternatif yang saling menggantikan adalah cara pandang yang kurang tepat. Kedua alat ini dibangun dengan filosofi, cakupan (scope), dan fokus arsitektur yang sangat berbeda. Docker Compose dirancang khusus untuk mendefinisikan dan menjalankan aplikasi multi-container pada satu host target. Sementara itu, Ansible adalah alat manajemen konfigurasi dan otomatisasi infrastruktur berskala luas yang mampu beroperasi di banyak host target secara paralel. Memahami kekuatan masing-masing alat, kapan harus memilih salah satunya, dan bagaimana mengintegrasikan keduanya secara hibrida adalah kunci penting dalam membangun alur deployment tingkat production.
flowchart TD
Start["Analisis Kebutuhan Deployment"] --> Q1{"Berapa jumlah host target?"}
Q1 -- "Satu Host" --> Q2{"Apakah hanya menjalankan container?"}
Q1 -- "Banyak Host" --> UseAnsible["Gunakan Ansible secara Mutlak"]
Q2 -- "Ya" --> UseCompose["Gunakan Docker Compose Langsung"]
Q2 -- "Tidak (Perlu Setup OS/Firewall/SSL)" --> UseHybrid["Gunakan Pola Hibrida: Ansible + Compose"]
UseAnsible --> Q3{"Butuh orkestrasi microservices rumit?"}
Q3 -- "Ya" --> UseK8s["Pertimbangkan Kubernetes (K8s)"]
Q3 -- "Tidak" --> UseAnsibleOnly["Gunakan Playbook Ansible + Docker Modules"]
Perbandingan Filosofi dan Arsitektur #
Docker Compose bekerja di level container runtime pada satu mesin. Ia membaca file deskripsi YAML lokal (docker-compose.yml) lalu menerjemahkannya ke dalam panggilan API ke Docker daemon lokal. Fokus utamanya adalah menyederhanakan hubungan ketergantungan antar kontainer (seperti jaringan internal dan urutan startup) agar developer tidak perlu mengetikkan puluhan parameter docker run yang panjang.
Ansible, di sisi lain, bekerja dengan prinsip agentless melalui koneksi SSH atau WinRM. Ia tidak peduli apakah targetnya berupa bare-metal server, mesin virtual (VM), cloud instance, atau sekadar kontainer lokal. Ansible melihat kontainer Docker hanya sebagai salah satu dari sekian banyak komponen infrastruktur yang harus dikelola—bersama dengan konfigurasi kernel OS, paket keamanan, sertifikat SSL, aturan firewall, pembuatan user, dan mounting penyimpanan fisik.
Berikut adalah tabel komparatif menyeluruh untuk melihat perbedaan karakteristik kedua alat ini:
| Kriteria Analisis | Docker Compose | Ansible (Modul Docker) |
|---|---|---|
| Cakupan Operasional | Terbatas pada satu host Docker saja (single host). | Mampu mengelola ratusan server secara paralel (multi-host). |
| Model Arsitektur | Membutuhkan Docker CLI dan Compose plugin terinstal secara lokal di host target. | Agentless. Hanya memerlukan Python di host target dan SSH akses. |
| Manajemen OS Host | Tidak memiliki kemampuan untuk mengonfigurasi sistem operasi, firewall, atau paket OS host. | Sangat kuat dalam mengonfigurasi seluruh aspek OS host sebelum menjalankan Docker. |
| Logika Kondisional | Terbatas pada dependensi status kesehatan kontainer (depends_on). |
Sangat fleksibel dengan blok kondisional (when), loop, handler, dan assert. |
| Manajemen Secret | Tergantung pada file .env lokal atau secret file yang rahasianya sering kali terekspos jika tidak hati-hati. |
Integrasi bawaan dengan Ansible Vault untuk enkripsi secret tingkat variabel. |
| Templating Dinamis | Terbatas pada substitusi variabel lingkungan dasar. | Memiliki mesin template Jinja2 penuh untuk menyusun file konfigurasi yang sangat kompleks. |
Kapan Memilih Docker Compose #
Docker Compose adalah alat yang sangat ekspresif dan ramah pengguna (user-friendly) saat kita berada di lingkungan pengembangan lokal (local development) atau mendeploy aplikasi multi-container mandiri pada satu server staging.
Compose unggul karena sintaksisnya yang ringkas dalam mendefinisikan jaringan privat antar kontainer, isolasi volume, dan ketergantungan urutan startup kontainer (depends_on dengan kondisi service_healthy).
Contoh File docker-compose.yml Tingkat Production #
Di bawah ini adalah contoh file Compose yang mendefinisikan stack web 3-tier (App Node.js, Cache Redis, dan Database PostgreSQL) lengkap dengan verifikasi kesehatan sistem:
# docker-compose.yml
version: "3.8"
services:
web-app:
image: company/node-app:v2.4.0
container_name: production-web
restart: unless-stopped
ports:
- "8080:3000"
environment:
DATABASE_URL: "postgresql://app_user:app_secure_pass@db-service:5432/production_db"
REDIS_URL: "redis://cache-service:6379"
NODE_ENV: "production"
depends_on:
db-service:
condition: service_healthy
cache-service:
condition: service_started
networks:
- app-network
db-service:
image: postgres:15-alpine
container_name: production-db
restart: unless-stopped
volumes:
- pg-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: "production_db"
POSTGRES_USER: "app_user"
POSTGRES_PASSWORD: "app_secure_pass"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app_user -d production_db"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
cache-service:
image: redis:7-alpine
container_name: production-redis
restart: unless-stopped
networks:
- app-network
volumes:
pg-data:
driver: local
networks:
app-network:
driver: bridge
Dalam skenario pengembangan lokal, developer cukup menjalankan satu perintah docker compose up -d untuk menghidupkan seluruh ekosistem aplikasi ini beserta relasi antar komponennya.
Kapan Memilih Ansible untuk Pengelolaan Kontainer #
Kita harus beralih menggunakan Ansible ketika lingkup deployment kita telah melampaui batas satu aplikasi mandiri. Beberapa contoh kebutuhan nyata yang tidak dapat diselesaikan oleh Docker Compose meliputi:
- Multi-Host Target: Kita ingin mendeploy kontainer frontend di server grup
webserversdan kontainer backend/database di server grupdbservers. Docker Compose tidak dapat melakukan koordinasi lintas server (cross-host coordination). - Ketergantungan Infrastruktur Non-Docker: Sebelum kontainer berjalan, kita harus memperluas partisi disk LVM, memasang sertifikat SSL komersial ke folder
/etc/ssl, mengonfigurasi aturan firewalliptablesatauufw, dan mendaftarkan cron job backup ke server penyimpanan eksternal. - Templating Konfigurasi Kompleks: Kita perlu menghasilkan file konfigurasi aplikasi (seperti
nginx.confatausettings.py) secara dinamis berdasarkan IP internal server yang dideteksi secara otomatis saat runtime oleh Ansible.
Berikut adalah contoh playbook Ansible yang menangani seluruh persiapan infrastruktur non-docker sebelum akhirnya menjalankan kontainer Docker:
# playbooks/deploy_infrastruktur_dan_docker.yml
---
- name: Siapkan Infrastruktur Host dan Jalankan Container
hosts: app_servers
become: true
vars:
app_port: 8080
tasks:
- name: 1. Pastikan UFW (Firewall) terinstal
apt:
name: ufw
state: present
- name: 2. Buka akses port aplikasi di firewall host
ufw:
rule: allow
port: "{{ app_port }}"
proto: tcp
- name: 3. Buat direktori penyimpanan data persisten
file:
path: /var/data/webapp
state: directory
owner: www-data
group: www-data
mode: '0750'
- name: 4. Salin sertifikat SSL host secara dinamis
copy:
src: "files/ssl/{{ inventory_hostname }}.crt"
dest: /etc/ssl/certs/app.crt
owner: root
group: root
mode: '0640'
- name: 5. Jalankan kontainer menggunakan modul Ansible
community.docker.docker_container:
name: my-web-app
image: nginx:alpine
state: started
ports:
- "{{ app_port }}:80"
volumes:
- "/var/data/webapp:/usr/share/nginx/html:ro"
- "/etc/ssl/certs/app.crt:/etc/nginx/ssl/app.crt:ro"
Integrasi Terbaik: Ansible Mendeploy Docker Compose #
Di dunia nyata tingkat production, kita tidak perlu memaksakan diri untuk memilih salah satu alat secara ekstrem. Pola integrasi hibrida (hybrid pattern) adalah pendekatan terbaik yang diadopsi oleh banyak tim DevOps modern: Gunakan Ansible sebagai orkestrator dan penyiap infrastruktur host, lalu gunakan Docker Compose sebagai pendefinisi stack aplikasi.
Dalam pola ini, peran dibagi secara jelas:
- Ansible: Mengelola VM, menginstal Docker Engine, mengonfigurasi daemon, menyiapkan direktori, menyalin sertifikat SSL, menghasilkan file
.envterenkripsi dari Ansible Vault, menyalin filedocker-compose.ymlke host target, dan mengeksekusi Compose stack. - Docker Compose: Menentukan ketergantungan antar kontainer, konfigurasi jaringan privat mikro, dan parameter pemetaan internal aplikasi.
Ansible menyediakan modul community.docker.docker_compose_v2 untuk mengeksekusi stack Compose dengan cara yang sangat rapi dan idempoten.
Contoh Implementasi Playbook Hibrida #
Berikut adalah susunan task hibrida lengkap yang mendeploy file Compose ke server target:
# playbooks/deploy_hybrid_stack.yml
---
- name: Deploy Aplikasi Hibrida via Docker Compose
hosts: production_servers
become: true
vars:
project_dir: "/opt/production_app"
app_db_pass: "{{ vault_db_password }}" # Variabel sensitif dari Vault
tasks:
- name: 1. Pastikan direktori projek aplikasi ada di host
file:
path: "{{ project_dir }}"
state: directory
owner: deployer
group: docker
mode: '0775'
- name: 2. Deploy file docker-compose.yml dari template Jinja2
template:
src: templates/docker-compose.yml.j2
dest: "{{ project_dir }}/docker-compose.yml"
owner: deployer
group: docker
mode: '0644'
- name: 3. Deploy file lingkungan .env secara aman (menggunakan no_log)
template:
src: templates/env.j2
dest: "{{ project_dir }}/.env"
owner: deployer
group: docker
mode: '0600' # Hanya boleh dibaca oleh pemilik (deployer)
no_log: true
- name: 4. Tarik (pull) image terbaru yang didefinisikan dalam file Compose
community.docker.docker_compose_v2:
project_src: "{{ project_dir }}"
state: present
pull: always # Menjamin kita menarik image terbaru sebelum start
register: compose_pull_result
- name: 5. Jalankan stack Docker Compose secara utuh
community.docker.docker_compose_v2:
project_src: "{{ project_dir }}"
state: present
recreate: auto # Otomatis me-recreate kontainer jika konfigurasi berubah
build: false # Jangan build di target server, gunakan pre-built image
Dengan metode ini, tim developer tetap dapat memperbarui file docker-compose.yml mereka di repository git aplikasi, sementara tim operasi (Ops) cukup menggunakan Ansible untuk menarik pembaruan tersebut dan me-deploy-nya secara konsisten ke seluruh cluster server production.
Pola Anti-pattern dan Best Practice Integrasi #
Agar integrasi hibrida berjalan mulus, ada beberapa kebiasaan buruk (anti-pattern) yang harus kita hindari, beserta solusi terbaik (best practice) sebagai panduan implementasi:
1. Duplikasi Definisi Parameter Kontainer #
- Anti-pattern: Mendefinisikan port, volume, dan variabel lingkungan yang sama di dalam file
docker-compose.ymldan juga menulis ulang parameternya di taskdocker_containerAnsible secara redundan. - Best Practice: Jika menggunakan Compose, biarkan file
docker-compose.ymlmenjadi satu-satunya sumber kebenaran (single source of truth) mengenai struktur kontainer. Gunakan Ansible hanya untuk mengirimkan file tersebut dan memicu eksekusinya.
2. Menyimpan File .env yang Berisi Rahasia di Git
#
- Anti-pattern: Menyimpan file
.envberisi password database polos langsung ke repository Git bersama filedocker-compose.yml. - Best Practice: Simpan password di Ansible Vault. Buat template file
env.j2di Ansible, lalu biarkan Ansible men-generate file.envdi server target saat proses deployment berlangsung dengan izin hak akses file yang sangat ketat (0600).
Struktur Direktori Proyek Integrasi Hibrida #
Ketika kita menggabungkan Ansible dan Docker Compose, menyusun tata letak folder yang rapi dan terstandarisasi sangat penting untuk menjaga kejelasan kode. Tanpa struktur yang jelas, file playbook, template Jinja2, dan deskripsi docker-compose akan bercampur aduk, menyulitkan tim pengembang dan operasional untuk melakukan kolaborasi.
Berikut adalah pola struktur direktori yang direkomendasikan untuk proyek integrasi hibrida tingkat production:
ansible-compose-project/
├── group_vars/
│ ├── all.yml # Variabel umum untuk seluruh environment
│ ├── staging.yml # Konfigurasi khusus staging
│ └── production.yml # Konfigurasi khusus production (misal: domain, IP)
├── host_vars/
│ └── app-node-01.yml # Parameter spesifik per server host
├── roles/
│ ├── common/ # Role untuk penyiapan dasar OS, firewall, & user
│ ├── docker/ # Role untuk instalasi & konfigurasi Docker Engine
│ └── app_deploy/ # Role khusus untuk men-deploy stack Compose
│ ├── tasks/
│ │ └── main.yml # Alur task deployment Compose
│ └── templates/
│ ├── docker-compose.yml.j2 # Template Compose dinamis
│ └── env.j2 # Template file lingkungan (.env)
├── playbooks/
│ └── deploy.yml # Playbook utama yang memanggil seluruh role
├── inventory/
│ ├── staging # Daftar server staging
│ └── production # Daftar server production
└── ansible.cfg # Konfigurasi global Ansible
Dalam struktur ini, role app_deploy hanya fokus pada pengelolaan siklus hidup aplikasi. Template docker-compose.yml.j2 di dalamnya dapat membaca variabel dari file di group_vars/production.yml secara dinamis saat playbook dijalankan, memungkinkan file Compose yang sama digunakan di staging maupun production tanpa perubahan manual.
Strategi Troubleshooting dan Log Monitoring Lintas Host #
Salah satu kelemahan terbesar Docker Compose adalah keterbatasan visibilitasnya ketika aplikasi berjalan di banyak server. Jika kita mendeploy aplikasi ke 5 server web yang berbeda menggunakan Docker Compose secara manual, kita harus melakukan SSH ke masing-masing dari kelima server tersebut dan mengetikkan docker compose logs secara terpisah untuk mencari sumber error.
Ansible memecahkan tantangan ini dengan memungkinkannya bertindak sebagai konsol agregasi log terpusat sederhana melalui orkestrasi perintah ad-hoc atau playbook troubleshooting.
Berikut adalah contoh playbook Ansible khusus untuk mendiagnosis dan mengumpulkan log error dari seluruh host target secara terpusat:
# playbooks/troubleshoot.yml
---
- name: Agregasi Log Error Kontainer Lintas Host
hosts: production_servers
become: true
vars:
project_dir: "/opt/production_app"
log_output_dir: "./debug_logs"
tasks:
- name: 1. Periksa status kesehatan seluruh kontainer di server target
community.docker.docker_compose_v2:
project_src: "{{ project_dir }}"
state: present
register: compose_status
- name: 2. Kumpulkan log kontainer yang bermasalah (terakhir 50 baris)
command: "docker compose -p {{ compose_status.actions[0].project }} logs --tail=50"
args:
chdir: "{{ project_dir }}"
register: container_logs
changed_when: false
- name: 3. Buat direktori penyimpanan debug lokal di control node
file:
path: "{{ log_output_dir }}"
state: directory
delegate_to: localhost
run_once: true
- name: 4. Simpan log dari masing-masing server ke file lokal
copy:
content: "{{ container_logs.stdout }}"
dest: "{{ log_output_dir }}/logs-{{ inventory_hostname }}.txt"
delegate_to: localhost
Ketika playbook debugging ini dieksekusi, Ansible akan berjalan secara paralel di seluruh host, mengekstrak log terbaru dari kontainer, dan menyimpannya di mesin kontrol lokal kita dalam folder ./debug_logs/ terpisah per server (misal: logs-web-01.txt, logs-web-02.txt). Pola troubleshooting terorkestrasi ini menghemat waktu deteksi insiden secara signifikan.
Ringkasan #
- Fokus Docker Compose — Sempurna untuk mendefinisikan hubungan multi-container pada satu server target tunggal, terutama pada lingkungan lokal dan staging terisolasi.
- Fokus Ansible — Sangat unggul untuk manajemen multi-host target, otomatisasi konfigurasi sistem operasi dasar, pengelolaan keamanan host, dan koordinasi alur kerja lintas server.
- Gunakan Pendekatan Hibrida — Terapkan kombinasi terbaik: gunakan Ansible untuk menyiapkan sistem operasi host dan mengirim berkas, lalu gunakan Docker Compose untuk mengorkestrasi siklus hidup kontainer.
- Gunakan Modul docker_compose_v2 — Manfaatkan modul resmi Ansible
community.docker.docker_compose_v2untuk mengeksekusi deployment stack secara idempoten dan terstruktur di server target.- Amankan dengan Vault — Jangan pernah membiarkan file konfigurasi lingkungan
.envberisi rahasia dalam bentuk plaintext di server. Enkripsi variabel rahasia dengan Ansible Vault dan pasang opsino_log: truepada task terkait.