Docker Compose: Bind mount आणि Named volume मधील फरक
Docker Compose मध्ये Bind mount आणि Named volume कधी वापरावे? डेटा आणि कॉन्फिगरेशनसाठी योग्य पर्याय निवडा. फाईल परमिशनच्या समस्या, बॅकअप आणि मायग्रेशनची संपूर्ण माहिती येथे वाचा.
Bind mount की named volume: थोडक्यात उत्तर
Docker Compose volumes दोन प्रकारचे असतात आणि त्यांची निवड फाईल्सच्या मालकीवर अवलंबून असते. ज्या फाईल्स तुम्ही स्वतः लिहिता किंवा वाचता, उदा. config, templates, static sites, त्यासाठी bind mount वापरा. ज्या डेटाची मालकी ॲप्लिकेशनकडे असते, उदा. database files, search indexes, uploaded media, त्यासाठी named volume वापरा. Bind mount होस्टवरील अशा पाथला निर्देशित करते जो तुम्ही एडिटरमध्ये उघडू शकता. Named volume हे Docker द्वारे तयार केलेले आणि व्यवस्थापित केलेले स्टोरेज असते, ज्यामध्ये तुम्ही Docker च्या माध्यमातून प्रवेश करता.
दोन्ही प्रकार service मधील एकाच volumes: की (key) अंतर्गत येतात, त्यामुळे गोंधळ होऊ शकतो. फरक कोलनच्या (:) डाव्या बाजूला असतो. जर डावी बाजू . किंवा / ने सुरू होत असेल, तर तो होस्ट पाथ आहे, म्हणजेच तो bind mount आहे. इतर कोणतेही नाव असल्यास तो named volume असतो आणि अशा नावाचा उल्लेख टॉप-लेव्हल volumes: ब्लॉक मध्ये करणे आवश्यक असते.
Compose फाईलमधील दोन सिंटॅक्स
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 फाईल असते. myapp नावाची डिरेक्टरी असल्यास myapp_pgdata हे नाव मिळते. हे महत्त्वाचे आहे कारण डिरेक्टरीचे नाव बदलल्यास तुम्हाला एक नवीन रिकामे व्हॉल्यूम मिळते आणि ॲप्लिकेशनचा डेटा गहाळ झाल्यासारखे वाटते. डेटा गहाळ झालेला नसतो: जुने व्हॉल्यूम अजूनही docker volume ls द्वारे सूचीबद्ध असते. जर डिरेक्टरी हलवण्याची शक्यता असेल, तर compose फाईलमध्ये name: वापरून नाव निश्चित करा किंवा COMPOSE_PROJECT_NAME सेट करा. अशा प्रकारच्या सेटिंग्ज तुमच्या इतर Compose environment files and secrets सोबत ठेवल्या पाहिजेत.
परवानगीतील त्रुटी मुख्यतः bind mount मध्येच का दिसतात
हा सर्वात महत्त्वाचा व्यावहारिक फरक आहे. तो मुख्यतः एका नियमामुळे निर्माण होतो: पहिल्यांदा वापरताना रिकामा named volume image मधून भरला जातो; bind mount कधीही अशा प्रकारे भरला जात नाही.
Docker image मध्ये आधीपासून सामग्री असलेल्या directory वर रिकामा named volume mount करते तेव्हा ती सामग्री volume मध्ये कॉपी केली जाते. image ने निश्चित केलेले ownership आणि modes तसेच ठेवले जातात. अधिकृत Postgres image मध्ये /var/lib/postgresql/data त्याच्या स्वतःच्या postgres user च्या मालकीचे असते. त्यामुळे volume त्याच numeric id च्या मालकीचे तयार होते आणि database सुरू होतो.
हे seeding म्हणजे named volume ला मिळणारी एकमेव सुरुवातीची सुविधा आहे. volume कुठे ठेवायचा हे Docker व्यवस्थापित करते; परंतु containers त्यावर नेहमीच्या filesystem operations ने read आणि write करतात. त्यामुळे bind mount प्रमाणेच ownership आणि modes लागू होतात. Image मध्ये नसलेल्या path वर mount केलेल्या named volume ला किंवा वेगळ्या image अथवा user ने प्रथम भरलेल्या volume ला image कडून ownership मिळत नाही. त्यामुळे non-root process ला तिथेही परवानगी नाकारली जाऊ शकते. खालील id तपासणी दोन्ही प्रकारांसाठी काम करते.
bind mount याच्या उलट काम करते. Host वर जे काही आहे तेच container ला दिसते आणि ownership देखील तशीच दिसते. त्या path वरील image मधील सामग्री लपवली जाते. Host directory अस्तित्वात नसेल, तर Docker daemon ती तयार करतो. Daemon root म्हणून चालत असल्याने root:root च्या मालकीची directory तयार होते. त्यानंतर non-root user म्हणून चालणाऱ्या container process ला त्यात write करता येत नाही:
PermissionError: [Errno 13] Permission denied: '/data/app.db'यावरील उपाय म्हणजे numeric ids जुळवणे. bind mount मधील ownership ची तुलना नावाने नव्हे, तर numeric user id ने केली जाते, कारण container चे स्वतःचे /etc/passwd असते. Container मधील app नावाचा user host वर कोणताही अर्थ दर्शवत नाही. Daemon user-namespace remapping सह चालत नसल्यास uid 1000 दोन्ही बाजूंना uid 1000 असतो. हे remapping userns-remap असून ते /etc/docker/daemon.json मध्ये किंवा dockerd command line वर सेट केले जाते. Remapping प्रत्येक container id ला host वरील subordinate range मध्ये हलवते. 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 ./datadocker compose exec web id container process प्रत्यक्षात कोणत्या uid ने चालतो ते दाखवते. Remapping नसल्यास host directory त्या संख्येच्या मालकीची करा किंवा service मध्ये user: "1000:1000" वापरून container ला तुमच्या uid वर चालवा. Remapping सुरू असल्यास user: container ला तुमच्या host number वर pin करू शकत नाही, कारण तुम्ही सेट केलेला id देखील shift होतो. त्यामुळे त्या उदाहरणातील range मध्ये user: "1000:1000" तरीही host uid 232072 वर पोहोचते. त्याऐवजी host directory mapped host id च्या मालकीची करा. तुमची स्वतःची range /etc/subuid आणि /etc/subgid मध्ये आहे. Docker च्या documentation नुसार एका container साठी remapping बंद करण्याचा मार्ग फक्त --userns=host, docker container create, run किंवा exec आहे. स्वतः लिहिलेल्या application साठी user: pin करणे अधिक स्वच्छ पद्धत आहे. स्वतः न लिहिलेल्या image साठी host directory वर chown करणे अधिक सुरक्षित आहे, कारण काही images entrypoint root म्हणून सुरू करतात, privileges कमी करतात आणि खालील विशिष्ट ownership अपेक्षित ठेवतात.
आणखी दोन अडचणी लक्षात ठेवण्यासारख्या आहेत. Fedora, RHEL आणि SELinux (security-enhanced Linux) enforcing असलेल्या इतर systems वर bind mount ला relabel केल्याशिवाय परवानगी नाकारली जाते. त्यामुळे अनेक containers मध्ये share करायच्या path साठी :z किंवा फक्त एका container ने वापरायच्या path साठी :Z जोडा आणि ते - ./data:/data:Z या स्वरूपात लिहा. तसेच directory ऐवजी एकाच file चा bind mount केल्यास editor त्या file मध्ये थेट write न करता ती replace करतो तेव्हा समस्या निर्माण होते, कारण mount मूळ inode शी जोडलेला असतो. Container ला जुनी सामग्रीच दिसत राहते, जोपर्यंत तुम्ही तो restart करत नाही. File वारंवार edit केली जात असल्यास parent directory mount करा.
कार्यक्षमता: जिथे तफावत प्रत्यक्ष जाणवते
Linux सर्व्हरवर दोन्ही प्रकार एकाच कर्नल पाथवरून जातात, त्यामुळे थ्रूपुटमधील फरक इतका कमी असतो की त्या आधारावर निवड करणे आवश्यक नसते. डीफॉल्ट local ड्रायव्हर वापरणारे Named volumes हे Docker च्या उर्वरित फाईलसिस्टमवर, /var/lib/docker/volumes/ अंतर्गत राहतात, तर bind mount तुम्ही निर्देशित केलेल्या ठिकाणी असते.
ही तफावत macOS आणि Windows साठीच्या Docker Desktop वर दिसून येते, जिथे कंटेनर एका व्हर्च्युअल मशीनमध्ये चालतात. तिथे bind mount होस्ट फाईलसिस्टममधून फाईल शेअरिंग लेयरद्वारे व्हर्च्युअल मशीनमध्ये प्रवेश करते. अशा वेळी Node.js डिपेंडन्सी ट्री किंवा PHP फ्रेमवर्क कॅशेसारखी अनेक लहान फाईल ऑपरेशन्स असलेली वर्कलोड्स लक्षणीयरीत्या मंदावतात. Named volumes व्हर्च्युअल मशीनच्या आतच राहतात आणि त्यांना हा फटका बसत नाही. म्हणूनच अनेक डेव्हलपमेंट compose फाईल्स सोर्स डिरेक्टरीला bind-mount करतात, परंतु node_modules वर named volume घोषित करतात.
दुसरा महत्त्वाचा फरक म्हणजे डेटा कुठे साठवला जातो. /mnt/backup वर केलेली bind mount त्या डिस्कवर डेटा ठेवते. Named volume हे /var/lib/docker ज्या फाईलसिस्टमवर आहे तिथे साठवले जाते, जे VPS वर सहसा रूट डिस्क असते. Named volume मध्ये वाढणारा डेटाबेस तुमच्या सिस्टम लॉग्स असलेल्या डिस्कला पूर्णपणे भरू शकतो. कोणतीही समस्या उद्भवण्यापूर्वी ते तपासा:
docker system df -v
df -h /var/lib/dockerdocker system df -v प्रत्येक व्हॉल्यूमची माहिती त्याच्या आकारासह दर्शवते आणि ज्या व्हॉल्यूम्सचा वापर आता कोणताही कंटेनर करत नाही, त्यांना चिन्हांकित करते.
Named volume तपासणे
Named volume हे काही गूढ नसते. Docker ला त्याचा मार्ग (path) विचारा:
docker volume inspect myapp_pgdataMountpoint फील्डमध्ये होस्टवरील प्रत्यक्ष मार्ग मिळतो, जो सामान्यतः /var/lib/docker/volumes/myapp_pgdata/_data असतो. तुम्ही sudo ls वापरून तो वाचू शकता, जे त्वरित तपासणीसाठी उपयुक्त ठरते. या मार्गाचा वापर फाईल्समध्ये बदल करण्यासाठी करू नका. root वापरकर्ता म्हणून तिथे काहीही लिहिल्यास वर नमूद केलेली मालकी हक्काची (ownership) समस्या पुन्हा उद्भवू शकते. तसेच, हा मार्ग केवळ local ड्रायव्हरचा तपशील आहे, जो इतर volume ड्रायव्हर्समध्ये नसतो.
व्हॉल्यूमच्या आत पाहण्याचा सुरक्षित मार्ग म्हणजे एक तात्पुरता (throwaway) कंटेनर वापरणे, जो तो व्हॉल्यूम माउंट करतो:
docker run --rm -v myapp_pgdata:/vol alpine ls -la /volहे कोणत्याही ड्रायव्हरसाठी काम करते, प्रत्यक्ष कंटेनरला दिसणारे परवानग्यांचे नियमच यालाही दिसतात आणि --rm मुळे मागे कोणतीही अनावश्यक फाईल शिल्लक राहत नाही.
प्रत्येक प्रकारचा बॅकअप घेणे
Bind mount ही एक सामान्य डिरेक्टरी असते, त्यामुळे कोणत्याही फाईल-लेव्हल बॅकअप टूलद्वारे ती सहज हाताळता येते. बॅकअप टूलला फक्त होस्ट पाथ (host path) निर्देशित करा आणि तुमचे काम पूर्ण होईल. Named volume साठी एक अतिरिक्त पायरी आवश्यक असते, कारण बॅकअप टूलला त्या व्हॉल्यूमच्या आत प्रवेश करावा लागतो. व्हॉल्यूम आणि एक होस्ट डिरेक्टरी एका अल्पकालीन कंटेनरमध्ये माउंट करा आणि त्यानंतर एक आर्काइव्ह तयार करा:
docker run --rm \
-v myapp_pgdata:/data:ro \
-v "$PWD":/backup \
alpine tar czf /backup/pgdata.tar.gz -C /data .हे उलट क्रियेने (reversing) नवीन व्हॉल्यूममध्ये रिस्टोर करा:
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 /datatar हे कंटेनरमध्ये root म्हणून चालताना numeric ownership जपून ठेवते, ज्यामुळे रिस्टोर केलेला व्हॉल्यूम ॲप्लिकेशनसाठी वापरण्यायोग्य राहतो.
दोन्ही प्रकारांसाठी एक इशारा लागू होतो. डेटाबेस चालू असताना त्याच्या फाईल्स कॉपी केल्यास तुम्हाला एका 'moving target' चे आर्काइव्ह मिळेल, जे रिस्टोर करताना करप्ट (corrupt) होऊ शकते. त्यामुळे आधी सर्व्हिस थांबवा किंवा docker compose exec -T db pg_dump -U postgres appdb > appdb.sql मध्ये दर्शविल्याप्रमाणे डेटाबेसच्या स्वतःच्या टूलचा वापर करून डंप (dump) घ्या. यामुळे एक साधी फाईल तयार होईल, जी तुम्ही तुमच्या compose फाईल्ससोबत 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 मुळे मालकी हक्क (ownership), मोड्स आणि टाइमस्टॅम्प जसेच्या तसे राहतात, त्यामुळे ज्या कंटेनर युजरला जुनी डिरेक्टरी वाचता येत होती, तोच युजर नवीन व्हॉल्यूमही वाचू शकतो. त्यानंतर सर्व्हिसमध्ये बदल करून pgdata:/var/lib/postgresql/data वापरा, टॉप-लेव्हल volumes: ब्लॉक मध्ये pgdata जोडा, docker compose up -d चालवा आणि जुनी डिरेक्टरी हटवण्यापूर्वी ॲप्लिकेशनचे लॉग्स तपासा. उलट प्रक्रियेसाठी याच कमांडमध्ये /from आणि /to ची अदलाबदल करा.
चाचणी करताना एक गोष्ट लक्षात ठेवा. docker compose down मुळे named volumes सुरक्षित राहतात, परंतु docker compose down -v मुळे प्रोजेक्टमध्ये घोषित केलेले सर्व named volumes हटवले जातात आणि ही कृती पूर्ववत करता येत नाही. bind mount दोन्ही प्रक्रियांमध्ये सुरक्षित राहते, कारण ती डिरेक्टरी Docker च्या मालकीची नसते. जर तुम्हाला लाइफसायकल कमांड्स नवीन असतील, तर VPS साठी Docker Compose मूलभूत मार्गदर्शक मध्ये त्या सविस्तर स्पष्ट केल्या आहेत.
सेवेनुसार निवड
ही फाइल कोण लिहिते ते ठरवा. Text editor मध्ये संपादित करून git मध्ये commit केलेली configuration bind mount मध्ये ठेवा आणि ती :ro mount करा, कारण ती दिसणे आणि versioned असणे आवश्यक आहे. हाताने कधीही न उघडलेली application state named volume मध्ये ठेवा, कारण Docker image मधून permissions तयार करते आणि हा data host path वर अवलंबून राहत नाही.
Media हे मिश्र प्रकरण आहे. Photo library application लिहिते, पण तिचे व्यवस्थापन तुम्हीही करता. ती बहुतेकदा विशिष्ट disk वर ठेवण्याइतकी मोठी असते. तिला त्या disk वरील path वर bind mount करा आणि ownership एकदा जाणीवपूर्वक सेट करा. बहुतेक self-hosted stacks शेवटी हीच रचना स्वीकारतात: databases आणि caches साठी named volumes, configuration साठी bind mounts आणि तुम्हाला महत्त्वाच्या असलेल्या मोठ्या directory साठी bind mount. Support desk म्हणून VPS वर चालणारे Chatwoot याच रचनेत बसते: Postgres named volume मध्ये आणि uploaded attachments अशा path वर, ज्याचा backup घेता येतो.
FAQ
bind mount आणि named volume यांच्यात काय फरक आहे?
bind mount host वरील path container मध्ये map करते. त्यामुळे दोन्ही बाजूंना तीच directory दिसते आणि तुम्ही नेहमीच्या tools ने ती edit करू शकता. named volume हे Docker तयार करून व्यवस्थापित करते. त्याचा संदर्भ नावाने घेतला जातो आणि तो top-level volumes: block मध्ये घोषित केला जातो. व्यावहारिक फरक ownership चा आहे: तुम्ही maintain करत असलेल्या configuration साठी bind mounts आणि application maintain करत असलेल्या data साठी named volumes वापरा.
bind mount वापरताना "permission denied" का मिळते, पण named volume वापरताना का मिळत नाही?
रिकामा named volume image मधून भरला जातो. त्यामुळे त्याला सामान्यतः image ने निश्चित केलेले ownership मिळते आणि container user त्यात write करू शकतो. तरीही permissions लागू राहतात. त्या path वर image मध्ये काहीही नसल्यास हीच समस्या named volume मध्येही येऊ शकते. 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" सेट करा. Daemon user-namespace remapping वापरत असल्यास mapped host id वर chown करा, कारण container चे ids host वर shift होतात आणि user: ही बाब बदलत नाही.
Docker named volumes disk वर कुठे साठवते?
Default local driver वापरल्यास ते /var/lib/docker/volumes/<volume>/_data अंतर्गत साठवले जातात आणि docker volume inspect <volume> अचूक Mountpoint दाखवते. काही तपासायचे असल्यास ते वाचा. परंतु त्यावर write फक्त 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 कॉपी करण्याऐवजी database चे स्वतःचे tool वापरून dump घ्या, कारण writes सुरू असताना घेतलेली file copy restore केल्यावर database corrupt स्थितीत येऊ शकतो.
docker compose down माझे volumes delete करते का?
docker compose down containers आणि networks काढते, परंतु named volumes तसेच ठेवते. docker compose down -v project ने घोषित केलेले प्रत्येक named volume देखील delete करते आणि ते कायमचे नष्ट होते. दोन्हीपैकी कोणतीही command bind mounts काढत नाही, कारण ती directory host ची असते, Docker ची नाही.