SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor · আপডেট করা হয়েছে 2026-08-26

Docker Compose volume: bind mount নাকি named volume?

config ও database data-র জন্য bind mount বা named volume বাছুন। file permission সমস্যা এড়ান, volume inspect করুন এবং নিরাপদে backup ও migrate করার পদ্ধতি জানুন।

Bind mount নাকি named volume: সংক্ষিপ্ত উত্তর

Docker Compose volume দুই ধরনের। পছন্দটি নির্ভর করে ফাইলের মালিকানা কার ওপর থাকবে তার ওপর। আপনি নিজে যে ফাইল লিখবেন ও পড়বেন, যেমন config, template এবং static site, সেগুলোর জন্য bind mount ব্যবহার করুন। যে data application নিজে পরিচালনা করবে, যেমন database file, search index এবং uploaded media, সেগুলোর জন্য named volume ব্যবহার করুন। bind mount host-এর এমন একটি path নির্দেশ করে, যা আপনি editor-এ খুলতে পারেন। named volume হলো Docker-এর তৈরি ও পরিচালিত storage, যেটিতে Docker-এর মাধ্যমেই পৌঁছাতে হয়।

একটি service-এর মধ্যে উভয় ধরনের volume একই volumes: key-এর অধীনে থাকে। তাই এগুলো প্রায়ই গুলিয়ে যায়। পার্থক্যটি colon-এর বাম পাশে। . বা / দিয়ে শুরু হওয়া বাম পাশের অংশ host path নির্দেশ করে, তাই সেটি bind mount। অন্য যেকোনো অংশ একটি name, তাই সেটি named volume; এবং সেই name-টি top-level volumes: block-এও ঘোষণা করতে হবে।

Compose file-এ দুটি syntax

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। Top-level volumes: entry বাদ পড়লে Compose service "db" refers to undefined volume pgdata দেখিয়ে থেমে যায়।

এটি চালু করুন এবং Docker কী তৈরি করেছে তা তালিকাভুক্ত করুন:

docker compose up -d
docker volume ls

Volume-টির নাম pgdata নয়। এর নাম <project>_pgdata। এখানে project name-এর default হলো compose file থাকা directory-এর নাম। myapp নামের একটি directory হলে নামটি হবে myapp_pgdata। এটি গুরুত্বপূর্ণ, কারণ directory-এর নাম পরিবর্তন করলে আপনি একটি নতুন empty volume পান এবং application-টি মনে হয় তার data হারিয়েছে। আসলে তা হয়নি: পুরোনো volume এখনও docker volume ls-এর তালিকায় আছে। Directory সরতে পারে এমন ক্ষেত্রে compose file-এ name: দিয়ে নাম নির্দিষ্ট করুন, অথবা COMPOSE_PROJECT_NAME সেট করুন। এ ধরনের setting আপনার অন্যান্য Compose environment file ও secret-এর সঙ্গে রাখা উচিত।

শুধু bind mount-এ permission error কেন হয়

এটাই সবচেয়ে গুরুত্বপূর্ণ বাস্তব পার্থক্য। এর কারণ একটি নিয়ম: প্রথমবার ব্যবহারের সময় খালি named volume image থেকে প্রাথমিক content পায়, কিন্তু bind mount কখনো তা পায় না।

Docker যখন image-এ আগে থেকেই content থাকা কোনো directory-এর ওপর একটি খালি named volume mount করে, তখন image-এর সেই content volume-এ কপি করে। Image-এ নির্ধারিত ownership এবং mode-ও বজায় থাকে। Official Postgres image-এ /var/lib/postgresql/data তার নিজস্ব postgres user-এর মালিকানাধীন থাকে। তাই volume-টির মালিকানাও একই numeric id হয় এবং database start হয়।

Bind mount ঠিক উল্টোভাবে কাজ করে। Host-এ যা আছে, container সেটিই দেখে এবং ownership-ও একই থাকে। ওই path-এ থাকা image-এর content আড়াল হয়ে যায়। Host directory না থাকলে Docker daemon সেটি তৈরি করে। Daemon root হিসেবে চলে, তাই directory-টির মালিক হয় root:root। এরপর non-root user হিসেবে চলা container process ওই directory-তে লিখতে পারে না:

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

সমাধান হলো numeric id দুপাশে একই করা। Bind mount-এর ক্ষেত্রে ownership নাম দিয়ে নয়, numeric user id দিয়ে তুলনা করা হয়, কারণ container-এর নিজস্ব /etc/passwd থাকে। Container-এর ভেতরে app নামের user host-এ কোনো অর্থ বহন করে না। Uid 1000 উভয় পাশেই uid 1000।

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

docker compose exec web id container process বাস্তবে যে uid হিসেবে চলে, তা দেখায়। Host directory-টির মালিকানা ওই সংখ্যার সঙ্গে মিলিয়ে দিন। অথবা service-এ user: "1000:1000" ব্যবহার করে container-কে আপনার uid-তে চালান। নিজের লেখা application-এর ক্ষেত্রে user: নির্দিষ্ট করে দেওয়া বেশি পরিষ্কার। নিজে না-লেখা image-এর ক্ষেত্রে host directory-তে Chown করা বেশি নিরাপদ। কারণ কিছু image root হিসেবে entrypoint চালু করে, পরে privilege কমিয়ে দেয় এবং নির্দিষ্ট ownership প্রত্যাশা করে।

আরও দুটি সমস্যা জানা দরকার। Fedora, RHEL এবং SELinux (security-enhanced Linux) enforcing অবস্থায় থাকা অন্যান্য system-এ relabel না করা পর্যন্ত bind mount প্রত্যাখ্যাত হয়। তাই একাধিক container-এর মধ্যে শেয়ার করা path-এর জন্য :z এবং শুধু একটি container-এর ব্যবহারের path-এর জন্য :Z যোগ করুন। এটি - ./data:/data:Z হিসেবে লিখতে হবে। আর directory-এর বদলে একটি নির্দিষ্ট file bind mount করলে editor file-টি in-place লেখার পরিবর্তে প্রতিস্থাপন করার সময় সমস্যা হয়। কারণ mount-টি মূল inode অনুসরণ করে। Container পুরোনো content-ই দেখতে থাকে, যতক্ষণ না সেটি restart করা হয়। File-টি প্রায়ই সম্পাদনা করা হলে parent directory mount করুন।

Performance: যেখানে পার্থক্য বাস্তব

Linux server-এ উভয় ধরনের storage একই kernel path ব্যবহার করে। তাই throughput-এর পার্থক্য এত কম যে এর ভিত্তিতে সিদ্ধান্ত নেওয়া উচিত নয়। ডিফল্ট local driver ব্যবহার করা named volume-গুলো Docker-এর বাকি data-এর মতো একই filesystem-এ, /var/lib/docker/volumes/-এর অধীনে থাকে। bind mount থাকে আপনি যে location নির্ধারণ করেছেন সেখানে।

Docker Desktop for macOS এবং Windows-এ এই পার্থক্য দেখা যায়, কারণ container-গুলো একটি virtual machine-এর ভিতরে চলে। সেখানে bind mount host filesystem থেকে file sharing layer-এর মাধ্যমে ওই virtual machine-এ যায়। Node.js dependency tree বা PHP framework cache-এর মতো অনেক ছোট file operation থাকা workload-এ এর ফলে লক্ষণীয়ভাবে গতি কমে। named volume virtual machine-এর ভিতরেই থাকে এবং এই অতিরিক্ত খরচ হয় না। এ কারণেই development compose file-এ source directory bind-mount করা হয়, কিন্তু node_modules-এর ওপর একটি named volume নির্ধারণ করা হয়।

আরেকটি বাস্তব পার্থক্য হলো data কোথায় লেখা হয়। /mnt/backup-এ bind mount করলে data ওই disk-এ লেখা হয়। named volume-এর data /var/lib/docker ধারণকারী filesystem-এ লেখা হয়, যা VPS-এ সাধারণত root disk। named volume-এর ভিতরে বাড়তে থাকা database সেই একই disk ভরে দেয়, যেখানে system log-ও থাকে। সমস্যা তৈরি হওয়ার আগে এটি পরীক্ষা করুন:

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

docker system df -v size-সহ প্রতিটি volume তালিকাভুক্ত করে এবং যেসব volume আর কোনো container ব্যবহার করে না, সেগুলো চিহ্নিত করে।

নামযুক্ত volume পরীক্ষা করা

নামযুক্ত volume কোনো black box নয়। Docker-কে এর অবস্থান জানাতে বলুন:

docker volume inspect myapp_pgdata

Mountpoint field-এ host-এর প্রকৃত path দেখা যায়, সাধারণত /var/lib/docker/volumes/myapp_pgdata/_datasudo ls দিয়ে এটি পড়তে পারেন। দ্রুত পরীক্ষা করার জন্য এটি উপযোগী। তবে এই path-কে file edit করার স্থান হিসেবে ব্যবহার করবেন না। সেখানে root হিসেবে write করলে উপরে বর্ণিত ownership সমস্যা আবার তৈরি হবে। তাছাড়া path-টি local driver-এর একটি নির্দিষ্ট বিবরণ, যা অন্য volume driver-এ নাও থাকতে পারে।

ভেতরের বিষয়বস্তু দেখার নিরাপদ উপায় হলো volume mount করে একটি সাময়িক container চালানো:

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

যেকোনো driver-এর ক্ষেত্রে এটি কাজ করে। প্রকৃত container যে permissions দেখে, এটিও একই permissions দেখে। --rm-এর কারণে কাজ শেষে কোনো কিছু অবশিষ্ট থাকে না।

প্রতিটি ধরনের ব্যাকআপ নেওয়া

Bind mount একটি সাধারণ directory, তাই যেকোনো file-level backup tool এটি স্বয়ংক্রিয়ভাবে পরিচালনা করতে পারে। Backup-এর জন্য host path নির্দিষ্ট করলেই কাজ শেষ। Named volume-এর ক্ষেত্রে আরও একটি ধাপ প্রয়োজন, কারণ tool-টিকে volume-এর ভেতরে প্রবেশ করতে হয়। একই short-lived 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 /data

Container-এর ভেতরে root হিসেবে চলার সময় tar numeric ownership সংরক্ষণ করে। এটাই restored volume-কে application-এর জন্য ব্যবহারযোগ্য রাখে।

উভয় ধরনের ক্ষেত্রেই একটি সতর্কতা প্রযোজ্য। Database চলমান অবস্থায় তার file কপি করলে এমন একটি archive তৈরি হয়, যা পরিবর্তনশীল অবস্থার snapshot। এটি restore করার পরে corrupt state তৈরি হতে পারে। আগে service বন্ধ করুন, অথবা database-এর নিজস্ব tool ব্যবহার করে dump নিন, যেমন docker compose exec -T db pg_dump -U postgres appdb > appdb.sql-এ দেখানো হয়েছে। এতে একটি সাধারণ file তৈরি হয়। এরপর compose file-এর পাশাপাশি সেটিকে স্বাভাবিক encrypted restic backup routine-এ অন্তর্ভুক্ত করতে পারেন।

named volume-এ bind mount স্থানান্তর

এই স্থানান্তরটি rename নয়, copy operation। এটি সম্পন্ন হতে প্রায় এক মিনিট লাগে।

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, mode এবং timestamp অপরিবর্তিত রাখে। তাই পুরোনো directory পড়তে পারা container user নতুন volume-টিও পড়তে পারে। এরপর service-টি pgdata:/var/lib/postgresql/data ব্যবহার করার জন্য পরিবর্তন করুন, top-level volumes: block-এ pgdata যোগ করুন, docker compose up -d চালান এবং পুরোনো directory মুছে ফেলার আগে application-এর log পরীক্ষা করুন। উল্টো দিকে যেতে হলে একই command ব্যবহার করুন, তবে /from এবং /to অদলবদল করুন।

পরীক্ষা করার সময় একটি বিষয় মনে রাখুন। docker compose down named volume অপরিবর্তিত রাখে। কিন্তু docker compose down -v project-এ ঘোষিত প্রতিটি named volume মুছে দেয়, এবং এটি undo করা যায় না। bind mount উভয় ক্ষেত্রেই টিকে থাকে, কারণ Docker কখনও ওই directory-টির মালিক ছিল না। lifecycle command-গুলো এখনও নতুন হলে VPS-এর জন্য Docker Compose-এর মৌলিক নির্দেশিকা-তে সেগুলোর ব্যবহার ধাপে ধাপে দেখানো হয়েছে।

কোন ধরনের service কোথায় রাখবেন

ফাইলটি কে লিখছে, তা নির্ধারণ করুন। কোনো text editor-এ সম্পাদনা করে git-এ commit করা configuration bind mount-এ রাখা উচিত, যা :ro হিসেবে mount করা থাকে। এতে ফাইলটি দৃশ্যমান থাকে এবং version control-এর আওতায় থাকে। আপনি হাতে কখনো না খোলা application state named volume-এ রাখা উচিত। Docker এতে সঠিক permission সেট করে, এবং data কোনো host path-এর ওপর নির্ভর করে না।

মিশ্র ধরনের ক্ষেত্রে media বিবেচনা করুন। একটি photo library application লিখে, কিন্তু আপনি নিজেও এটি পরিচালনা করেন। এটি প্রায়ই এত বড় হয় যে নির্দিষ্ট disk ব্যবহার করা সুবিধাজনক। সেই disk-এর একটি path-এ এটি bind mount করুন এবং একবার নির্দিষ্টভাবে ownership সেট করুন। অধিকাংশ self-hosted stack শেষ পর্যন্ত এই পদ্ধতিই ব্যবহার করে: database ও cache-এর জন্য named volume, configuration-এর জন্য bind mount, এবং আপনার কাছে গুরুত্বপূর্ণ বড় directory-এর জন্য bind mount। একটি support desk, যেমন VPS-এ চলমান Chatwoot, ঠিক এই কাঠামোতে পড়ে। Postgres থাকে named volume-এ, আর uploaded attachment থাকে এমন একটি path-এ, যেটি backup-এর জন্য নির্দিষ্ট করা যায়।

FAQ

Bind mount এবং named volume-এর মধ্যে পার্থক্য কী?

একটি bind mount host-এর একটি path container-এর মধ্যে map করে। তাই উভয় দিক থেকেই একই directory দেখা যায় এবং আপনি সাধারণ tool দিয়ে এটি edit করতে পারেন। একটি named volume হলো Docker-এর তৈরি ও পরিচালিত storage, যেটিকে name দিয়ে উল্লেখ করা হয় এবং top-level volumes: block-এ declare করা হয়। ব্যবহারিক পার্থক্যটি ownership-এ: আপনি নিজে পরিচালনা করেন এমন config-এর জন্য bind mount ব্যবহার করুন, আর application নিজে পরিচালনা করে এমন data-এর জন্য named volume ব্যবহার করুন।

Bind mount-এ "permission denied" পাই, কিন্তু named volume-এ পাই না কেন?

একটি খালি named volume image থেকে seed করা হয়। তাই image যে ownership নির্ধারণ করেছে, volume সেটিই গ্রহণ করে এবং container user তাতে লিখতে পারে। Bind mount host directory-কে ঠিক যেভাবে আছে সেভাবেই দেখায়। Docker-কে যদি সেই directory তৈরি করতে হয়, তবে সেটি root-এর ownership-এ তৈরি হয়। Container কোন numeric id ব্যবহার করছে তা দেখতে docker compose exec <service> id চালান। এরপর host directory-তে sudo chown -R <uid>:<gid> চালান, অথবা service-এ user: "1000:1000" নির্ধারণ করুন।

Docker named volume disk-এ কোথায় সংরক্ষণ করে?

Default local driver ব্যবহার করলে এগুলো /var/lib/docker/volumes/<volume>/_data-এর অধীনে থাকে। সঠিক Mountpoint দেখতে docker volume inspect <volume> চালান। কিছু যাচাই করতে হলে এটি পড়তে পারেন। তবে এতে কেবল container-এর মাধ্যমে লিখুন, কারণ host-এ root হিসেবে edit করলে ownership এমনভাবে বদলে যেতে পারে যা container প্রত্যাশা করে না।

Named volume কীভাবে backup করব?

একটি স্বল্পস্থায়ী container চালান, যেখানে volume এবং host directory দুটিই mount করা থাকবে। এরপর docker run --rm -v myvol:/data:ro -v "$PWD":/backup alpine tar czf /backup/myvol.tar.gz -C /data . ব্যবহার করে এক স্থান থেকে অন্য স্থানে archive তৈরি করুন। Database-এর ক্ষেত্রে live file copy না করে database-এর নিজস্ব tool দিয়ে dump তৈরি করুন। কারণ write চলাকালীন নেওয়া file copy restore করলে corrupt state তৈরি হতে পারে।

docker compose down কি আমার volume মুছে ফেলে?

docker compose down container ও network সরিয়ে দেয় এবং named volume রেখে দেয়। docker compose down -v project-এ declare করা প্রতিটি named volume-ও মুছে দেয়, যা স্থায়ীভাবে কার্যকর হয়। কোনো command-ই bind mount সরায় না, কারণ সেই directory host-এর এবং Docker-এর নয়।