Skip to main content
DevOps dari nol · Pelajaran 20 dari 25 · 14 menit

Docker Volume untuk Pemula: Volume, Bind Mount, dan tmpfs

Docker volume untuk pemula: beda volume, bind mount, dan tmpfs, kapan volume baru diisi dari image, siapa pemilik file-nya, dan apa yang dihapus down -v.

Oleh Matthews WongDitinjau pada

Poin utama

Docker volume adalah penyimpanan yang dibuat dan dikelola Docker di luar container mana pun, sehingga datanya tetap ada saat container dihapus. Bind mount justru menampilkan folder dari host, lengkap dengan file dan pemiliknya. tmpfs mount hanya menyimpan file di memori. Tanpa salah satunya, semua tulisan masuk ke writable layer container dan ikut hilang bersamanya.

Setelah pelajaran ini, Anda bisa

  • Memilih named volume, bind mount, atau tmpfs untuk sebuah data, dan menjelaskan kapan masing-masing bertahan atau hilang.
  • Menjelaskan kapan Docker menyalin file dan pemiliknya dari image ke volume baru, dan memperbaiki mount yang tidak bisa ditulis aplikasi non-root.
  • Mem-backup dan me-restore named volume dengan container sekali pakai, dan tahu perintah Compose mana yang menghapusnya.
Lihat cara kerjanya

Ikuti diagramnya langkah demi langkah

Tekan Putar, atau melangkah dengan panah. Setiap langkah juga ditulis di bawah diagram.

Di mana data container disimpan

Tulisan container masuk ke writable layer dan hilang saat deploy membuat ulang container; named volume bertahan lebih lama dari container dan hanya diisi dari image selama masih kosong; bind mount menampilkan folder host dengan pemilik dari host; dan docker compose down -v menghapus volume itu.

Langkah 1 dari 7. Sebuah container yang berjalan sebagai uid 1001, dengan writable layer miliknya sendiri. Di luarnya: image asal container itu, named volume yang dikelola Docker, dan sebuah folder di host.

Tombol: ← → langkah · Home / End · K putar atau jeda

  1. Sebuah container yang berjalan sebagai uid 1001, dengan writable layer miliknya sendiri. Di luarnya: image asal container itu, named volume yang dikelola Docker, dan sebuah folder di host.

  2. Tanpa mount, semua yang ditulis aplikasi masuk ke writable layer container. next/image menyimpan setiap cover yang sudah dioptimasi di .next/cache/images, jadi di situlah cache-nya berada.

    /app/.next/cache/imagesTebak langkah berikutnya Deploy menarik image baru dan membuat ulang container. Apa yang terjadi pada cover yang di-cache di writable layer lama? (Container baru mewarisinya · Ikut terhapus bersama container lama)
  3. docker compose up -d dengan image baru membuat ulang container. Writable layer lama ikut terhapus bersama container lama, jadi setiap cover harus dioptimasi lagi dari awal.

    docker compose up -d
  4. Pasang named volume kosong di sana, dan Docker lebih dulu menyalin isi image di path itu, beserta pemiliknya. Jika image tidak punya folder di sana, volume tetap milik root.

    - next-image-cache:/app/.next/cache/imagesTebak langkah berikutnya Deploy berikutnya membuat ulang container, dan cache-nya kini ada di named volume. Apa yang ditemukan container baru di sana? (Cover yang sama, masih ter-cache · Cache kosong lagi · Salinan baru dari image yang baru)
  5. Volume hidup di luar container mana pun. Compose membuat ulang container, memasang volume yang sama, dan cover yang sudah di-cache masih ada. Tidak ada yang disalin lagi, karena volume-nya tidak kosong.

    docker compose pull && docker compose up -d
  6. Ganti dengan bind mount, dan container melihat folder host apa adanya, termasuk pemiliknya, tanpa ada yang disalin. Folder yang dibuat -v di Linux milik root, jadi uid 1001 tidak bisa menulis.

    - ./cache:/app/.next/cache/images
  7. docker compose down menghapus container dan network, tetapi named volume tetap ada. Tambahkan -v, dan Compose ikut menghapus volume yang dideklarasikan file itu, beserta seluruh isinya.

    docker compose down -v

Apa itu Docker volume?

Docker volume adalah penyimpanan yang dibuat dan dikelola Docker untuk container, di luar container mana pun. Ini penting karena ke mana data pergi kalau tidak ada volume: semua yang ditulis container masuk ke writable layer, yang hanya milik container itu, sulit diambil datanya oleh proses lain, dan menurut dokumentasi Docker tidak bertahan saat container dihapus. Container diganti setiap kali deploy, jadi apa pun yang perlu disimpan harus tinggal di tempat lain.

Baca selengkapnya (2)

Docker menyediakan tiga tempat untuk itu: volume, bind mount, dan tmpfs mount. Data volume berada di direktori penyimpanan milik Docker di host, dan docker volume inspect menunjukkan lokasinya. Isinya hidup di luar siklus hidup container: hapus container-nya, volume tetap ada, bahkan saat tidak ada yang memakainya. Docker menyebut volume sebagai mekanisme yang disarankan untuk menyimpan data yang dibuat dan dipakai container, dan lebih mudah di-backup atau dipindahkan dibanding bind mount.

Named volume punya nama yang Anda pilih, seperti next-image-cache milik situs ini, sehingga setiap container baru bisa memasang volume yang sama. Volume anonim mendapat nama acak; jalankan container-nya dengan --rm, maka Docker menghapus volume anonim itu saat container berhenti.

Apa bedanya dengan bind mount?

Bind mount memasukkan file atau folder dari host ke dalam container. Path-nya Anda tentukan sendiri, dan host serta container membaca dan menulis file yang sama. Itu yang Anda butuhkan untuk source code saat development, dan Docker menyarankan bind mount setiap kali kedua sisi perlu mengakses file-nya. Ini juga berisiko: secara default bind mount punya akses tulis ke file host, jadi tambahkan ro kalau container cukup membaca saja.

Baca selengkapnya (1)

Bind mount membawa folder host apa adanya, termasuk pemilik dan permission-nya. Jika path di host belum ada, -v membuatnya, selalu sebagai folder, sedangkan --mount berhenti dengan error; Compose juga membuatnya kecuali create_host_path dimatikan. Dalam uji coba di Docker Engine 29.8.1 untuk Linux, folder yang dibuat -v dimiliki root dengan mode 755, dan proses yang berjalan sebagai uid 1001 mendapat Permission denied. Di Docker Desktop untuk Mac, dengan folder yang dibagikan dari macOS, penulisan yang sama berhasil, jadi coba kasus ini di mesin Linux.

Apa yang terjadi saat mount menimpa file yang sudah ada di image?

Pasang mount apa pun di atas folder yang sudah diisi image, maka file image di sana tersembunyi selama mount itu ada. Bind mount selalu menyembunyikannya, begitu juga volume yang sudah berisi file. Dokumentasi Docker menambahkan bahwa tidak ada cara mudah untuk memunculkan kembali file yang tersembunyi; buat ulang container tanpa mount itu.

Baca selengkapnya (2)

Pengecualiannya adalah volume kosong, termasuk setiap volume yang baru dibuat. Secara default Docker lebih dulu menyalin file yang sudah ada di folder itu ke dalamnya, yang oleh dokumentasinya disebut cara yang baik untuk mengisi data di awal. Referensi Dockerfile menyatakan hal yang sama untuk VOLUME: docker run mengisi volume baru dengan apa pun yang ada di lokasi itu di dalam image. Opsi volume-nocopy, atau nocopy di Compose, mematikan penyalinan ini, dan bind mount tidak pernah diisi dengan cara ini.

Pemilik file ikut tersalin. Dokumentasi Docker tidak menuliskannya secara eksplisit, jadi hal ini diuji di Docker Engine 29.8.1: volume baru yang dipasang di folder milik uid 1001 di dalam image langsung dimiliki uid 1001. Dipasang di path yang tidak ada di image, volume sejenis justru dimiliki root, dan uid 1001 tidak bisa menulis ke sana. Penyalinan juga hanya terjadi selama volume masih kosong: volume yang sudah berisi tetap menyimpan file dan pemiliknya, walaupun image baru datang.

Kapan tmpfs jadi pilihan yang tepat?

tmpfs mount bersifat sementara dan hanya hidup di memori host. Saat container berhenti, mount itu dihapus beserta file-nya, dan container tidak bisa berbagi satu tmpfs. Docker mendokumentasikannya untuk Docker di Linux; Docker Desktop menjalankan container di VM Linux, dan di sanalah langkah coba sendiri di bawah mengujinya.

Baca selengkapnya (1)

Pakai untuk file sementara yang tidak perlu ada di disk. Dua batasannya menurut dokumentasi Docker: yang Anda tulis di sana dihitung ke batas memori container, dan kernel tetap bisa memindahkannya ke swap di disk. Dengan --mount tanpa ukuran, tmpfs bisa tumbuh sampai separuh RAM host.

Kenapa situs ini menyimpan cache gambarnya di named volume?

next/image mengoptimasi setiap cover saat pertama kali diminta, lalu menyimpan hasilnya di folder cache/images di direktori build Next.js, di sini .next/cache/images. Tanpa mount, folder itu berada di writable layer, dan setiap deploy menjalankan docker compose up -d dengan image baru, yang menghentikan lalu membuat ulang container. Referensi Docker menyebut recreate itu mempertahankan volume yang terpasang, jadi named volume membawa cache dari satu container ke container berikutnya.

Baca selengkapnya (1)

Komentar di file compose juga menjelaskan kenapa bukan bind mount: folder host yang dibuat Docker akan dimiliki root, sedangkan named volume akan mewarisi pemilik uid 1001 dari image. Kedua aturan itu benar, tetapi yang kedua butuh folder di path itu di dalam image, dan stage runner tidak membuatnya: stage itu hanya menyalin output standalone Next, yang tidak punya folder cache, dan file static. Dengan kondisi file saat ini, volume itu kemungkinan besar dimulai dalam keadaan milik root, sama seperti temuan pelajaran 5. Perbaikannya satu baris RUN di runner, sebelum USER nextjs, yang membuat .next/cache/images dan menyerahkannya ke nextjs.

Apa yang menghapus volume?

Menghapus container tidak pernah menghapus named volume; Docker menyimpannya sampai Anda sendiri yang menghapus. docker compose down menghapus container dan network project, dan membiarkan named volume, bahkan volume anonim, tetap ada. docker compose down -v juga menghapus named volume yang dideklarasikan di bagian volumes file itu serta volume anonim yang terpasang di container-nya. Volume bertanda external tidak pernah dihapus. Deploy situs ini menjalankan docker compose pull lalu up -d, tidak pernah down -v, jadi volume cache-nya bertahan melewati setiap rilis.

Baca selengkapnya (1)

docker volume rm dan docker volume prune menghapus volume secara langsung; pelajaran 15 membahas flag prune mana yang ikut menyentuh named volume.

Bagaimana cara mem-backup named volume?

Dengan container sekali pakai. Resep Docker menjalankan container dengan --rm yang memasang volume dan sebuah folder host, menjalankan tar untuk menulis arsip ke folder host itu, lalu selesai; restore adalah kebalikannya, ke volume baru. Contoh di dokumentasi Docker menjangkau volume lewat --volumes-from; memasangnya lewat nama, seperti di langkah coba sendiri di bawah, bekerja sama saja.

Baca selengkapnya (1)

Arsip tar hanya sekonsisten file-nya saat dibaca tar. Dokumentasi PostgreSQL menyatakan backup level file system mengharuskan server dimatikan, karena tar tidak mengambil snapshot atomik; untuk database, hentikan dulu atau pakai tool dump miliknya. Volume situs ini hanya berisi cache yang bisa dibuat ulang, jadi tidak perlu di-backup sama sekali.

Cara situs ini melakukannya

Konfigurasi nyata di balik pelajaran ini

Kutipan dari repositori yang membangun dan men-deploy situs ini, apa adanya.

docker-compose.yml:14-23
    volumes:
      # Persist next/image's optimised-variant cache across deploys.
      # next.config.ts sets minimumCacheTTL to a year, but the cache lived in the
      # container's writable layer and every deploy replaces the container — so
      # the first request for each cover after a deploy paid a full JPEG decode
      # plus an AVIF encode again, on 1 vCPU under a 512 MB cap. A named volume
      # rather than a bind mount, so Docker seeds its ownership from the image's
      # uid 1001 (Dockerfile:35) instead of creating a root-owned host dir the
      # container cannot write to.
      - next-image-cache:/app/.next/cache/images

Komentar ini memuat kedua alasan desainnya. Deploy mengganti container, dan Compose mempertahankan volume yang terpasang saat membuat ulang container, jadi cache-nya bertahan. Bagian soal pemilik hanya berlaku jika image punya folder di /app/.next/cache/images untuk disalin Docker, dan tidak ada yang membuatnya di stage runner. Rujukan barisnya juga sudah bergeser: user uid 1001 sekarang dibuat di baris 63 Dockerfile.

docker-compose.yml:49-50
volumes:
  next-image-cache:

Entri di level atas ini mendeklarasikan volume tanpa opsi, jadi Docker membuatnya dengan pengaturan default engine saat docker compose up pertama kali berjalan, lalu memakainya ulang setelah itu. Compose menambahkan nama project sebagai awalan, karena itu docker volume ls menampilkan nama yang lebih panjang daripada di file. Volume ini hanya terhapus jika sengaja dihapus, atau lewat docker compose down -v.

Dockerfile:66-67
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

Dua baris ini menyerahkan server standalone, folder .next-nya, dan file static kepada uid 1001. Output standalone Next tidak punya folder cache, seperti yang terlihat di build lokal, jadi image tidak punya apa pun di .next/cache/images untuk disalin Docker ke volume baru. Membuat folder itu di runner, dengan pemilik nextjs, adalah langkah yang diandaikan oleh komentar compose.

Yang sering rusak

Kesalahan yang benar-benar membuang waktu

  • Permission denied di volume atau bind mount baru

    Aplikasi berjalan sebagai user non-root, sedangkan mount point-nya milik root: folder host yang dibuat -v, atau volume baru di path yang tidak pernah ada di image. Buat folder itu di Dockerfile dan serahkan ke user aplikasi sebelum USER, atau chown folder host ke uid aplikasi. Periksa dengan stat di dalam container: pemiliknya berupa angka, dan 0 berarti root.

  • Database kosong setelah docker compose down -v

    -v terlihat seperti flag untuk bersih-bersih, padahal flag itu menghapus named volume yang dideklarasikan file, beserta datanya, bukan hanya container. Pakai down biasa untuk menghentikan project. Kalau memang ingin menghapus volume, backup dulu dengan container sekali pakai.

  • Bind mount menyembunyikan isi image

    Pasang folder host di atas path yang sudah diisi image, misalnya kode aplikasi itu sendiri atau folder html milik nginx, maka file-file itu hilang di dalam container karena tertutup mount. Pasang di path terpisah, atau pakai named volume, yang saat masih kosong akan diisi dari image.

  • Image baru, volume lama

    Docker hanya menyalin file image ke volume yang masih kosong. Kirim file default baru lewat image baru, maka volume yang sudah ada tetap menyimpan file lama, karena isinya menutupi isi image. Jauhkan file default dari path yang di-mount, atau perbarui isi volume sendiri.

Named volume, bind mount, atau tmpfs: di mana data disimpan dan apa yang bisa dilewatinya, sesuai dokumentasi Docker.
Named volumeArea penyimpanan Docker di host, dikelola DockerTetap ada sampai Anda menghapusnya atau menjalankan down -vJika kosong, berisi salinan folder image di path ituData aplikasi, database, cache yang harus bertahan antar deploy
Bind mountPath host yang Anda pilihTetap ada: itu folder milik hostFolder host apa adanya, menutupi file imageSource code saat development, file konfigurasi yang diedit di host
tmpfsMemori hostHilang: dihapus saat container berhentiFolder kosongFile sementara yang tidak perlu ada di disk
Coba sendiri

Lakukan di komputer Anda sendiri

Anda butuh Docker di laptop dan terminal (macOS, Linux, atau WSL). Semua langkah berjalan di satu folder kosong, semua nama diawali demo-, dan langkah terakhir menghapus semuanya.

  1. Buat folder kerja, buat named volume, lalu inspect. Mountpoint adalah path di area penyimpanan milik Docker; di Docker Desktop path itu ada di dalam VM Linux-nya, bukan di disk laptop Anda.

    mkdir demo-volumes && cd demo-volumes
    docker volume create demo-data
    docker volume inspect demo-data
  2. Tulis file dari satu container sekali pakai, lalu baca dari container lain. Container pertama sudah tidak ada; file-nya masih ada dan mencetak hello.

    docker run --rm -v demo-data:/data alpine:3 sh -c 'echo hello > /data/note.txt'
    docker run --rm -v demo-data:/data alpine:3 cat /data/note.txt
  3. Pasang volume baru di atas folder html milik nginx, lalu folder host kosong di path yang sama. Volume menampilkan 50x.html dan index.html, hasil salinan dari image; bind mount tidak menampilkan apa-apa, karena menutupinya.

    docker run --rm -v demo-html:/usr/share/nginx/html nginx:alpine ls /usr/share/nginx/html
    mkdir site
    docker run --rm -v "$PWD/site":/usr/share/nginx/html nginx:alpine ls /usr/share/nginx/html
  4. Pemilik file ikut tersalin. node:22-alpine punya user node, uid 1000, pemilik /home/node, jadi volume baru di sana mencetak 1000. Di path yang tidak ada di image, volume mencetak 0, yaitu root, dan user node mendapat Permission denied.

    docker run --rm -v demo-home:/home/node node:22-alpine stat -c '%u %n' /home/node
    docker run --rm -u node -v demo-missing:/home/node/cache node:22-alpine \
      sh -c 'stat -c "%u %n" /home/node/cache; touch /home/node/cache/x'
  5. tmpfs mount hidup di memori: df menampilkan tmpfs sebagai filesystem-nya, dan tidak ada yang ditulis di sana bertahan setelah container selesai.

    docker run --rm --tmpfs /scratch alpine:3 df -h /scratch
  6. Backup volume dengan container sekali pakai yang menulis arsip tar ke folder ini, lalu restore ke volume baru dan baca lagi file-nya.

    docker run --rm -v demo-data:/data:ro -v "$PWD":/backup alpine:3 tar czf /backup/demo-data.tgz -C /data .
    docker volume create demo-restored
    docker run --rm -v demo-restored:/data -v "$PWD":/backup alpine:3 tar xzf /backup/demo-data.tgz -C /data
    docker run --rm -v demo-restored:/data alpine:3 cat /data/note.txt
  7. Sekarang dengan Compose: satu service dan satu named volume. Tulis file, paksa container yang benar-benar baru, lalu baca file-nya lagi. docker compose ps -q mencetak ID container yang berbeda di kali kedua; file-nya tetap berisi kept.

    printf 'services:\n  app:\n    image: nginx:alpine\n    volumes:\n      - data:/data\nvolumes:\n  data:\n' > compose.yaml
    docker compose up -d
    docker compose exec app sh -c 'echo kept > /data/note.txt'
    docker compose ps -q
    docker compose up -d --force-recreate
    docker compose ps -q
    docker compose exec app cat /data/note.txt
  8. docker compose down membiarkan volume-nya, yang tercantum sebagai demo-volumes_data, jadi file-nya selamat saat up lagi. down -v menghapusnya, dan daftar terakhir kembali kosong.

    docker compose down
    docker volume ls --filter name=demo-volumes
    docker compose up -d
    docker compose exec app cat /data/note.txt
    docker compose down -v
    docker volume ls --filter name=demo-volumes
  9. Bersihkan volume dan folder-nya.

    docker volume rm demo-data demo-html demo-home demo-missing demo-restored
    cd .. && rm -rf demo-volumes
Kuis singkat

Tiga pertanyaan sebelum lanjut

Pilih jawaban untuk melihat kenapa benar atau salah. Tidak ada nilai, jadi tebak saja dengan bebas; jawaban yang salah disimpan di browser ini agar kursus bisa menanyakannya lagi nanti.

  1. 1.Sebuah service Postgres menyimpan datanya di named volume. Anda menjalankan docker compose down, lalu docker compose up -d. Apa yang terjadi pada datanya?
  2. 2.Sebuah named volume baru dipasang di /app/uploads, path yang tidak ada di image. Aplikasi berjalan sebagai uid 1001. Apa yang terjadi saat aplikasi menulis ke sana?
  3. 3.Anda melakukan bind mount folder host yang kosong ke /usr/share/nginx/html di image nginx. Apa isi folder itu di dalam container?
Dari pelajaran sebelumnya

Dua pertanyaan dari pelajaran sebelumnya

Mengingat kembali pelajaran lama setelah jeda membuatnya lebih melekat. Jawab dari ingatan sebelum mencari apa pun.

  1. 1.Service Anda tidak menjalankan task di node C. Sebuah klien terhubung ke node C di port yang dipublikasikan. Apa yang terjadi?
  2. 2.Anda mengubah A record dengan TTL 3600. Dua puluh menit kemudian rekan Anda masih mendapat alamat lama. Apa yang terjadi?

Dari: 19. Belajar Docker Swarm: Service, Routing Mesh, dan Rolling Update · 17. Jenis DNS Record dan Fungsinya: A, CNAME, MX, TXT, dan TTL

Pikirkan dulu

Jawab dalam hati, lalu cek

  1. 1.Kenapa cache gambar situs ini butuh volume?Lihat jawabannya

    Jawaban:Setiap deploy membuat ulang container, dan writable layer ikut terhapus bersama container lama. Named volume hidup di luar container, jadi Compose memasang volume yang sama ke setiap container baru.

  2. 2.Kapan Docker menyalin file image ke volume, dan kapan tidak?Lihat jawabannya

    Jawaban:Hanya saat volume masih kosong ketika dipasang dan image punya isi di path itu. Volume yang sudah berisi tetap menyimpan isinya, ada image baru atau tidak, dan bind mount tidak pernah diisi.

  3. 3.Perintah mana yang menghapus named volume milik project Compose?Lihat jawabannya

    Jawaban:docker compose down -v, docker volume rm, dan volume prune dengan flag yang ikut menyasar named volume. down biasa, recreate, dan menghapus container sama sekali tidak menyentuh named volume.

Pelajari lebih dalam

Bahasan mendalam terkait di situs ini