Skip to main content
BlogDevOps

Docker Compose Watch: Feedback Instan untuk Dev Container Lokal

Docker Compose Watch menyinkronkan kode ke container berjalan dalam milidetik. Begini cara saya mengganti bind mount dengan aturan sync, rebuild, dan sync+restart.

Matthews Wong

Software Engineer

April 20268 menit baca
Docker Compose Watch: Feedback Instan untuk Dev Container Lokal

Foto oleh Florian Olivo

Bertahun-tahun workflow container lokal saya punya pajak di setiap perubahan: edit file, pindah ke terminal, jalankan docker compose up --build, tunggu tiga puluh detik sampai dua menit, lalu cek browser. Kalikan dengan sekitar delapan puluh perubahan yang saya buat dalam satu sore yang fokus, dan saya membuang banyak waktu hanya untuk menunggu rebuild. Docker Compose Watch menghapus pajak itu hampir seluruhnya, dan fiturnya sudah ada di binary Compose yang Anda pakai sekarang.

Jawaban singkat untuk Anda yang sedang mencari: tambahkan blok develop.watch ke compose.yaml, deklarasikan path mana yang harus sync, rebuild, atau sync+restart, lalu jalankan docker compose up --watch. Compose Watch resmi GA di Compose v2.22.0 (dibundel dengan Docker Desktop 4.24), jadi kalau Anda pernah update Docker sejak akhir 2023, fiturnya sudah tersedia. Di artikel ini saya akan membahas cara saya memakainya untuk setup API NestJS plus worker, di mana ia mengalahkan bind mount, dan gotcha yang sempat menggigit saya di proyek nyata.

Kenapa Loop Dev Lokal yang Lama Terasa Lambat

Sebelum Watch, ada dua opsi untuk kode live di dalam container, dan keduanya punya sisi tajam:

  • Rebuild penuh di setiap perubahan. Benar secara teknis tapi sangat lambat, terutama untuk proyek Node di mana npm install mendominasi waktu build meski layer caching sudah bagus.
  • Bind mount direktori source Anda. Cepat, tapi ikut menyeret node_modules milik host, binary spesifik OS, dan file temp editor ke dalam container, menyebabkan drift klasik works-on-my-machine yang justru ingin Anda hindari dengan container.
  • Di macOS dan Windows, bind mount juga membayar penalti translasi filesystem lewat VM, sehingga operasi yang berat file terasa jauh lebih lambat dibanding Linux native.

Compose Watch mengambil jalan ketiga: ia mengamati file di host dan menyalin perubahan satu arah ke container yang sedang berjalan. Image Anda tetap menjadi satu-satunya sumber kebenaran untuk dependency dan library sistem, sementara source code mengalir masuk saat Anda menekan save. Perubahan di sisi container tidak pernah bocor balik ke host, dan itu persis arah trust yang Anda inginkan saat development.

Tiga Action Watch: sync, rebuild, sync+restart

Setiap aturan watch memasangkan sebuah path dengan sebuah action. Memilih action yang tepat per path adalah sumber percepatan sesungguhnya, karena action termurah yang tetap menghasilkan container yang benar adalah pemenangnya.

ActionApa yang dilakukanKapan saya memakainya
syncMenyalin file yang berubah ke container berjalan di path target, tanpa me-restart apa pun.Source code di framework apa pun dengan hot reload: NestJS dengan webpack HMR, Next.js, Vite, script yang diawasi nodemon.
rebuildMembangun ulang image dengan BuildKit dan mengganti container yang berjalan, seperti docker compose up --build untuk service itu.package.json, lockfile, Dockerfile, apa pun yang terpanggang ke dalam layer image. Juga bahasa terkompilasi seperti Go di mana binary adalah artefaknya.
sync+restartMenyalin file yang berubah, lalu me-restart proses container tanpa membangun ulang image.File konfigurasi yang dibaca sekali saat boot: file .env, nginx.conf, ormconfig. Image-nya tidak masalah, prosesnya saja yang perlu start ulang.

compose.yaml Nyata dengan Aturan Watch

Berikut versi ringkas dari setup yang saya jalankan untuk API NestJS plus background worker. Perhatikan bagaimana setiap path mendapat action termurah yang masih layak, dan bagaimana ignore mencegah file test memicu sync yang sia-sia:

# compose.yaml — NestJS API + worker, watch-enabled
services:
  api:
    build: ./api
    ports:
      - "3000:3000"
    develop:
      watch:
        # hot-reload source straight into the container
        - path: ./api/src
          target: /app/src
          action: sync
        # dependency changes need a real rebuild
        - path: ./api/package.json
          action: rebuild
        # config tweak? just restart the process
        - path: ./api/.env.development
          action: sync+restart
          target: /app/.env.development

  worker:
    build: ./worker
    develop:
      watch:
        - path: ./worker/src
          target: /app/src
          action: sync
          ignore:
            - "**/*.spec.ts"

Lalu jalankan semuanya dengan watch aktif:

docker compose up --watch
# or, to run watch without attaching logs:
docker compose watch

Pro tip: tetap pakai docker compose up --watch (satu terminal, log dan watch jadi satu) sampai stack Anda membesar. Dengan lebih dari tiga atau empat service, pisahkan log ke terminal lain dengan docker compose logs -f api supaya notifikasi sync tidak menenggelamkan output aplikasi Anda.

Compose Watch vs Bind Mount: Mana yang Menang

Saya masih sering ditanya kenapa tidak mount saja direktori source dan selesai. Ini perbandingan jujurnya setelah menjalankan kedua pendekatan di proyek klien dan aplikasi saya sendiri yang di-deploy ke VPS:

Compose Watch

Sync satu arah dari host ke container. node_modules tetap milik container, dibangun untuk Linux di dalam image. File temp editor otomatis difilter, dan save beruntun di-debounce menjadi transfer batch. Lingkungan dev sangat dekat dengan perilaku image production.

Bind mount

Dua arah secara default, jadi tulisan dari container mengotori tree di host Anda. node_modules host menutupi milik image kecuali Anda menambah trik anonymous volume. I/O lebih lambat lewat batas VM macOS/Windows. Masih oke untuk eksperimen cepat dan proyek satu service.

Aturan praktis saya: bind mount untuk prototyping sekali pakai, Compose Watch untuk apa pun yang punya Dockerfile dan kelak akan dirilis. Action sync memberi kecepatan feedback selevel bind mount sambil menjaga image sebagai kontrak, dan kontrak itulah yang membuat lompatan dari laptop ke node production Docker Swarm saya terasa membosankan, dan memang itu tujuannya.

Gotcha yang Menghabiskan Satu Sore Saya

  • Watch hanya bekerja pada service yang punya atribut build. Kalau sebuah service hanya punya image, Compose tidak punya apa-apa untuk di-rebuild atau di-sync dan seksi watch-nya diabaikan.
  • Image container butuh binary stat, mkdir, dan rmdir agar sync berfungsi. Distroless dan beberapa image ultra-minimal tidak memilikinya, jadi siapkan varian dev dari Dockerfile Anda berbasis tag slim atau alpine.
  • User container harus bisa menulis ke target sync. Kalau Dockerfile Anda turun ke user non-root (dan memang seharusnya begitu di production), pastikan user itu memiliki direktori target di stage dev Anda, atau sync akan gagal diam-diam.
  • Path di ignore relatif terhadap path yang diawasi, bukan root proyek. Saya sempat kehilangan waktu bertanya-tanya kenapa exclusion dist saya tidak berefek sampai membaca ulang dokumentasinya.

Jangan arahkan action sync ke package.json dengan harapan dependency ikut terinstall. Sync hanya menyalin file; node_modules di container tidak akan berubah. Manifest dependency tempatnya di action rebuild, titik.

Checklist Adopsi: Migrasi Proyek dalam 15 Menit

  1. Jalankan docker compose version dan pastikan Anda di v2.22.0 atau lebih baru; upgrade Docker Desktop atau plugin Compose kalau belum.
  2. Hapus bind mount source code dari file compose Anda, sisakan hanya named volume untuk database dan cache.
  3. Tambahkan blok develop.watch per service: sync untuk source yang bisa hot reload, rebuild untuk manifest dependency dan Dockerfile, sync+restart untuk config yang dibaca saat boot.
  4. Tambahkan entri ignore untuk file test, output build, dan apa pun yang tidak dibutuhkan hot reloader Anda.
  5. Jalankan docker compose up --watch, ubah satu file, dan pastikan Anda melihat notifikasi sync diikuti baris log hot reload dari framework Anda.

Intinya

Compose Watch adalah salah satu fitur quality-of-life yang diam-diam balik modal dalam satu jam pertama. Loop terukur saya di codebase NestJS ukuran menengah turun dari sekitar 45 detik per perubahan dengan rebuild menjadi di bawah dua detik dengan sync plus webpack HMR, dan tidak seperti bind mount, saya tidak menukar fidelitas environment untuk mendapatkannya.

Kalau tim Anda masih rebuild image di setiap save, atau berkelahi dengan hantu node_modules dari bind mount, luangkan lima belas menit itu. Permukaan konfigurasinya cuma tiga action dan satu daftar ignore. Itu saja seluruh fiturnya, dan itu sudah cukup.

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Apa itu Docker Compose Watch dan versi berapa yang memperkenalkannya?

Docker Compose Watch adalah fitur yang mengamati file di host dan menyalin perubahan satu arah ke container yang sedang berjalan tanpa memerlukan rebuild penuh. Fitur ini resmi GA di Compose v2.22.0 yang dibundel dengan Docker Desktop 4.24. Jika Anda pernah update Docker sejak akhir 2023, fiturnya sudah tersedia.

Apa saja tiga action watch dan kapan masing-masing digunakan?

Tiga action-nya adalah sync, rebuild, dan sync+restart. Gunakan sync untuk source code di framework dengan hot reload seperti NestJS dengan webpack HMR, Next.js, Vite, atau nodemon. Gunakan rebuild untuk manifest dependency seperti package.json, lockfile, dan Dockerfile itu sendiri. Gunakan sync+restart untuk file konfigurasi yang dibaca sekali saat boot, seperti file .env atau nginx.conf, di mana image-nya tidak masalah tapi prosesnya perlu start ulang.

Bagaimana perbandingan Compose Watch dengan bind mount untuk development lokal?

Compose Watch melakukan sync satu arah dari host ke container, menjaga node_modules tetap di dalam container yang dibangun untuk Linux, otomatis memfilter file temp editor, dan men-debounce save beruntun menjadi transfer batch. Bind mount bersifat dua arah secara default sehingga tulisan dari container bisa mengotori tree di host dan menyebabkan konflik node_modules kecuali ditambahkan trik anonymous volume. Di macOS dan Windows, bind mount juga membayar penalti translasi filesystem lewat VM yang memperlambat operasi berat file.

Apa saja gotcha yang paling sering ditemui saat menyiapkan Compose Watch?

Watch hanya berlaku untuk service yang memiliki atribut build; service dengan hanya key image akan diabaikan tanpa peringatan. Sync juga membutuhkan binary stat, mkdir, dan rmdir di dalam image container, sehingga image distroless dan ultra-minimal perlu varian dev berbasis tag slim atau alpine. Selain itu, jangan arahkan action sync ke package.json dengan harapan dependency ikut terinstall — sync hanya menyalin file, jadi manifest dependency harus menggunakan action rebuild.

Seberapa jauh peningkatan kecepatan Compose Watch dibanding rebuild di setiap save?

Penulis mengukur loop di codebase NestJS ukuran menengah yang turun dari sekitar 45 detik per perubahan dengan rebuild penuh menjadi di bawah dua detik menggunakan sync dikombinasikan dengan webpack HMR. Tidak seperti bind mount, peningkatan kecepatan ini tidak mengorbankan fidelitas environment, sehingga image development tetap selaras dengan perilaku aplikasi di production.