Docker Compose menjalankan beberapa container sekaligus dari satu file YAML. Tiap container disebut service, dan satu perintah, docker compose up, menyalakan semuanya dengan pengaturan yang sama setiap kali. Bayangin partitur orkestra: semua pemain, alat musiknya, dan siapa masuk setelah siapa ditulis di satu kertas, lalu dirigen memberi satu aba-aba. Tapi pemain biola yang sudah duduk belum tentu sudah selesai menyetem. Ingat bagian ini, karena di situ bug paling sering di Compose.
🧪 Tebakan cepat: service
apppunyadepends_on: - db. Apakah Compose menunggu Postgres siap menerima koneksi sebelum menyalakanapp? Tebak dulu, jawabannya ada di bagian "depends_on belum berarti siap".
Dari tiga docker run jadi satu file
catatan-api butuh tiga container: app Node-nya, Postgres untuk menyimpan catatan, dan Redis untuk cache daftar catatan. Dengan docker run, kamu harus membuat network, volume, lalu tiga perintah panjang, dengan urutan yang benar, setiap kali. Dengan Compose, semuanya ditulis sekali di docker-compose.yml (nama compose.yaml juga diterima) di folder project:
services:
app:
build: .
env_file: .env
ports:
- "3000:3000"
depends_on:
- db
- redis
db:
image: postgres:16
environment:
POSTGRES_USER: catatan
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
db-data:
services:berisi tiga service:app,db,redis. Nama service sekaligus jadi nama host: dari dalamapp, database dicapai didb:5432(detailnya di lesson Docker Networking).build: .membangun image dari Dockerfile di folder ini.image:memakai image jadi dari registry.env_file: .envmengisi environment variable app dari file.env, misalnyaDATABASE_URL=postgres://catatan:...@db:5432/catatan.${DB_PASSWORD}diambil Compose dari file yang sama.ports:sama dengan-pdidocker run: port 3000 laptop ke port 3000 container.volumes:menyimpan data Postgres di named volumedb-data, supaya gak hilang saat container dihapus (lesson Docker Volumes).depends_on:mengatur urutan:dbdanredisdinyalakan sebelumapp.
Perintah sehari-hari
docker compose up -d # build kalau perlu, buat network, lalu nyalakan semua di background
docker compose ps -a # status semua container, termasuk yang sudah keluar
docker compose logs -f app # ikuti log service app
docker compose up -d --build # build ulang image app setelah kodenya berubah
docker compose down # hentikan dan hapus container serta network
docker compose down -v # sama, ditambah hapus volume: data database ikut hilang
-d(detach): jalan di background, terminalmu bebas lagi.downmenyisakan volume, jadi catatan di database masih ada saatupberikutnya.down -vmenghapus volume juga.- Compose memberi awalan nama folder (nama project) ke semuanya: container
catatan-api-db-1, networkcatatan-api_default, volumecatatan-api_db-data.
depends_on belum berarti siap
Saat nyala, catatan-api langsung menyambung ke database untuk menjalankan migration, dan kalau gagal, dia keluar dengan exit code 1. Ini yang terjadi di up pertama, persis seperti di Lab:
| Detik | db | app |
|---|---|---|
| 0,0 | container start, Postgres mulai menyiapkan database baru | menunggu |
| 0,7 | masih menyiapkan | container start (depends_on terpenuhi) |
| 1,0 | belum mendengarkan port 5432 | menyambung, ditolak, exit 1 |
| 5,2 | siap menerima koneksi | sudah mati |
app-1 | Gagal konek ke database: connect ECONNREFUSED 172.18.0.2:5432
Jadi jawabannya: gak. depends_on biasa cuma menunggu container db start, bukan Postgres di dalamnya siap. Itu jawaban tebakannya. Dan karena ini balapan waktu, kadang lolos (database-nya kebetulan sudah ada dan cepat siap), kadang gagal, yang bikin bug ini licin.
Obatnya: beri db sebuah healthcheck, perintah yang dijalankan Docker berulang kali untuk mengecek apakah service sehat, lalu suruh app menunggu status sehat itu:
app:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
healthcheck:
test: ["CMD", "pg_isready", "-h", "localhost", "-U", "catatan"]
interval: 2s
timeout: 3s
retries: 15
pg_isreadyberhasil begitu Postgres menerima koneksi.-h localhostmemaksa lewat TCP, seperti app.- Docker menjalankannya tiap 2 detik. Status
dbberubah daristartingjadihealthydi cek pertama yang berhasil (detik 6,0 diuppertama). condition: service_healthymembuat Compose menungguhealthydulu, baru menyalakanapp. Outputup -dmenulisHealthydi barisdb.
Membaca daftar service
Latihan lesson ini memakai format yang disederhanakan: tiap service ditulis sebagai beberapa baris kunci: nilai, dan antar service dipisah satu baris kosong:
service: app
image: node:20
port: 3000
service: db
image: postgres:16
port: 5432
Nama service ada di baris yang diawali service: . Potong teksnya per baris dengan split("\n"), ambil baris yang startsWith("service: "), lalu buang awalan itu: hasilnya ["app", "db"], sesuai urutan di file.
⚠️ Jebakan yang sering ketemu
- Mengira
depends_onmenunggu database siap. Tanpa healthcheck dancondition: service_healthy, app bisa menyambung sebelum Postgres siap dan langsung crash. docker compose psgak menampilkan app. App yang crash sudah keluar;pscuma menampilkan yang jalan. Pakaips -a, lalulogs app.- Lupa
--build.up -dmemakai image app yang sudah ada. Setelah kode berubah, jalankanup -d --build. down -vdi server. Satu-vmenghapus volume database. Di laptop berguna untuk mulai dari nol, di production menghapus data pengguna.
TL;DR: Docker Compose menulis semua service (app, db, redis) di docker-compose.yml dan menyalakannya dengan satu perintah. docker compose up -d jalan di background, ps -a melihat semua container termasuk yang keluar, logs -f app membaca log, up -d --build membangun ulang image, down menghapus container dan network, down -v juga menghapus volume beserta datanya. Nama service jadi nama host (db:5432). depends_on biasa cuma menunggu container start; supaya app menunggu database benar-benar siap, beri db healthcheck (pg_isready) dan tulis condition: service_healthy di depends_on app.