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 membacadocker-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 instruksibuild), 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 dariup. 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 -vjuga 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_onmenunggu kesiapan. Secara default,depends_onhanya 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 instruksihealthcheckdalam definisi servis database-mu, lalu gunakan sintaksdepends_onbentuk panjang dengancondition: service_healthy. - Menyimpan secret ke Git. Sangat menggoda untuk langsung nulis
POSTGRES_PASSWORD: my-secret-passworddidocker-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
- Docker Docs: Compose file version 3 reference - Spesifikasi resmi dan sumber kebenaran untuk semua key dan sintaks yang tersedia.
- Docker Docs: Overview of Docker Compose - Pengenalan tingkat tinggi dari para pembuatnya langsung.
- YAML Spec - Karena semua file
docker-compose.ymladalah YAML, memahami sintaksnya (map, list, anchor) bisa sangat membantu. - Awesome Docker - Daftar sumber daya Docker pilihan, banyak di antaranya berisi tutorial dan contoh file
docker-compose.ymluntuk berbagai stack.