Docker Compose: Bind mount vs Named volume வேறுபாடுகள்
Docker Compose-ல் Bind mount மற்றும் Named volume எப்போது பயன்படுத்த வேண்டும்? கோப்பு அனுமதி சிக்கல்கள், தரவு மேலாண்மை மற்றும் பேக்கப் எடுக்கும் முறைகளை விரிவாக அறியுங்கள்.
Bind mount அல்லது named volume: சுருக்கமான பதில்
Docker Compose volumes இரண்டு வகைகளாக உள்ளன. கோப்புகளை யார் நிர்வகிக்கிறார்கள் என்பதே இதற்கான தேர்வு. நீங்கள் நேரடியாகப் படிக்கும் அல்லது எழுதும் கோப்புகளுக்கு (உதாரணமாக: config, templates, static sites) bind mount-ஐப் பயன்படுத்தவும். பயன்பாடு (application) சொந்தமாக உருவாக்கும் தரவுகளுக்கு (உதாரணமாக: database files, search indexes, uploaded media) named volume-ஐப் பயன்படுத்தவும். Bind mount என்பது host-ல் உள்ள ஒரு பாதையைக் குறிக்கும், அதை நீங்கள் ஒரு editor மூலம் திறக்க முடியும். Named volume என்பது Docker-ஆல் உருவாக்கப்பட்டு நிர்வகிக்கப்படும் சேமிப்பகம், இதை நீங்கள் Docker மூலமாகவே அணுக முடியும்.
இரண்டுமே ஒரு service-க்குள் ஒரே volumes: key-ன் கீழ் வருவதால், குழப்பம் ஏற்பட வாய்ப்புள்ளது. இவற்றிற்கு இடையிலான வேறுபாடு colon-க்கு இடதுபுறம் உள்ள பகுதியில் உள்ளது. இடதுபுறம் . அல்லது / என்று தொடங்கினால் அது host path, அதாவது அது ஒரு bind mount. மற்றவை அனைத்தும் ஒரு பெயரைக் குறிக்கும், எனவே அது ஒரு named volume. அந்தப் பெயர் மேல்மட்டத்தில் உள்ள volumes: block-ல் கட்டாயம் அறிவிக்கப்பட்டிருக்க வேண்டும்.
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 முறையில் mount செய்கிறது. ஒரு container மாற்றியமைக்கக் கூடாத configuration கோப்புகளுக்கு இதுவே சரியான இயல்புநிலை (default) அமைப்பாகும். மேல்மட்டத்திலுள்ள volumes: உள்ளீட்டை நீக்கினால், service "db" refers to undefined volume pgdata பிழையுடன் Compose நின்றுவிடும்.
இதை இயக்கி, Docker உருவாக்கியுள்ளவற்றை பட்டியலிடவும்:
docker compose up -d
docker volume lsஇந்த volume-க்கு pgdata என்று பெயரிடப்படவில்லை. இதற்கு <project>_pgdata என்று பெயரிடப்பட்டுள்ளது; இதில் project-ன் பெயர், compose கோப்பு உள்ள கோப்பகத்தின் (directory) பெயரை இயல்புநிலையாகக் கொள்கிறது. myapp என்ற பெயருடைய கோப்பகம் myapp_pgdata என்பதை உருவாக்குகிறது. கோப்பகத்தின் பெயரை மாற்றினால் புதிய காலி volume உருவாகும் என்பதால் இது முக்கியமானது; அப்போது உங்கள் application தரவுகளை இழந்தது போலத் தோன்றும். உண்மையில் தரவுகள் இழக்கப்படவில்லை: பழைய volume docker volume ls கட்டளையின் மூலம் பட்டியலிடப்படும். கோப்பகம் மாறக்கூடும் என்றால், compose கோப்பில் name: மூலம் பெயரை உறுதிப்படுத்தவும் அல்லது COMPOSE_PROJECT_NAME-ஐ அமைக்கவும். இது போன்ற அமைப்புகள் உங்கள் பிற Compose environment கோப்புகள் மற்றும் ரகசியங்கள் பிரிவில் இடம்பெற வேண்டும்.
Bind mount-களில் மட்டும் ஏன் permission பிழைகள் ஏற்படுகின்றன
இதுவே நடைமுறையில் உள்ள மிகப்பெரிய வேறுபாடு. இது ஒரு விதியைப் பொறுத்தது: முதலில் பயன்படுத்தப்படும்போது காலியாக இருக்கும் named volume, image-ல் உள்ள தரவுகளைக் கொண்டு நிரப்பப்படும் (seeded). ஆனால், bind mount ஒருபோதும் அவ்வாறு செய்யாது.
Docker ஒரு காலியான named volume-ஐ, ஏற்கனவே உள்ளடக்கத்தைக் கொண்ட ஒரு directory-ன் மீது mount செய்யும்போது, அந்த image-ல் உள்ள ownership மற்றும் modes-உடன் அந்த உள்ளடக்கத்தை volume-க்குள் நகலெடுக்கும். அதிகாரப்பூர்வ Postgres image, /var/lib/postgresql/data-ஐ அதன் சொந்த postgres பயனரின் உரிமையில் வைத்திருக்கும். எனவே, அந்த volume-ம் அதே numeric id உரிமையுடன் உருவாகி, database இயங்கத் தொடங்கும்.
Bind mount இதற்கு நேர்மாறாகச் செயல்படும். Host-ல் என்ன இருக்கிறதோ அதுவே container-க்குத் தெரியும் (ownership உட்பட). அந்தப் பாதையில் உள்ள image-ன் உள்ளடக்கம் மறைக்கப்படும். Host directory இல்லையென்றால், Docker daemon அதை உருவாக்கும். Daemon root-ஆக இயங்குவதால், அந்த directory root:root உரிமையில் உருவாகும். Non-root பயனராக இயங்கும் container process-ஆல் அதில் எழுத முடியாது:
PermissionError: [Errno 13] Permission denied: '/data/app.db'இதற்கான தீர்வு, எண்களை (numeric IDs) ஒத்துப்போகச் செய்வதுதான். Bind mount-ல் ownership என்பது பெயரால் அல்ல, numeric user id-ஆல் ஒப்பிடப்படுகிறது. ஏனெனில், container-க்கு அதன் சொந்த /etc/passwd இருக்கும். Container-க்குள் app என்று அழைக்கப்படும் ஒரு பயனர், host-ல் எந்த அர்த்தமும் தராது. Uid 1000 என்பது இரு பக்கங்களிலும் 1000 என்றே குறிக்கப்படும்.
id -u
mkdir -p ./data
docker compose exec web id
sudo chown -R 1000:1000 ./datadocker compose exec web id, container process உண்மையில் எந்த uid-ல் இயங்குகிறது என்பதைக் காட்டும். Host directory-ன் உரிமையை அந்த எண்ணிற்கு மாற்றவும், அல்லது service-ல் user: "1000:1000" மூலம் container-ஐ உங்கள் எண்ணிற்குப் பொருத்தவும் (pin). நீங்கள் சொந்தமாக எழுதிய application-க்கு user:-ஐப் பயன்படுத்துவது சுத்தமான முறையாகும். நீங்கள் எழுதாத image-களுக்கு host directory-ஐ chown செய்வது பாதுகாப்பானது. ஏனெனில், சில image-கள் root-ஆக entrypoint-ஐத் தொடங்கி, பின் உரிமைகளைக் குறைத்து (drop privileges), குறிப்பிட்ட ownership-ஐ எதிர்பார்க்கும்.
மேலும் இரண்டு சிக்கல்களைத் தெரிந்துகொள்வது அவசியம். Fedora, RHEL மற்றும் SELinux (security-enhanced Linux) அமலில் உள்ள பிற system-களில், bind mount மறுக்கப்படும். எனவே, containers-க்கு இடையே பகிரப்படும் பாதைக்கு :z-ஐயும், ஒரு container மட்டும் பயன்படுத்தும் பாதைக்கு :Z-ஐயும் சேர்க்கவும். இது - ./data:/data:Z என எழுதப்படும். மேலும், ஒரு directory-க்கு பதிலாக ஒரு கோப்பை (file) மட்டும் bind mount செய்யும்போது, ஒரு editor அந்த கோப்பை மாற்றியமைத்தால் (replace), mount பழைய inode-ஐயே பின்தொடரும். நீங்கள் restart செய்யும் வரை container பழைய உள்ளடக்கத்தையே பார்க்கும். கோப்பு அடிக்கடி திருத்தப்பட்டால், அதன் parent directory-ஐ mount செய்யவும்.
செயல்திறன்: இடைவெளி எங்கே உண்மையானது
Linux server-ல் இரண்டு வகைகளும் ஒரே kernel path வழியாகவே செல்கின்றன, எனவே throughput-ல் உள்ள வித்தியாசம் மிகக் குறைவு; இதை அடிப்படையாகக் கொண்டு நீங்கள் எதையும் தேர்வு செய்ய வேண்டியதில்லை. இயல்பான local driver-ஐப் பயன்படுத்தும் named volumes, Docker-ன் பிற பகுதிகள் இருக்கும் அதே filesystem-ல், /var/lib/docker/volumes/-க்குக் கீழ் அமைகின்றன. ஆனால், bind mount நீங்கள் குறிப்பிடும் எந்த இடத்திலும் அமையும்.
Docker Desktop for macOS மற்றும் Windows-ல் இந்த இடைவெளி தெளிவாகத் தெரியும், ஏனெனில் அங்கு containers ஒரு virtual machine-க்குள் இயங்குகின்றன. அங்கு ஒரு bind mount, host filesystem-லிருந்து அந்த virtual machine-க்குள் ஒரு file sharing layer வழியாகச் செல்கிறது. இதனால், Node.js dependency tree அல்லது PHP framework cache போன்ற பல சிறிய file செயல்பாடுகளைக் கொண்ட workloads குறிப்பிடத்தக்க அளவில் வேகம் குறைகின்றன. Named volumes அந்த virtual machine-க்குள்ளேயே இருப்பதால், இந்தச் செலவை (cost) அவை ஏற்பதில்லை. இதனால்தான் பல development compose files, source directory-ஐ bind-mount செய்தாலும், node_modules-க்கு மேல் ஒரு named volume-ஐ அறிவிக்கின்றன.
மற்றொரு முக்கியமான வித்தியாசம் தரவுகள் எங்கு சேமிக்கப்படுகின்றன என்பதுதான். /mnt/backup-க்கு ஒரு bind mount செய்வது, தரவுகளை அந்த disk-ல் வைக்கிறது. ஒரு named volume, /var/lib/docker இருக்கும் எந்த filesystem-ல் வேண்டுமானாலும் அமையும்; VPS-ல் இது பொதுவாக root disk-ஆகவே இருக்கும். ஒரு named volume-க்குள் வளரும் database, உங்கள் system logs இருக்கும் அதே disk-ஐ நிரப்பிவிடும். ஒரு சிக்கலாக மாறுவதற்கு முன் அதைச் சரிபார்க்கவும்:
docker system df -v
df -h /var/lib/dockerdocker system df -v ஒவ்வொரு volume-ன் அளவையும் பட்டியலிடுகிறது, மேலும் எந்த container-உம் பயன்படுத்தாத volumes-ஐயும் இது குறிக்கும்.
Named volume-ஐ ஆய்வு செய்தல்
Named volume என்பது ஒரு மர்மமான பெட்டி அல்ல. அது எங்குள்ளது என்பதை Docker-இடம் கேட்கலாம்:
docker volume inspect myapp_pgdataMountpoint புலம் ஒரு உண்மையான host path-ஐக் காட்டுகிறது, இது பொதுவாக /var/lib/docker/volumes/myapp_pgdata/_data ஆக இருக்கும். நீங்கள் அதை sudo ls மூலம் படிக்கலாம், இது விரைவான சரிபார்ப்பிற்கு பயனுள்ளதாக இருக்கும். கோப்புகளைத் திருத்துவதற்கு இதை ஒரு இடமாகப் பயன்படுத்த வேண்டாம். root பயனர் மூலம் அங்கு எழுதுவது மேலே விவரிக்கப்பட்ட ownership சிக்கலை மீண்டும் உருவாக்கும், மேலும் இந்த path என்பது local driver-ன் ஒரு நுணுக்கம் மட்டுமே, மற்ற volume driver-களில் இது இருக்காது.
அதற்குள் பார்ப்பதற்கான பாதுகாப்பான வழி, அந்த volume-ஐ mount செய்யும் ஒரு தற்காலிக container-ஐப் பயன்படுத்துவதாகும்:
docker run --rm -v myapp_pgdata:/vol alpine ls -la /volஇது எந்தவொரு driver-க்கும் வேலை செய்யும், உண்மையான container பார்க்கும் அதே அனுமதிகளை இதுவும் பார்க்கும், மேலும் --rm காரணமாக இது எதையும் பின்னால் விட்டுச் செல்லாது.
ஒவ்வொரு வகைக்கும் பேக்கப் எடுத்தல்
Bind mount என்பது ஒரு சாதாரண directory ஆகும், எனவே எந்தவொரு file-level backup கருவியும் இதை எளிதாகக் கையாளும். Host path-ஐ பேக்கப் கருவியில் குறிப்பிட்டால் போதுமானது. Named volume-க்கு கூடுதல் ஒரு படி தேவை, ஏனெனில் பேக்கப் கருவி அந்த volume-க்குள் நுழைய வேண்டும். ஒரு தற்காலிக container-ல் அந்த volume-ஐயும் ஒரு host directory-யையும் mount செய்து, பின்வருமாறு archive உருவாக்கவும்:
docker run --rm \
-v myapp_pgdata:/data:ro \
-v "$PWD":/backup \
alpine tar czf /backup/pgdata.tar.gz -C /data .புதிய volume-ல் இதைத் திருப்பிச் செலுத்துவதன் (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 /datatar, container-க்குள் root பயனர் மூலம் இயங்கும்போது numeric ownership-ஐ அப்படியே பாதுகாக்கிறது. இதுவே மீட்டெடுக்கப்பட்ட volume-ஐ application பயன்படுத்தக்கூடிய நிலையில் வைத்திருக்க உதவுகிறது.
இரண்டு வகைக்கும் ஒரு எச்சரிக்கை பொருந்தும். Database இயங்கிக்கொண்டிருக்கும்போது அதன் கோப்புகளை நகலெடுப்பது, மாறிக்கொண்டிருக்கும் தரவின் archive-ஐ உருவாக்கும்; இது மீட்டெடுக்கும்போது தரவு சிதைந்த நிலைக்கு (corrupt state) செல்லக்கூடும். எனவே, முதலில் service-ஐ நிறுத்தவும் அல்லது docker compose exec -T db pg_dump -U postgres appdb > appdb.sql-ல் உள்ளவாறு database-ன் சொந்தக் கருவியைப் பயன்படுத்தி dump எடுக்கவும். இது ஒரு சாதாரண கோப்பை உருவாக்கும், அதை நீங்கள் உங்கள் compose கோப்புகளுடன் சேர்த்து ஒரு encrypted restic backup routine-ல் இணைக்கலாம்.
Bind mount-ஐ named volume-க்கு மாற்றுதல்
இந்த மாற்றம் ஒரு நகலெடுப்பு (copy) ஆகும், இது பெயர் மாற்றம் (rename) அல்ல. இதற்கு சுமார் ஒரு நிமிடம் ஆகும்.
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, modes மற்றும் timestamps ஆகியவற்றை அப்படியே வைத்திருக்கும். எனவே, பழைய directory-ஐ வாசிக்க முடிந்த container user-ஆல் புதிய volume-ஐயும் தொடர்ந்து வாசிக்க முடியும். அதன் பிறகு, pgdata:/var/lib/postgresql/data-ஐப் பயன்படுத்தும் வகையில் service-ஐ மாற்றவும். top-level volumes: block-ல் pgdata-ஐச் சேர்க்கவும். பின் docker compose up -d-ஐ இயக்கவும். பழைய directory-ஐ நீக்குவதற்கு முன்பு, application-ன் logs-ஐச் சரிபார்க்கவும். இதற்கு நேர்மாறான செயல்பாட்டிற்கு, /from மற்றும் /to ஆகியவற்றை இடமாற்றி அதே கட்டளையைப் பயன்படுத்தவும்.
சோதனை செய்யும்போது ஒரு விஷயத்தை நினைவில் கொள்ளவும். docker compose down ஆனது named volumes-ஐப் பாதிக்காது. ஆனால், docker compose down -v அந்த project-ல் அறிவிக்கப்பட்டுள்ள அனைத்து named volumes-ஐயும் நீக்கிவிடும். இதைத் திரும்பப் பெற (undo) முடியாது. Bind mount-ஐ Docker நிர்வகிப்பதில்லை என்பதால், அது இவ்விரண்டு கட்டளைகளாலும் பாதிக்கப்படாது. Lifecycle கட்டளைகள் உங்களுக்குப் புதியவை என்றால், VPS-க்கான Docker Compose அடிப்படை வழிகாட்டி அவற்றை விரிவாக விளக்குகிறது.
சேவை வாரியாகத் தேர்ந்தெடுத்தல்
கோப்பை யார் உருவாக்குகிறார்கள் என்று கவனிக்கவும். நீங்கள் text editor-ல் திருத்தி git-ல் commit செய்யும் configuration கோப்புகள் bind mount-ல் இருக்க வேண்டும், அவை :ro-ல் mount செய்யப்பட வேண்டும், ஏனெனில் அவை உங்களுக்குத் தெரிய வேண்டும் மற்றும் version control-ல் இருக்க வேண்டும். நீங்கள் கைமுறையாகத் திறக்காத application state-கள் named volume-ல் இருக்க வேண்டும், ஏனெனில் Docker அவற்றின் அனுமதிகளை (permissions) சரியாக அமைக்கும் மற்றும் தரவு host path-ஐச் சார்ந்திருக்காது.
கலப்பு வகை என்பது media கோப்புகள் ஆகும். ஒரு photo library-ஐ application எழுதும், ஆனால் அதை நீங்களும் நிர்வகிப்பீர்கள், மேலும் அது ஒரு குறிப்பிட்ட disk-ஐப் பயன்படுத்தும் அளவுக்குப் பெரியதாக இருக்கும். அதை அந்த disk-ல் உள்ள ஒரு path-க்கு bind mount செய்யவும், அதன் உரிமையை (ownership) ஒருமுறை மட்டும் கவனமாக அமைக்கவும். பெரும்பாலான self-hosted stack-கள் இந்த முறையையே பின்பற்றுகின்றன: database மற்றும் cache-களுக்கு named volume-களையும், configuration மற்றும் நீங்கள் முக்கியமாகக் கருதும் பெரிய directory-களுக்கு bind mount-களையும் பயன்படுத்துகின்றன. VPS-ல் இயங்கும் Chatwoot போன்ற ஒரு support desk இந்த முறையில்தான் அமைகிறது; இதில் Postgres ஒரு named volume-லும், பதிவேற்றப்பட்ட கோப்புகள் நீங்கள் backup எடுக்கக்கூடிய ஒரு path-லும் இருக்கும்.
FAQ
bind mount மற்றும் named volume-க்கு இடையே உள்ள வேறுபாடு என்ன?
Bind mount என்பது host-ல் உள்ள ஒரு பாதையை container-க்குள் இணைக்கிறது. இதனால் இரு பக்கங்களிலும் ஒரே directory தெரியும், மேலும் சாதாரண கருவிகளைக் கொண்டு நீங்கள் அதைத் திருத்த முடியும். Named volume என்பது Docker-ஆல் உருவாக்கப்பட்டு நிர்வகிக்கப்படும் சேமிப்பகம் ஆகும். இது பெயரால் குறிக்கப்படுகிறது மற்றும் top-level volumes: தொகுதியில் அறிவிக்கப்படுகிறது. நடைமுறையில், நீங்கள் பராமரிக்கும் configuration கோப்புகளுக்கு bind mount-ஐயும், application பராமரிக்கும் தரவுகளுக்கு named volume-ஐயும் பயன்படுத்துவது சிறந்தது.
bind mount-ல் ஏன் "permission denied" பிழை வருகிறது, ஆனால் named volume-ல் வருவதில்லை?
காலியாக உள்ள named volume, image-ல் உள்ள அமைப்புகளைப் பெற்றுக்கொள்ளும். எனவே, image-ல் வரையறுக்கப்பட்ட உரிமையாளர் (ownership) அதற்கு இருக்கும் மற்றும் container பயனர் அதில் எழுத முடியும். Bind mount, host directory-ஐ அப்படியே காட்டும். Docker அந்த directory-ஐ உருவாக்க வேண்டியிருந்தால், அது root உரிமையில் உருவாக்கப்படும். Container பயன்படுத்தும் numeric id-ஐப் பார்க்க docker compose exec <service> id கட்டளையை இயக்கவும், பிறகு host directory-க்கு sudo chown -R <uid>:<gid> செய்யவும் அல்லது service-ல் user: "1000:1000"-ஐ அமைக்கவும்.
Docker named volume-களை வட்டில் (disk) எங்கே சேமிக்கிறது?
இயல்புநிலை local driver-ஐப் பயன்படுத்தும்போது, அவை /var/lib/docker/volumes/<volume>/_data-க்கு கீழ் சேமிக்கப்படும். docker volume inspect <volume> கட்டளை அதன் சரியான Mountpoint-ஐக் காட்டும். ஏதேனும் சரிபார்க்க வேண்டுமென்றால் அதைப் படிக்கலாம், ஆனால் container வழியாக மட்டுமே அதில் எழுத வேண்டும். ஏனெனில், host-ல் root பயனராகத் திருத்தங்கள் செய்வது, container எதிர்பாராத வகையில் உரிமையாளர் மாற்றங்களை ஏற்படுத்திவிடும்.
named volume-ஐ எவ்வாறு backup எடுப்பது?
Volume மற்றும் host directory ஆகிய இரண்டையும் இணைத்து ஒரு தற்காலிக container-ஐ இயக்கவும். பிறகு docker run --rm -v myvol:/data:ro -v "$PWD":/backup alpine tar czf /backup/myvol.tar.gz -C /data . கட்டளையைப் பயன்படுத்தி ஒன்றிலிருந்து மற்றொன்றுக்கு archive செய்யவும். Database-க்கு, நேரடி கோப்புகளை நகலெடுப்பதற்குப் பதிலாக, அந்த database-ன் சொந்தக் கருவியைப் பயன்படுத்தி dump எடுக்கவும். ஏனெனில், தரவுகள் எழுதப்படும்போது கோப்புகளை நகலெடுத்தால், அவை சிதைந்த நிலையில் (corrupt) மீட்கப்பட வாய்ப்புள்ளது.
docker compose down கட்டளை எனது volume-களை நீக்கிவிடுமா?
docker compose down கட்டளை container-கள் மற்றும் network-களை மட்டுமே நீக்கும், named volume-களை அப்படியே விட்டுவிடும். docker compose down -v கட்டளை, project-ல் அறிவிக்கப்பட்ட அனைத்து named volume-களையும் நிரந்தரமாக நீக்கிவிடும். Bind mount-கள் எந்தக் கட்டளையாலும் நீக்கப்படாது, ஏனெனில் அந்த directory Docker-க்குச் சொந்தமானது அல்ல, அது host-க்குச் சொந்தமானது.