Best Practice #
Docker Compose sudah menjadi standar de‑facto untuk local development modern. Baik backend, frontend, database, message broker, hingga tool observability kini umum dijalankan bersamaan menggunakan Compose.
Namun, Docker Compose untuk local development memiliki tujuan yang sangat berbeda dengan production. Kesalahan paling umum adalah:
- Menyamakan Compose local dengan Compose production
- Terlalu fokus pada optimasi image size
- Mengorbankan developer experience (DX)
Artikel ini membahas best practice Docker Compose untuk local development secara umum, lintas bahasa dan framework (Go, Java, Node.js, Python, Rust, frontend, dll), dengan fokus pada:
- Kecepatan iterasi developer
- Konsistensi environment
- Kemudahan debugging
- Skalabilitas tim
Prinsip Utama Docker Compose untuk Local Development #
Sebelum masuk ke teknis, pahami dulu prinsip dasarnya:
Local Development ≠ Production #
Tujuan Compose local:
- Cepat dijalankan
- Mudah diubah
- Mudah di-debug
Bukan:
- Image sekecil mungkin
- Security hardening maksimal
- Zero shell access
👉 Optimasi production dilakukan di Dockerfile production, bukan di Compose local.
Source of Truth Ada di Host #
Untuk local dev:
- Kode ditulis di host
- Container hanya runtime
Artinya:
- Gunakan volume mount
- Hindari copy source code berulang
Compose adalah Orchestrator Lokal #
Docker Compose bertugas:
- Menjalankan banyak service
- Mengatur dependency
- Menyediakan network internal
Bukan:
- CI/CD tool
- Production orchestrator
Struktur Dasar docker-compose.yml yang Sehat #
version: "3.9"
services:
app:
build: .
ports:
- "8080:8080"
volumes:
- .:/app
environment:
APP_ENV: local
db:
image: postgres:16
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
Struktur ini sederhana, eksplisit, dan mudah dipahami oleh developer baru.
#1: Gunakan Volume Mount untuk Source Code #
volumes:
- .:/app
Manfaat:
- Edit kode langsung di host
- Tidak perlu rebuild image setiap perubahan
- Cocok dengan hot reload
❌ Anti-pattern:
- COPY source code di Dockerfile untuk local dev
- Rebuild image setiap save file
#2: Pisahkan Dependency Cache dari Source Code #
Untuk bahasa dengan dependency berat (Node, Java, Rust, Python):
volumes:
- node_modules:/app/node_modules
- cargo-registry:/usr/local/cargo/registry
Manfaat:
- Dependency tidak hilang saat container restart
- Build jauh lebih cepat
#3: Gunakan .env File (Tapi Jangan Overkill) #
env_file:
- .env
Gunakan .env untuk:
- Credential lokal
- Konfigurasi non-sensitive
Hindari:
- 1
.envraksasa untuk semua environment - Menyimpan secret production
#4: Gunakan depends_on dengan Benar #
depends_on:
- db
Catatan penting:
depends_ontidak menjamin service siap, hanya urutan start- Untuk database, gunakan retry logic di aplikasi
❌ Jangan mengandalkan sleep di entrypoint.
#5: Gunakan Network Default Compose #
Docker Compose otomatis membuat network:
<project>_default
Manfaat:
- Service saling resolve via nama service
- Tidak perlu expose port internal
Contoh:
DATABASE_URL=postgres://user:pass@db:5432/app
#6: Expose Port Secukupnya #
ports:
- "8080:8080"
Expose hanya:
- Service yang diakses dari host (API, frontend)
Jangan expose:
- Database
- Redis
- Message broker (kecuali perlu debug)
#7: Gunakan Nama Service yang Jelas #
services:
api:
worker:
frontend:
db:
Manfaat:
- Mudah dibaca
- Mudah diskusi antar tim
- Mudah scaling service tertentu
#8: Gunakan Restart Policy dengan Bijak #
Untuk local dev:
restart: unless-stopped
Cocok untuk:
- Database
- Message broker
Hindari restart policy agresif untuk app utama saat debugging.
#9: Gunakan Profiles untuk Opsional Service #
profiles:
- debug
Contoh use case:
- Adminer / pgAdmin
- Mailhog
- Mock service
Menjaga Compose tetap ringan.
#10: Jangan Takut Banyak Service #
Compose local boleh verbose:
- API
- Worker
- Scheduler
- DB
- Cache
- Queue
Lebih baik eksplisit daripada menyembunyikan kompleksitas.
#11: Gunakan .dockerignore Secara Konsisten #
.git
node_modules
target
.env
Tanpa ini:
- Build context besar
- Cache Docker sering invalid
#12: Logging Harus Keluar ke STDOUT #
Untuk local dev:
- Jangan log ke file
- Jangan log rotation
Biarkan Docker menangani log:
docker compose logs -f app
Pola Umum yang Terbukti Efektif #
Dockerfile.dev+docker-compose.ymlDockerfile.prodterpisah- Satu Compose per project
- Dokumentasi singkat di README
Kapan Perlu Lebih dari Satu Compose File? #
Gunakan override saat:
- Compose terlalu besar
- Ada perbedaan OS
- Feature tertentu opsional
Contoh:
docker-compose.ymldocker-compose.debug.yml
Anti-Pattern #
❌ Compose terlalu mirip production ❌ Multi-stage build agresif ❌ Tidak pakai volume ❌ Semua service expose port ❌ Mengandalkan sleep untuk dependency
Penutup #
Docker Compose untuk local development adalah alat produktivitas developer, bukan alat optimasi production.
Best practice utamanya:
- Prioritaskan DX
- Minimalkan friction
- Buat environment konsisten
- Jangan over-engineer
Dengan pendekatan ini, Docker Compose akan terasa ringan, cepat, dan menyenangkan digunakan, bahkan untuk project besar dan tim yang berkembang.