SSD Nodes Learn Hosting plans →
गाइड Matt Connorलेखक: Matt Connor · अपडेट किया गया: 2026-10-28

Docker Compose में Bind mount बनाम Named volume का चुनाव

Docker Compose में Bind mount और Named volume के बीच सही विकल्प कैसे चुनें। कॉन्फ़िगरेशन, डेटा स्टोरेज, फाइल परमिशन की समस्याओं और बैकअप लेने के तरीकों के बारे में विस्तार से जानें।

Bind mount या named volume: संक्षिप्त उत्तर

Docker Compose volumes दो प्रकार के होते हैं, और इनका चयन इस आधार पर किया जाता है कि फाइलों का स्वामी कौन है। जिन फाइलों को आप स्वयं लिखते और पढ़ते हैं, उनके लिए bind mount का उपयोग करें, जैसे कि config, templates, और static sites। जिन डेटा का स्वामी application स्वयं है, उनके लिए named volume का उपयोग करें, जैसे कि database files, search indexes, और uploaded media। Bind mount host पर एक ऐसे path की ओर संकेत करता है जिसे आप किसी editor में खोल सकते हैं। Named volume वह storage है जिसे Docker आपके लिए बनाता और ट्रैक करता है, और आप इसे Docker के माध्यम से एक्सेस करते हैं।

दोनों ही एक service के भीतर समान volumes: key के अंतर्गत दिखाई देते हैं, यही कारण है कि इनमें भ्रम होता है। अंतर colon के बाईं ओर है। यदि बाईं ओर . या / से शुरू होता है, तो यह एक host path है, इसलिए यह एक bind mount है। इसके अलावा कुछ भी एक नाम है, इसलिए यह एक named volume है, और उस नाम को top-level volumes: block में घोषित किया जाना अनिवार्य है।

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:

pgdata:/var/lib/postgresql/data एक named volume है। ./nginx.conf:/etc/nginx/nginx.conf एक bind mount है, और :ro इसे read-only मोड में माउंट करता है, जो उन कॉन्फ़िगरेशन के लिए सही डिफ़ॉल्ट है जिन्हें कंटेनर द्वारा कभी भी ओवरराइट नहीं किया जाना चाहिए। यदि आप टॉप-लेवल volumes: एंट्री को हटा देते हैं, तो Compose service "db" refers to undefined volume pgdata एरर के साथ रुक जाएगा।

इसे शुरू करें और देखें कि Docker ने क्या बनाया है:

docker compose up -d
docker volume ls

वॉल्यूम का नाम pgdata नहीं है। इसका नाम <project>_pgdata है, जहाँ प्रोजेक्ट का नाम डिफ़ॉल्ट रूप से उस डायरेक्टरी के नाम पर आधारित होता है जिसमें compose file मौजूद है। myapp नामक डायरेक्टरी का परिणाम myapp_pgdata होता है। यह महत्वपूर्ण है क्योंकि डायरेक्टरी का नाम बदलने पर आपको एक नया खाली वॉल्यूम मिल जाएगा, और ऐसा लगेगा कि एप्लिकेशन का डेटा खो गया है। डेटा खोया नहीं है: पुराना वॉल्यूम अभी भी docker volume ls द्वारा लिस्ट किया जाता है। यदि डायरेक्टरी के स्थान बदलने की संभावना हो, तो compose file में name: के साथ नाम को पिन करें, या COMPOSE_PROJECT_NAME सेट करें। इस तरह की सेटिंग्स आपकी अन्य Compose environment files and secrets के साथ होनी चाहिए।

permission errors अक्सर bind mounts को क्यों प्रभावित करते हैं

यह सबसे बड़ा व्यावहारिक अंतर है, और यह मुख्य रूप से एक नियम से आता है: एक named volume जो पहली बार उपयोग किए जाने पर खाली होता है, उसे image से seed किया जाता है, जबकि bind mount कभी भी ऐसा नहीं होता है।

जब Docker किसी ऐसी directory पर एक खाली named volume mount करता है जिसमें image के भीतर पहले से content मौजूद है, तो यह उस content को volume में copy कर देता है, और वही ownership और modes लागू करता है जो image ने सेट किए थे। आधिकारिक Postgres image /var/lib/postgresql/data को अपने स्वयं के postgres user के स्वामित्व में रखती है, इसलिए volume का स्वामित्व भी उसी numeric id के पास होता है, और database start हो जाता है।

वह seeding ही एकमात्र शुरुआती लाभ है जो एक named volume को मिलता है। Docker यह प्रबंधित करता है कि volume कहाँ स्थित है, लेकिन containers इसे सामान्य filesystem operations के साथ read और write करते हैं, इसलिए ownership और modes वैसे ही लागू होते हैं जैसे वे bind mount पर होते हैं। एक named volume जिसे ऐसे path पर mount किया गया है जो image में मौजूद नहीं है, या जिसे पहली बार किसी अलग image या user द्वारा भरा गया है, उसे image से कोई ownership नहीं मिलती है, और वहाँ एक non-root process को भी access से मना किया जा सकता है। नीचे दिया गया id check दोनों प्रकार के लिए काम करता है।

एक bind mount इसके विपरीत काम करता है। host पर जो कुछ भी है, container वही देखता है, जिसमें ownership भी शामिल है, और उस path पर मौजूद image content छिप जाता है। यदि host directory मौजूद नहीं है, तो Docker daemon उसे बना देता है, और daemon root के रूप में चलता है, इसलिए आपको root:root के स्वामित्व वाली एक directory मिलती है। एक non-root user के रूप में चलने वाला container process फिर इसमें write नहीं कर सकता है:

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

इसका समाधान यह है कि numbers को मेल खाया जाए। bind mount पर ownership की तुलना numeric user id द्वारा की जाती है, नाम से नहीं, क्योंकि container का अपना /etc/passwd होता है। container के अंदर app नामक user का host पर कोई अर्थ नहीं है। Uid 1000 का अर्थ दोनों तरफ uid 1000 है, जब तक कि daemon user-namespace remapping (userns-remap, जिसे /etc/docker/daemon.json में या dockerd command line पर सेट किया जाता है) के साथ न चले। Remapping हर container id को host पर एक subordinate range में shift कर देती है। 231072 से शुरू होने वाली Docker की उदाहरण range में, container uid 0 host uid 231072 है, इसलिए container uid 1000 host uid 232072 है।

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

docker compose exec web id उस uid को print करता है जिसके रूप में container process वास्तव में चलता है। Remapping के बिना, host directory को उस number से मिलाएँ, या service में user: "1000:1000" के साथ container को अपने number पर pin करें। Remapping चालू होने पर, user: container को आपके host number पर pin नहीं कर सकता है, क्योंकि आपके द्वारा सेट किया गया id भी shift हो जाता है: उस उदाहरण range में user: "1000:1000" अभी भी host uid 232072 पर ही आता है। इसके बजाय host directory को mapped host id पर chown करें (आपकी अपनी range /etc/subuid और /etc/subgid में है)। Docker का documentation केवल एक single container के लिए remapping को बंद करने के तरीके के रूप में docker container create, run या exec पर --userns=host का उल्लेख करता है। आपके द्वारा लिखे गए application के लिए user: को pin करना अधिक साफ-सुथरा है। आपके द्वारा न लिखी गई image के लिए host directory को chown करना अधिक सुरक्षित है, क्योंकि कुछ images root के रूप में entrypoint शुरू करती हैं, privileges छोड़ती हैं, और नीचे विशिष्ट ownership की अपेक्षा करती हैं।

दो और traps हैं जिन्हें जानना उपयोगी है। Fedora, RHEL और SELinux (security-enhanced Linux) लागू करने वाले अन्य systems पर, एक bind mount को तब तक मना कर दिया जाता है जब तक कि उसे relabel न किया जाए, इसलिए containers के बीच साझा किए गए path के लिए :z जोड़ें या केवल एक container द्वारा उपयोग किए जाने वाले path के लिए :Z जोड़ें, जिसे - ./data:/data:Z के रूप में लिखा जाता है। और एक directory के बजाय एक single file का bind mount तब टूट जाता है जब कोई editor file को place में write करने के बजाय उसे replace कर देता है, क्योंकि mount original inode का अनुसरण करता है। जब तक आप इसे restart नहीं करते, container पुराना content ही देखता रहता है। जब file को अक्सर edit किया जाता है तो parent directory को mount करें।

प्रदर्शन: जहाँ अंतर वास्तविक है

Linux सर्वर पर दोनों प्रकार के वॉल्यूम एक ही kernel path से होकर गुजरते हैं, इसलिए throughput में अंतर इतना कम होता है कि आपको इस आधार पर चुनाव नहीं करना चाहिए। डिफ़ॉल्ट local ड्राइवर का उपयोग करने वाले named volumes Docker के बाकी हिस्सों की तरह ही /var/lib/docker/volumes/ के अंतर्गत उसी filesystem पर रहते हैं, और bind mount वहीं रहता है जहाँ आपने उसे point किया है।

यह अंतर macOS और Windows के लिए Docker Desktop पर दिखाई देता है, जहाँ containers एक virtual machine के अंदर चलते हैं। वहाँ एक bind mount host filesystem से उस virtual machine में एक file sharing layer के माध्यम से जाता है, और बहुत सारी छोटी file operations वाले workloads, जैसे कि Node.js dependency tree या PHP framework cache, काफी धीमे हो जाते हैं। Named volumes virtual machine के अंदर ही रहते हैं और उन्हें यह लागत नहीं चुकानी पड़ती। यही कारण है कि बहुत सारी development compose files source directory को bind-mount करती हैं लेकिन node_modules पर एक named volume घोषित करती हैं।

दूसरा वास्तविक अंतर यह है कि bytes कहाँ स्टोर होते हैं। /mnt/backup पर एक bind mount डेटा को उस डिस्क पर रखता है। एक named volume उस filesystem पर जाता है जो /var/lib/docker को होल्ड करता है, जो VPS पर आमतौर पर root disk होती है। एक named volume के अंदर बढ़ती हुई database उसी डिस्क को भर देती है जिस पर आपके system logs होते हैं। इसे किसी incident के बनने से पहले जाँच लें:

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

docker system df -v हर वॉल्यूम को उसके आकार के साथ सूचीबद्ध करता है, और उन वॉल्यूम को चिह्नित करता है जिन्हें अब कोई container refer नहीं करता है।

Named volume का निरीक्षण करना

Named volume कोई black box नहीं है। Docker से पूछें कि यह कहाँ स्थित है:

docker volume inspect myapp_pgdata

Mountpoint field एक वास्तविक host path प्रदान करता है, जो सामान्यतः /var/lib/docker/volumes/myapp_pgdata/_data होता है। आप इसे sudo ls के साथ पढ़ सकते हैं, और यह त्वरित जाँच के लिए उपयोगी है। इसे फाइलें संपादित करने के स्थान के रूप में न देखें। वहाँ root के रूप में लिखने से ऊपर वर्णित ownership की समस्या फिर से उत्पन्न हो जाती है, और यह path local driver का एक विवरण है जिसे अन्य volume drivers साझा नहीं करते हैं।

इसके अंदर देखने का सुरक्षित तरीका एक throwaway container का उपयोग करना है जो उस volume को mount करता है:

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

यह किसी भी driver के लिए काम करता है, वही permissions देखता है जो वास्तविक container देखता है, और --rm के कारण पीछे कुछ भी नहीं छोड़ता है।

प्रत्येक प्रकार का बैकअप लेना

Bind mount एक सामान्य directory होती है, इसलिए कोई भी file-level backup tool इसे आसानी से संभाल लेता है। बैकअप को host path पर निर्देशित करें और आपका काम हो गया। Named volume के लिए एक अतिरिक्त चरण की आवश्यकता होती है, क्योंकि tool को इसके अंदर जाना पड़ता है। Volume और एक host directory को एक अल्पकालिक container में mount करें, फिर एक archive लिखें:

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

इसे एक नए volume में reverse करके restore करें:

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

tar container के अंदर root के रूप में चलने पर numeric ownership को सुरक्षित रखता है, जिससे restore किया गया volume application द्वारा उपयोग करने योग्य बना रहता है।

एक चेतावनी दोनों प्रकारों पर लागू होती है। Database के चलते समय उसकी files को copy करने से आपको एक moving target का archive मिलता है, और यह restore होने पर corrupt स्थिति में हो सकता है। पहले service को रोकें, या docker compose exec -T db pg_dump -U postgres appdb > appdb.sql के अनुसार database के अपने tool के माध्यम से dump करें। इससे एक plain file बनती है जिसे आप अपनी compose files के साथ encrypted restic backup routine में शामिल कर सकते हैं।

Bind mount को named volume पर माइग्रेट करना

यह प्रक्रिया एक कॉपी है, न कि रीनेम, और इसमें लगभग एक मिनट का समय लगता है।

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/'

cp -a ओनरशिप, मोड और टाइमस्टैम्प को सुरक्षित रखता है, इसलिए जिस कंटेनर यूजर के पास पुरानी डायरेक्टरी को पढ़ने की अनुमति थी, वह नई वॉल्यूम को भी पढ़ पाएगा। इसके बाद सर्विस को pgdata:/var/lib/postgresql/data का उपयोग करने के लिए बदलें, टॉप-लेवल volumes: ब्लॉक में pgdata जोड़ें, docker compose up -d चलाएं, और पुरानी डायरेक्टरी को डिलीट करने से पहले एप्लिकेशन के लॉग्स की जाँच करें। विपरीत दिशा में जाने के लिए समान कमांड का उपयोग करें, जिसमें /from और /to को आपस में बदल दिया जाता है।

टेस्टिंग के दौरान एक बात का ध्यान रखें। docker compose down named volumes को प्रभावित नहीं करता है, लेकिन docker compose down -v प्रोजेक्ट द्वारा घोषित हर named volume को डिलीट कर देता है, और इसे वापस ठीक करने का कोई विकल्प नहीं है। Bind mount दोनों स्थितियों में सुरक्षित रहता है, क्योंकि Docker उस डायरेक्टरी का स्वामी नहीं होता है। यदि आप लाइफसाइकिल कमांड्स के लिए नए हैं, तो VPS के लिए Docker Compose बेसिक्स गाइड में इनका विस्तार से वर्णन किया गया है।

सेवा-दर-सेवा चयन

यह तय करें कि फ़ाइल कौन लिखता है। जिस कॉन्फ़िगरेशन को आप टेक्स्ट एडिटर में संपादित करते हैं और git में कमिट करते हैं, उसे bind mount में रखें, जिसे :ro पर माउंट किया गया है, क्योंकि आप इसे दृश्यमान और वर्शन्ड रखना चाहते हैं। एप्लिकेशन स्टेट जिसे आप कभी भी मैन्युअल रूप से नहीं खोलते हैं, उसे named volume में रखा जाना चाहिए, क्योंकि Docker इमेज से अनुमतियों (permissions) को सीड करता है और डेटा किसी होस्ट पाथ पर निर्भर नहीं करता है।

मिश्रित स्थिति मीडिया की है। फोटो लाइब्रेरी को एप्लिकेशन द्वारा लिखा जाता है, लेकिन आप इसे प्रबंधित भी करते हैं, और यह अक्सर इतना बड़ा होता है कि इसके लिए एक विशिष्ट डिस्क की आवश्यकता होती है। इसे उस डिस्क के एक पाथ पर bind mount करें, और एक बार जानबूझकर स्वामित्व (ownership) सेट करें। अधिकांश self-hosted स्टैक इसी पैटर्न का पालन करते हैं: डेटाबेस और कैश के लिए named volumes, और कॉन्फ़िगरेशन तथा आपके द्वारा उपयोग की जाने वाली बड़ी डायरेक्टरी के लिए bind mounts। VPS पर चल रहा Chatwoot जैसा सपोर्ट डेस्क बिल्कुल इसी स्थिति में आता है, जहाँ Postgres एक named volume में होता है और अपलोड की गई अटैचमेंट एक ऐसे पाथ पर होती हैं जिसे आप बैकअप के लिए पॉइंट कर सकते हैं।

FAQ

Bind mount और named volume में क्या अंतर है?

Bind mount host के एक path को container के अंदर map करता है, जिससे दोनों तरफ एक ही directory दिखाई देती है और आप सामान्य tools से उसे edit कर सकते हैं। Named volume वह storage है जिसे Docker बनाता और manage करता है, जिसे नाम से पहचाना जाता है और top-level volumes: block में घोषित किया जाता है। व्यावहारिक अंतर स्वामित्व (ownership) का है: bind mounts उन config के लिए हैं जिन्हें आप maintain करते हैं, और named volumes उन data के लिए हैं जिन्हें application maintain करती है।

मुझे bind mount के साथ "permission denied" क्यों मिलता है, जबकि named volume के साथ नहीं?

एक खाली named volume image से seed होता है, इसलिए यह आमतौर पर image द्वारा निर्धारित स्वामित्व को inherit करता है और container user इसमें लिख सकता है। यह अभी भी permissions लागू करता है, इसलिए यदि image में उस path पर कुछ न हो तो यह उसी तरह fail हो सकता है। Bind mount host directory को बिल्कुल वैसा ही दिखाता है जैसी वह है, और यदि Docker को वह directory बनानी पड़ी, तो उसने उसे root के स्वामित्व में रखा होगा। Container द्वारा उपयोग की जाने वाली numeric id देखने के लिए docker compose exec <service> id चलाएँ, फिर host directory पर sudo chown -R <uid>:<gid> करें, या, जब daemon user namespaces को remap न कर रहा हो, तो service पर user: "1000:1000" set करें। यदि daemon user-namespace remapping का उपयोग करता है, तो इसके बजाय mapped host id पर chown करें, क्योंकि container की ids host पर shift हो जाती हैं और user: उसे नहीं बदलता है।

Docker named volumes को disk पर कहाँ store करता है?

Default local driver के साथ वे /var/lib/docker/volumes/<volume>/_data के अंतर्गत रहते हैं, और docker volume inspect <volume> सटीक Mountpoint को print करता है। यदि आपको कुछ जाँचने की आवश्यकता हो तो इसे पढ़ें, लेकिन इसमें केवल container के माध्यम से ही लिखें, क्योंकि host पर root के रूप में edit करने से स्वामित्व (ownership) उन तरीकों से बदल जाता है जिनकी container अपेक्षा नहीं करता है।

मैं named volume का backup कैसे लूँ?

Volume और एक host directory दोनों को mount करके एक short-lived container चलाएँ, फिर docker run --rm -v myvol:/data:ro -v "$PWD":/backup alpine tar czf /backup/myvol.tar.gz -C /data . के साथ एक से दूसरे में archive करें। Database के लिए, live files को copy करने के बजाय database के अपने tool से dump करें, क्योंकि writes के दौरान ली गई file copy restore होने पर corrupt स्थिति में हो सकती है।

क्या docker compose down मेरे volumes को delete कर देता है?

docker compose down containers और networks को हटा देता है और named volumes को वहीं रहने देता है। docker compose down -v project द्वारा घोषित प्रत्येक named volume को भी स्थायी रूप से delete कर देता है। इन दोनों commands द्वारा bind mounts को नहीं हटाया जाता है, क्योंकि वह directory host की होती है, न कि Docker की।

क्या यह लेख उपयोगी था?