FlowingDev

Mengenal Docker Compose: remot universal untuk container-containermu

Pelajari cara Docker Compose menggunakan file YAML untuk mengelola aplikasi multi-container, mengubah perintah docker run yang rumit menjadi satu blueprint yang bisa dibagikan.

Coba tool-nya: Docker Run ke Compose

Dalam satu kalimat

Docker Compose adalah tool yang memungkinkan kamu mendefinisikan dan menjalankan aplikasi multi-container menggunakan satu file YAML yang mudah dibaca, alih-alih sekumpulan perintah docker run yang panjang dan ribet.

Masalah yang dipecahkan

Pada mulanya, ada docker run. Dan ya... lumayan lah. Untuk menjalankan satu container, oke-oke aja. Kamu ketik perintahnya, mungkin tambah port mapping dan volume, dan boom, servis kamu langsung jalan.

Tapi gimana kalau aplikasimu bukan cuma satu servis? Gimana kalau kamu punya frontend web, backend API, database PostgreSQL, dan cache Redis? Tiba-tiba, kamu nggak cuma menjalankan satu perintah. Kamu harus nge-juggle empat perintah sekaligus.

Kamu harus buat network secara manual biar mereka bisa saling ngobrol. Kamu harus mastiin nggak sengaja nge-map port host yang sama ke semuanya. Kamu harus hafal perintah docker run yang panjang banget untuk tiap servis, dengan semua environment variable dan volume mount-nya. Kalau mau berbagi setup ini ke anggota tim baru, kamu harus nulis file README.md raksasa yang isinya kayak doa biar mereka nge-copy-paste semuanya dengan benar. Ini resep jitu untuk kekacauan, salah ketik (typo), dan dilema klasik "lho, di mesin gue jalan kok!".

Kekacauan inilah yang coba dijinakkan oleh Docker Compose, yang lahir dari proyek bernama Fig yang diakuisisi Docker pada 2014. Intinya adalah beralih dari mengelola "peliharaan" container satu per satu menjadi mengorkestrasi seluruh "kawanan" aplikasi. Alih-alih mengeluarkan perintah imperatif (jalankan ini, lalu jalankan itu, hubungkan seperti ini...), kamu cukup menulis satu file deklaratif (ini lho tampilan seluruh tumpukan aplikasi saya) dan biarkan Compose menangani detail-detail rumit untuk mewujudkannya.

Cara kerjanya di balik layar

Pada intinya, Docker Compose adalah penerjemah. Ia menerjemahkan file YAML deskriptif menjadi serangkaian panggilan API ke Docker Engine. Ibaratnya, ini prinsip "show, don't tell" dalam manajemen container.

Dari flag docker run ke key YAML

Misalnya, kamu mau menjalankan database PostgreSQL. Perintah docker run-nya mungkin kelihatan kayak sup alfabet dari film hacker:

docker run --name my-postgres-db \
  -e POSTGRES_PASSWORD=supersecret \
  -p 5432:5432 \
  -v pgdata:/var/lib/postgresql/data \
  --restart unless-stopped \
  -d postgres:14

Perintah ini punya nama, environment variable untuk password, port mapping, named volume untuk menyimpan data secara permanen, restart policy, dan berjalan di background (-d).

Sekarang, mari kita lihat padanannya di Docker Compose dalam file docker-compose.yml:

version: '3.8' # Menentukan versi file Compose

services:
  db: # Ini nama yang mudah diingat untuk servis kita
    image: postgres:14
    container_name: my-postgres-db
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: supersecret
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata: # Kita deklarasikan named volume di sini

Lihat persamaannya? Flag-flag command-line tadi berubah menjadi key-key YAML yang rapi dan terorganisir. Ini bukan cuma lebih cantik; ini adalah definisi servis yang bisa dikontrol versinya, bisa dibagikan, dan jauh lebih minim risiko error.

Flag docker run Key docker-compose.yml Fungsinya
postgres:14 (image) image: postgres:14 Menentukan image container yang akan digunakan.
--name my-postgres-db container_name: my-postgres-db Memberikan nama spesifik pada container.
-p 5432:5432 ports: ["5432:5432"] Memetakan (mapping) port dari host ke container.
-v pgdata:/var/lib/... volumes: [pgdata:/var/lib/...] Melakukan mount volume untuk data persisten.
-e VAR=value environment: { VAR: value } Mengatur environment variable di dalam container.
--restart unless-stopped restart: unless-stopped Mendefinisikan restart policy container.

Keajaiban Networking

Di sinilah Compose benar-benar bersinar. Kalau kamu menambahkan servis web app ke file YAML yang sama, seperti ini:

services:
  db:
    # ... (konfigurasi postgres kita dari atas)
  
  api:
    image: my-cool-api:latest
    ports:
      - "8000:8000"
    environment:
      DATABASE_URL: postgresql://user:supersecret@db:5432/mydatabase
    depends_on:
      - db

Saat kamu menjalankan docker-compose up, Compose melakukan sesuatu yang brilian: ia membuat virtual network khusus untuk aplikasimu. Baik container db maupun api terpasang ke network ini.

Sekarang, servis api bisa terhubung ke database menggunakan hostname db—nama yang sama dengan yang kita berikan pada servis di file YAML! Nggak perlu lagi cari-cari alamat IP atau flag --link yang rapuh. Compose menangani semua resolusi DNS di dalam network pribadinya. Beginilah cara container web app kamu bisa membisikkan kata-kata manis (atau, ya tahu lah, query SQL) ke container database-mu dengan aman dan andal.

Siklus Hidup Compose

Perintah docker-compose adalah panel kontrolmu untuk seluruh tumpukan aplikasi.

  • docker-compose up: Ini perintah utamanya. Ia membaca docker-compose.yml-mu, memeriksa keadaan sistemmu, dan melakukan apa pun yang diperlukan agar cocok dengan file tersebut. Ia akan membuat network, membangun image (jika kamu menentukan instruksi build), membuat volume, dan memulai semua container servismu. Jika kamu menjalankannya lagi, ia akan secara cerdas memeriksa perubahan dan hanya membuat ulang container yang perlu diperbarui.
  • docker-compose down: Kebalikan dari up. Perintah ini menghentikan dan menghapus semua container, dan secara default, juga menghapus network yang dibuatnya. Ini tombol "bersihkan kekacauanku". Untuk pembersihan total, docker-compose down -v juga akan menghapus named volume.
  • docker-compose ps: Menunjukkan status semua container yang dikelola oleh file Compose-mu.
  • docker-compose logs -f: Mengikuti (tail) log dari semua servismu dalam satu aliran yang praktis, dengan kode warna berdasarkan servis. Sangat berharga untuk debugging.

Kisah dari Dunia Nyata

Saga "Di Mesin Gue Jalan Kok"

Devon baru saja menyelesaikan fitur baru untuk dasbor analitik perusahaannya, yang menggunakan backend Node.js dan database MongoDB. Semuanya berjalan lancar jaya di laptopnya. Dia nge-push kodenya dan bilang ke anak baru, Sam, untuk nge-pull dan menjalankannya. README buatan Devon punya dua perintah docker run yang super panjang. Sam, namanya juga manusia, salah ketik di path volume database. Aplikasinya jalan, tapi nggak bisa menyimpan apa-apa. Sam buang-buang waktu tiga jam untuk men-debug kode aplikasi, mengira bug-nya ada di sana, sementara Devon ngotot kodenya baik-baik saja. Akhirnya, mereka screen-share dan menemukan typo itu. Semua jadi frustrasi.

Pelajaran yang bisa diambil: Coba mereka pakai docker-compose.yml, proses onboarding cuma butuh satu perintah docker-compose up. Seluruh environment—port, volume, environment variable—bakal identik, menghilangkan semua kelas error setup dan mengubah debugging setengah hari jadi proses startup 30 detik.

Mimpi Buruk Pipeline CI/CD

Sebuah tim DevOps sedang membangun pipeline continuous integration untuk menguji aplikasi microservices mereka. Aplikasi itu punya web server, API gateway, servis user, dan cache Redis. Jenkinsfile mereka adalah skrip shell yang mengerikan, dengan empat panggilan docker run terpisah dan sekumpulan perintah sleep 30 sambil berharap-harap cemas database-nya sudah siap sebelum API mencoba terhubung. Tesnya nggak stabil; kadang lolos, kadang gagal karena sleep-nya kurang lama.

Pelajaran yang bisa diambil: Mereka menulis ulang pipeline-nya pakai Docker Compose. Jenkinsfile-nya disederhanakan menjadi docker-compose -f docker-compose.ci.yml up -d. Mereka menggunakan depends_on dengan condition: service_healthy untuk memastikan API hanya dimulai setelah database lolos health check internalnya. Tes yang nggak stabil itu hilang dalam semalam. Compose menyediakan cara deklaratif yang andal untuk mendefinisikan dan meluncurkan environment pengujian yang persis sama, setiap saat.

Sidecar yang Terlupakan

Seorang developer, Maria, men-deploy aplikasi Python utamanya dalam sebuah container Docker. Beberapa minggu kemudian, manajernya memintanya untuk menambahkan pemantauan performa yang detail. Cara terbaiknya adalah menjalankan Prometheus exporter sebagai "sidecar"—container kedua yang hidup berdampingan dengan aplikasi utama, berbagi network untuk mengambil metrik. Maria menyiapkannya dengan perintah docker run lain. Tapi sekarang dia harus ingat untuk memulai, menghentikan, dan me-restart dua container setiap kali dia membuat perubahan. Suatu hari, dia me-restart aplikasi tapi lupa dengan sidecar-nya, dan mereka kehilangan metrik seharian penuh.

Pelajaran yang bisa diambil: Maria me-refactor setup-nya ke dalam sebuah docker-compose.yml. Dia mendefinisikan aplikasi Python-nya sebagai satu servis dan Prometheus exporter sebagai servis kedua. Sekarang, docker-compose up menghidupkan keduanya, dan docker-compose down mematikan keduanya bersamaan. Mereka dikelola sebagai satu unit logis, sebagaimana mestinya. Compose membuat pola seperti sidecar jadi gampang banget dikelola.

Kesalahan dan Jebakan Umum

  • Menganggap depends_on menunggu kesiapan. Secara default, depends_on hanya menunggu container dependensi untuk mulai, bukan menunggu aplikasi di dalamnya benar-benar terinisialisasi dan siap menerima koneksi. API-mu bisa saja mulai sebelum database-mu siap di-query, yang menyebabkan crash. Solusi sebenarnya adalah menggunakan instruksi healthcheck dalam definisi servis database-mu, lalu gunakan sintaks depends_on bentuk panjang dengan condition: service_healthy.
  • Menyimpan secret ke Git. Sangat menggoda untuk langsung nulis POSTGRES_PASSWORD: my-secret-password di docker-compose.yml. Jangan lakukan itu. Siapa pun yang punya akses ke repository-mu sekarang punya password database-mu. Cara yang benar adalah menggunakan file .env (yang kamu tambahkan ke .gitignore) dan mereferensikan variabel seperti ${POSTGRES_PASSWORD} di file Compose-mu.
  • Tertukar antara bind mount dan named volume. Path yang diawali dengan . atau / (misalnya, ./my-app:/app) adalah bind mount, yang memetakan direktori dari mesin host-mu. Ini bagus untuk development agar perubahan kode langsung terlihat. Path yang hanya diawali dengan nama (misalnya, db-data:/var/lib/mysql) adalah named volume yang dikelola Docker. Ini lebih baik untuk menyimpan data persisten seperti database, karena independen terhadap platform dan dikelola oleh Docker engine. Menggunakan yang salah bisa menyebabkan masalah izin atau data yang tidak se-portabel yang kamu kira.
  • Menggunakannya untuk produksi skala besar. Docker Compose luar biasa untuk development, testing, dan bahkan deployment produksi skala kecil di satu host. Tapi ini BUKAN pengganti orkestrator container penuh seperti Kubernetes atau Docker Swarm. Ia tidak punya konsep bawaan untuk klaster multi-node, self-healing, load balancing antar node, atau rolling update yang canggih. Ketahui batasannya.

Kenapa Ini Harus Kamu Lirik

Kamu harus kepikiran Docker Compose begitu aplikasimu melibatkan lebih dari satu bagian yang bergerak.

  • Kamu sedang membangun aplikasi web dengan database terpisah? Pakai Compose.
  • Kamu perlu menjalankan aplikasi, cache, dan background worker? Pakai Compose.
  • Kamu ingin memberi rekan timmu cara satu perintah untuk menjalankan seluruh stack dev? Pakai Compose.
  • Kamu sedang menyiapkan pipeline CI yang perlu menjalankan environment sementara untuk testing? Pakai Compose.

Ini adalah tool standar industri yang default untuk pengembangan lokal berbasis container. Mempelajarinya adalah langkah selanjutnya yang alami setelah docker run, dan ini adalah gerbang untuk memahami dunia orkestrasi aplikasi yang lebih kompleks. Ia menjembatani kesenjangan antara menjalankan satu container dan menjalankan sistem terdistribusi yang lengkap.

Pelajari Lebih Dalam

Teori beres. Saatnya praktik — 100% di browser kamu.

Coba tool-nya: Docker Run ke Compose