Ansible vs Docker Compose

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:

  1. Multi-Host Target: Kita ingin mendeploy kontainer frontend di server grup webservers dan kontainer backend/database di server grup dbservers. Docker Compose tidak dapat melakukan koordinasi lintas server (cross-host coordination).
  2. Ketergantungan Infrastruktur Non-Docker: Sebelum kontainer berjalan, kita harus memperluas partisi disk LVM, memasang sertifikat SSL komersial ke folder /etc/ssl, mengonfigurasi aturan firewall iptables atau ufw, dan mendaftarkan cron job backup ke server penyimpanan eksternal.
  3. Templating Konfigurasi Kompleks: Kita perlu menghasilkan file konfigurasi aplikasi (seperti nginx.conf atau settings.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 .env terenkripsi dari Ansible Vault, menyalin file docker-compose.yml ke 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.yml dan juga menulis ulang parameternya di task docker_container Ansible secara redundan.
  • Best Practice: Jika menggunakan Compose, biarkan file docker-compose.yml menjadi 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 .env berisi password database polos langsung ke repository Git bersama file docker-compose.yml.
  • Best Practice: Simpan password di Ansible Vault. Buat template file env.j2 di Ansible, lalu biarkan Ansible men-generate file .env di 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_v2 untuk mengeksekusi deployment stack secara idempoten dan terstruktur di server target.
  • Amankan dengan Vault — Jangan pernah membiarkan file konfigurasi lingkungan .env berisi rahasia dalam bentuk plaintext di server. Enkripsi variabel rahasia dengan Ansible Vault dan pasang opsi no_log: true pada task terkait.

← Sebelumnya: Deploy Container   Berikutnya: Image Build →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact