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 .env raksasa untuk semua environment
  • Menyimpan secret production

#4: Gunakan depends_on dengan Benar #

depends_on:
  - db

Catatan penting:

  • depends_on tidak 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.yml
  • Dockerfile.prod terpisah
  • 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.yml
  • docker-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.

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