Volume Docker: Data yang Harus Selamat dari Restart

Salah satu kesalahan yang paling sering saya lihat dari developer yang baru pindah ke Docker adalah menganggap container itu seperti server biasa: data disimpan di dalamnya, lalu suatu hari container di-restart atau image di-rebuild, dan data hilang begitu saja. Ini bukan bug Docker, ini memang cara kerjanya secara by design. Filesystem di dalam container bersifat sementara, menempel pada layer container itu sendiri. Begitu container dihapus, layer itu ikut hilang. Untuk data yang harus tetap ada — database, file upload, cache besar — kita butuh mekanisme penyimpanan yang hidup di luar siklus hidup container. Di situlah volume masuk.

Kenapa Filesystem Container Itu Fana

Docker image dibangun dari layer-layer read-only. Saat image dijalankan jadi container, Docker menambahkan satu layer tulis di atasnya (writable layer). Semua perubahan yang terjadi selama container berjalan — file baru, log, data database — masuk ke layer ini. Masalahnya, layer ini terikat ke container, bukan ke image. Kalau kita jalankan docker rm lalu bikin container baru dari image yang sama, kita mulai dari nol lagi. Untuk aplikasi stateless seperti API atau frontend, ini bukan masalah. Tapi untuk apa saja yang menyimpan state — MariaDB, PostgreSQL, storage upload Laravel — kita butuh tempat penyimpanan yang tidak ikut hancur bersama container.

Named Volume: Default yang Paling Aman

Named volume adalah storage yang dikelola sepenuhnya oleh Docker, biasanya hidup di direktori internal Docker di host (di Linux umumnya di bawah /var/lib/docker/volumes). Kita cukup memberinya nama, dan Docker yang urus lokasinya di disk.

services:
  db:
    image: mariadb:11
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:

Kelebihan named volume: performanya baik karena dikelola langsung oleh Docker engine, siklus hidupnya terpisah dari container (volume tetap ada walau container dihapus, kecuali kita eksplisit pakai docker volume rm atau docker compose down -v), dan gampang dipindah lewat docker volume command atau di-backup dengan container bantu yang me-mount volume yang sama. Untuk data database, saya hampir selalu pakai named volume sebagai default. Kita tidak perlu tahu atau peduli struktur file internal MariaDB atau Postgres di disk host — biarkan Docker yang urus.

Bind Mount: Ketika Kita Perlu Kontrol Penuh atas Lokasi

Bind mount berbeda: kita menunjuk langsung path di filesystem host, dan Docker akan me-mount path itu ke dalam container apa adanya.

services:
  app:
    image: php:8.3-fpm
    volumes:
      - ./src:/var/www/html
      - ./storage/logs:/var/www/html/storage/logs

Bind mount paling cocok untuk dua skenario. Pertama, saat development: kita mount source code lokal ke dalam container supaya perubahan kode langsung terlihat tanpa perlu rebuild image, live reload jadi mungkin. Kedua, saat kita memang butuh file di lokasi host yang spesifik dan bisa diakses langsung dari luar Docker — misalnya konfigurasi nginx yang mau diedit manual, atau folder upload yang mau dipantau oleh proses lain di host. Kekurangannya, bind mount membuat container jadi bergantung pada struktur filesystem host, yang menyulitkan portabilitas antar mesin, dan permission antara user di dalam container dengan user host bisa jadi sumber masalah klasik yang sering bikin frustrasi.

Kapan Pakai yang Mana

Aturan praktis yang saya pakai: untuk data stateful yang dikelola sepenuhnya oleh service di dalam container — database, cache persisten, index pencarian — pakai named volume. Untuk source code saat development, atau file yang memang perlu diakses/diedit langsung dari host, pakai bind mount. Untuk data sensitif yang sifatnya sementara dan tidak boleh menyentuh disk sama sekali, misalnya socket atau secret runtime, ada juga opsi tmpfs yang menyimpan data di memori dan otomatis hilang saat container berhenti — jarang dipakai tapi berguna untuk kasus khusus itu.

Satu kebiasaan yang saya sarankan: jangan campur pola bind mount untuk direktori data database di production, karena kita jadi terikat pada permission dan struktur direktori host yang rawan berubah antar mesin atau antar versi OS. Biarkan named volume yang pegang data krusial, dan selalu punya strategi backup terpisah — baik lewat docker volume bantu, maupun dump native dari service database itu sendiri — karena volume yang aman dari restart container tetap bukan pengganti backup.

Takeaway

  • Filesystem container bersifat sementara; apa pun yang harus selamat dari restart wajib dipisah lewat volume.
  • Named volume: default paling aman untuk data stateful seperti database, dikelola penuh oleh Docker.
  • Bind mount: pas untuk development (live source code) atau saat butuh akses langsung dari host.
  • Volume mengamankan data dari siklus hidup container, tapi bukan pengganti backup sungguhan.