SSD Nodes Learn Hosting plans →
Mga Gabay Matt ConnorNi Matt Connor · Na-update 2026-08-30

Docker Compose: Bind Mount o Named Volume?

Alamin kung bind mount o named volume ang para sa config at data, pati file permission traps at mga hakbang sa pag-inspect, backup, at migration.

Bind mount o named volume: ang maikling sagot

May dalawang uri ng volume sa Docker Compose, at nakabatay ang pagpili sa kung sino ang may kontrol sa mga file. Gumamit ng bind mount para sa mga file na ikaw mismo ang sumusulat at nagbabasa, gaya ng config, template, at static site. Gumamit ng named volume para sa data na pagmamay-ari ng application, gaya ng mga database file, search index, at uploaded media. Tumutukoy ang bind mount sa isang path sa host na maaari mong buksan sa isang editor. Ang named volume ay storage na ginagawa at sinusubaybayan ng Docker para sa iyo, at ina-access mo ito sa pamamagitan ng Docker.

Pareho silang lumalabas sa ilalim ng iisang volumes: key sa loob ng isang service, kaya madalas silang napagkakamalan. Ang pinagkaiba ay ang nasa kaliwang bahagi ng colon. Kapag nagsisimula sa . o / ang kaliwang bahagi, host path ito, kaya bind mount ito. Anumang iba pa ay isang pangalan, kaya named volume ito, at dapat ding ideklara ang pangalang iyon sa top-level na volumes: block.

Ang dalawang syntax sa compose file

services:
  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: changeme
    volumes:
      - pgdata:/var/lib/postgresql/data
  web:
    image: nginx:1.27
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./site:/usr/share/nginx/html:ro

volumes:
  pgdata:

Ang pgdata:/var/lib/postgresql/data ay named volume. Ang ./nginx.conf:/etc/nginx/nginx.conf ay bind mount, at ang :ro ay nagmo-mount nito bilang read-only. Ito ang tamang default para sa configuration na hindi dapat kailanman baguhin ng container. Kapag nakalimutan ang top-level na volumes: entry, hihinto ang Compose at magpapakita ng service "db" refers to undefined volume pgdata.

I-start ito at ilista ang ginawa ng Docker:

docker compose up -d
docker volume ls

Hindi pgdata ang pangalan ng volume. <project>_pgdata ang pangalan nito, kung saan ang project name ay nagde-default sa pangalan ng directory na naglalaman ng compose file. Ang directory na may pangalang myapp ay magbibigay ng myapp_pgdata. Mahalaga ito dahil kapag pinalitan ang pangalan ng directory, magkakaroon ka ng bagong bakanteng volume, at magmumukhang nawala ang data ng application. Hindi ito nawala: nakalista pa rin ang lumang volume sa docker volume ls. Itakda ang pangalan gamit ang name: sa compose file, o itakda ang COMPOSE_PROJECT_NAME kung maaaring ilipat ang directory. Ang mga setting na gaya nito ay dapat ilagay kasama ng iba mo pang Compose environment files at secrets.

Bakit permission errors ay karaniwang nangyayari sa bind mounts

Ito ang pinakamalaking praktikal na pagkakaiba, at nagmumula ito sa isang panuntunan: ang named volume na walang laman sa unang paggamit ay sine-seed mula sa image, samantalang hindi ito ginagawa ng bind mount.

Kapag nag-mount ang Docker ng walang-lamang named volume sa isang directory na may laman na sa image, kinokopya nito ang laman sa volume, kasama ang ownership at modes na itinakda ng image. Ang official Postgres image ay naglalabas ng /var/lib/postgresql/data na pagmamay-ari ng sarili nitong postgres user, kaya ang volume ay nagiging pagmamay-ari ng kaparehong numeric id, at nagsisimula ang database.

Kabaligtaran ang ginagawa ng bind mount. Anuman ang nasa host ang nakikita ng container, kasama ang ownership, at natatago ang image content sa path na iyon. Kung hindi umiiral ang host directory, ginagawa ito ng Docker daemon, at tumatakbo ang daemon bilang root, kaya nagkakaroon ka ng directory na pagmamay-ari ng root:root. Hindi ito maisusulatan ng container process na tumatakbo bilang non-root user:

PermissionError: [Errno 13] Permission denied: '/data/app.db'

Ang ayos ay pag-isahin ang mga numero. Ang ownership sa bind mount ay ikinukumpara batay sa numeric user id, hindi sa pangalan, dahil may sarili itong /etc/passwd ang container. Walang kabuluhan sa host ang user na tinatawag na app sa loob ng container. Ang uid 1000 ay uid 1000 sa magkabilang panig.

id -u
mkdir -p ./data
docker compose exec web id
sudo chown -R 1000:1000 ./data

Ipinapakita ng docker compose exec web id ang uid kung saan aktuwal na tumatakbo ang container process. Itugma ang host directory sa numerong iyon, o itakda ang container na gamitin ang iyong numero sa pamamagitan ng user: "1000:1000" sa service. Mas malinis gamitin ang user: para sa application na ikaw mismo ang sumulat. Mas ligtas namang i-chown ang host directory para sa image na hindi ikaw ang sumulat, dahil may ilang image na nagsisimula ng entrypoint bilang root, nagda-drop ng privileges, at umaasa sa partikular na ownership sa loob nito.

May dalawa pang dapat bantayan. Sa Fedora, RHEL, at iba pang system na naka-enforce ang SELinux (security-enhanced Linux), dini-deny ang bind mount hanggang ma-relabel ito. Kaya idagdag ang :z para sa path na ibinabahagi ng mga container, o :Z para sa path na isang container lamang ang dapat gumamit, na isinusulat bilang - ./data:/data:Z. Bukod dito, nagkakaproblema ang bind mount ng isang file, sa halip na directory, kapag pinapalitan ng editor ang file sa halip na sumulat dito nang hindi pinapalitan ang file. Sinusundan kasi ng mount ang orihinal na inode. Patuloy na nakikita ng container ang lumang content hanggang i-restart mo ito. I-mount ang parent directory kapag madalas i-edit ang file.

Performance: kung saan talaga may pagkakaiba

Sa Linux server, dumadaan ang parehong uri sa iisang kernel path. Maliit lang ang pagkakaiba sa throughput. Huwag itong gawing batayan sa pagpili. Ang named volumes na gumagamit ng default na local driver ay nasa parehong filesystem ng iba pang bahagi ng Docker, sa ilalim ng /var/lib/docker/volumes/. Ang bind mount naman ay nasa lokasyong itinuro mo.

Lumilitaw ang pagkakaiba sa Docker Desktop para sa macOS at Windows, kung saan tumatakbo ang mga container sa loob ng virtual machine. Sa ganitong setup, dumadaan ang bind mount mula sa host filesystem papunta sa virtual machine sa pamamagitan ng file sharing layer. Dahil dito, kapansin-pansing bumabagal ang mga workload na maraming maliliit na file operation, gaya ng dependency tree ng Node.js o cache ng PHP framework. Nananatili sa loob ng virtual machine ang named volumes at hindi nila binabayaran ang ganitong overhead. Ito ang dahilan kung bakit maraming development compose file ang nagbi-bind-mount ng source directory ngunit nagde-declare ng named volume sa ibabaw ng node_modules.

Ang isa pang tunay na pagkakaiba ay kung saan napupunta ang bytes. Kapag nag-bind mount ka sa /mnt/backup, sa disk na iyon mapupunta ang data. Ang named volume ay mapupunta sa filesystem na naglalaman ng /var/lib/docker, na karaniwang nasa root disk sa isang VPS. Kapag lumaki ang database sa loob ng named volume, mapupuno nito ang disk na ginagamit din ng system logs. Suriin ito bago ito maging insidente:

docker system df -v
df -h /var/lib/docker

Inililista ng docker system df -v ang lahat ng volume kasama ang laki ng mga ito at minamarkahan ang mga volume na hindi na ginagamit ng anumang container.

Pagsusuri sa named volume

Ang named volume ay hindi black box. Itanong sa Docker kung saan ito matatagpuan:

docker volume inspect myapp_pgdata

Ibinibigay ng Mountpoint field ang aktuwal na host path, karaniwang /var/lib/docker/volumes/myapp_pgdata/_data. Mababasa mo ito gamit ang sudo ls, at kapaki-pakinabang ito para sa mabilisang pagsusuri. Huwag itong ituring na lugar kung saan dapat mag-edit ng mga file. Kapag sumulat ka roon bilang root, mauulit ang problema sa ownership na inilarawan sa itaas. Ang path ay detalye ng local driver, at hindi ito ibinabahagi ng ibang volume driver.

Ang ligtas na paraan upang tingnan ang laman nito ay gumamit ng throwaway container na nagmo-mount sa volume:

docker run --rm -v myapp_pgdata:/vol alpine ls -la /vol

Gumagana ito sa anumang driver, nakikita nito ang parehong permissions na nakikita ng aktuwal na container, at walang naiiwan dahil sa --rm.

Pagba-backup ng bawat uri

Ordinaryong directory ang bind mount, kaya awtomatiko itong nahahawakan ng anumang file-level backup tool. Ituro ang backup sa host path at tapos na. May isang dagdag na hakbang para sa named volume dahil kailangang makapasok dito ang tool. I-mount ang volume at isang host directory sa parehong short-lived container, saka gumawa ng archive:

docker run --rm \
  -v myapp_pgdata:/data:ro \
  -v "$PWD":/backup \
  alpine tar czf /backup/pgdata.tar.gz -C /data .

I-restore ito sa pamamagitan ng pagbabaligtad ng proseso papunta sa bagong volume:

docker volume create myapp_pgdata_restored
docker run --rm \
  -v myapp_pgdata_restored:/data \
  -v "$PWD":/backup \
  alpine tar xzf /backup/pgdata.tar.gz -C /data

Pinapanatili ng tar ang numeric ownership kapag tumatakbo ito bilang root sa loob ng container. Ito ang dahilan kung bakit magagamit ng application ang ni-restore na volume.

May isang babala para sa parehong uri. Kapag kinopya ang mga file ng database habang tumatakbo ito, archive ito ng patuloy na nagbabagong data at maaaring ma-restore sa corrupt na estado. Ihinto muna ang service, o gumamit ng dump sa pamamagitan ng sariling tool ng database, gaya ng nasa docker compose exec -T db pg_dump -U postgres appdb > appdb.sql. Gumagawa ito ng plain file na maaari mong isama sa isang karaniwang naka-encrypt na restic backup routine kasama ng iyong compose files.

Paglipat ng bind mount sa named volume

Ang paglipat ay pagkopya, hindi pagpapalit ng pangalan, at tumatagal ito nang humigit-kumulang isang minuto.

docker compose down
docker volume create myapp_pgdata
docker run --rm \
  -v "$PWD/data":/from \
  -v myapp_pgdata:/to \
  alpine sh -c 'cp -a /from/. /to/'

Pinapanatili ng cp -a ang ownership, modes, at timestamps. Dahil dito, mababasa pa rin ng container user na nakabasa sa dating directory ang bagong volume. Pagkatapos, baguhin ang service upang gamitin ang pgdata:/var/lib/postgresql/data, idagdag ang pgdata sa top-level na volumes: block, patakbuhin ang docker compose up -d, at basahin ang logs ng application bago mo burahin ang dating directory. Sa kabilang direksiyon, gamitin ang parehong command at pagpalitin ang /from at /to.

Tandaan ang isang bagay habang nagsusuri ka. Hindi ginalaw ng docker compose down ang named volumes, pero binubura ng docker compose down -v ang lahat ng named volume na dineklara ng project, at hindi na ito maa-undo. Nananatili ang bind mount sa parehong operasyon dahil hindi kailanman pagmamay-ari ng Docker ang directory na iyon. Kung bago pa sa iyo ang lifecycle commands, ipinapaliwanag ng gabay sa mga pangunahing kaalaman sa Docker Compose para sa VPS ang paggamit ng mga ito.

Pagpili, bawat serbisyo

Tukuyin kung sino ang sumusulat sa file. Ang configuration na ine-edit mo sa text editor at kino-commit sa git ay dapat nasa bind mount na naka-mount sa :ro, dahil kailangan itong makita at ma-version. Ang application state na hindi mo mano-manong binubuksan ay dapat nasa named volume, dahil maayos na ise-set ng Docker ang permissions at hindi nakadepende ang data sa host path.

Ang mixed case ay media. Isinusulat ng application ang photo library, pero ikaw din ang namamahala rito, at madalas ay sapat itong kalaki para mangailangan ng partikular na disk. I-bind mount ito sa isang path sa disk na iyon, at sadyang itakda ang ownership nang isang beses. Ito ang pattern na karaniwang ginagamit ng mga self-hosted stack: named volumes para sa mga database at cache, at bind mounts para sa configuration at sa malaking directory na mahalaga sa iyo. Eksaktong ganito ang support desk na Chatwoot na tumatakbo sa isang VPS, kung saan nasa named volume ang Postgres at nasa path na maaaring ituro sa backup ang mga uploaded attachment.

FAQ

Ano ang pagkakaiba ng bind mount at named volume?

Ang bind mount ay nagmamapa ng path sa host papunta sa container, kaya parehong nakikita ng dalawang panig ang iisang directory at maaari mo itong i-edit gamit ang mga karaniwang tool. Ang named volume ay storage na nililikha at mina-manage ng Docker, tinutukoy ayon sa pangalan at dine-declare sa top-level volumes: block. Ang praktikal na pagkakaiba ay nasa ownership: gamitin ang bind mounts para sa configuration na ikaw ang nagme-maintain, at ang named volumes para sa data na application ang nagme-maintain.

Bakit nakakakuha ako ng "permission denied" sa bind mount pero hindi sa named volume?

Ang empty named volume ay sine-seed mula sa image, kaya minamana nito ang ownership na itinakda ng image at maaaring sulatan ito ng container user. Eksaktong ipinapakita ng bind mount ang host directory, at kung kailangang likhain ng Docker ang directory na iyon, ginawa niya itong pag-aari ng root. Patakbuhin ang docker compose exec <service> id upang makita ang numeric id na ginagamit ng container, saka ang sudo chown -R <uid>:<gid> para sa host directory, o itakda ang user: "1000:1000" sa service.

Saan ini-store ng Docker ang named volumes sa disk?

Gamit ang default na local driver, nasa ilalim ang mga ito ng /var/lib/docker/volumes/<volume>/_data, at ipinapakita ng docker volume inspect <volume> ang eksaktong Mountpoint. Basahin ito kung kailangan mong magsuri, pero sumulat dito sa pamamagitan lamang ng container, dahil ang pag-edit bilang root sa host ay nagbabago ng ownership sa paraang hindi inaasahan ng container.

Paano ako magba-back up ng named volume?

Magpatakbo ng short-lived container na parehong may naka-mount na volume at host directory, saka i-archive ang data mula sa isa papunta sa isa gamit ang docker run --rm -v myvol:/data:ro -v "$PWD":/backup alpine tar czf /backup/myvol.tar.gz -C /data .. Para sa database, gamitin ang sariling tool ng database upang mag-dump sa halip na kopyahin ang live files, dahil ang file copy na ginawa habang may kasabay na writes ay maaaring ma-restore sa corrupt na estado.

Binubura ba ng docker compose down ang mga volume ko?

Inaalis ng docker compose down ang mga container at network at iniiwan ang named volumes. Binubura rin ng docker compose down -v ang bawat named volume na dine-declare ng project, at permanente ang pagbabagong ito. Hindi kailanman inaalis ng alinmang command ang bind mounts, dahil pag-aari ng host ang directory na iyon at hindi ng Docker.