Docker Compose cheat sheet: সার্ভারে দৈনন্দিন কমান্ড
বাস্তব সার্ভারে প্রতিদিনের কাজে দরকারি Compose কমান্ড একসঙ্গে পান: lifecycle, পরিবর্তন প্রয়োগ, logs, shell, network, volume ও নিরাপদ cleanup।
আপনি বাস্তবে যে Compose কমান্ডগুলো বেশি ব্যবহার করবেন
Docker Compose-এ 40টিরও বেশি subcommand রয়েছে। সার্ভারে দৈনন্দিন কাজে প্রায় এক ডজন ব্যবহার হয়। আপনি যে কাজটি করছেন, এই পৃষ্ঠা সেই অনুযায়ী কমান্ডগুলো সাজিয়েছে, প্রতিটির জন্য একটি সরল কারণ দিয়েছে এবং কোনো কমান্ডের আড়ালে থাকা জটিলতার বিস্তারিত ব্যাখ্যার দিকে নির্দেশ করেছে।
এখানে সবকিছু Compose V2 ব্যবহার করে: docker compose-এর মাঝে একটি space থাকে, পুরোনো docker-compose script নয়। V2 হলো একটি Go plugin, যা Docker Engine-এর সঙ্গে install হয়। বর্তমান package-গুলোতে V1 আর নেই। তাই July 2026 অনুযায়ী নতুন Ubuntu box-এ docker-compose: command not found থাকা স্বাভাবিক; এটি কোনো ত্রুটি নয়। docker compose version দিয়ে পরীক্ষা করুন। কোনো output না এলে docker-compose-plugin package install করুন।
নিচের প্রতিটি কমান্ড সেই directory থেকে চালান যেখানে আপনার compose.yaml রয়েছে। কারণ Compose ওই directory থেকে project name নেয় এবং file-টি তার relative path অনুযায়ী খুঁজে পায়। একই কমান্ড এক level উপরে চালালে Compose no configuration file provided: not found দিয়ে থেমে যাবে। File format আপনার কাছে নতুন হলে VPS-এ প্রথম Compose file দিয়ে শুরু করুন। এরপর কমান্ডগুলোর জন্য এখানে ফিরে আসুন।
Lifecycle: আপনি যে চারটি command টাইপ করবেন, এবং যে একটি container সরিয়ে দেয়
docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose downup -d network তৈরি করে, container তৈরি করে, সেগুলো চালু করে এবং ফিরে আসে। container তৈরি হওয়ার সঙ্গে সঙ্গেই এটি ফিরে আসে। তাই এর পরে curl probe চালানো deploy script প্রথমবার প্রায়ই ব্যর্থ হয়। up -d --wait healthcheck ঘোষণা করা প্রতিটি service healthy না হওয়া পর্যন্ত অপেক্ষা করে। কোনো service কখনো healthy না হলে এটি non-zero exit code দিয়ে শেষ হয়। এই flag-টির কার্যকারিতা এর পেছনের check-এর মানের ওপর নির্ভর করে। তাই automation-এ এটি ব্যবহারের আগে Compose বিশ্বাস করতে পারে এমন healthcheck লিখুন।
stop container থামায় এবং সেগুলো রেখে দেয়। তাই start একই writable layer-সহ একই container আবার চালু করে। down container থামানোর পর সেগুলো এবং project network সরিয়ে দেয়। volume-এর বাইরে container-এর ভিতরে লেখা যেকোনো data container-এর সঙ্গে মুছে যায়। Compose-এ এটি সবচেয়ে ব্যয়বহুল ভুল বোঝাবুঝি। down এবং stop-এর সম্পূর্ণ পার্থক্য অংশে এটি কোন ক্ষেত্রে সমস্যা তৈরি করে তা ব্যাখ্যা করা হয়েছে।
restart reload নয়। এটি একই container-এর বর্তমান configuration ব্যবহার করে container থামিয়ে আবার চালু করে। তাই পরিবর্তিত environment variable, নতুন image tag বা সম্পাদিত port mapping-এর কোনো প্রভাব পড়ে না। file পরিবর্তন প্রয়োগ করতে আবার up -d চালান। Compose প্রতিটি service-কে তার চলমান container-এর সঙ্গে তুলনা করে এবং শুধু configuration পরিবর্তিত হওয়া container-গুলো পুনরায় তৈরি করে।
পরিবর্তন প্রয়োগ করা: recreate, pull বা rebuild
docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build webup -d-এর configuration-এ কোনো পরিবর্তন না থাকলে এটি কিছুই করে না। এ কারণেই এটি বারবার চালানো নিরাপদ। --force-recreate এই তুলনা উপেক্ষা করে configuration একই হলেও প্রতিটি container প্রতিস্থাপন করে। তাই container-এর অস্বাভাবিক অভ্যন্তরীণ state দ্রুত পরিষ্কার করার এটি সবচেয়ে সহজ উপায়।
একটি image আপডেট করতে দুটি command লাগে, কারণ এগুলো ভিন্ন কাজ করে। pull ফাইলে উল্লেখ করা প্রতিটি tag-এর জন্য বর্তমান image download করে। এরপর up -d দেখে যে service-এর image ID তার চলমান container-এর সঙ্গে আর মেলে না, এবং container-টি পুনরায় তৈরি করে। pull ধাপটি বাদ দিলে up -d গত মাসের latest চালু রাখে এবং কোনো error দেখায় না। বিপরীত ঝুঁকি দেখা যায় multi-service stack-এ। সেখানে একই সময়ে প্রতিটি service-এর জন্য latest pull করলে দশ সেকেন্ড আগেও সচল থাকা একটি app নষ্ট হতে পারে। এই কারণে self-hosted AFFiNE workspace তার চারটি image tag আলাদাভাবে pin করে। Pinning করলে upgrade একটি নির্ধারিত পরিবর্তনে পরিণত হয়: tag সম্পাদনা করার পর একই pull ও recreate ধাপ চালাতে হয়। যে stack boot হওয়ার সময় database migrate করে, সেখানে যেকোনো command চালানোর আগে একটি dump প্রস্তুত রাখা উচিত। প্রতিটি version bump-এর সময় self-hosted Chatwoot support desk এই নিয়ম অনুসরণ করে।
build সেই service-গুলোর ক্ষেত্রে প্রযোজ্য, যেগুলো image:-এর পরিবর্তে একটি build: section ঘোষণা করে। up -d --build এক ধাপেই build ও start করে। Code পরিবর্তনের সময় এটিই সাধারণ workflow। কোনো cached layer স্পষ্টভাবে stale না হওয়া পর্যন্ত --no-cache ব্যবহার করবেন না, কারণ এটি প্রতিটি layer শূন্য থেকে rebuild করে। Registry image-এর পরিবর্তে checked out git tag থেকে কোনো stack deploy করা হলে একই build workflow তার update path হিসেবেও কাজ করে। এভাবেই self-hosted openGym workout tracker একটি pinned version থেকে পরেরটিতে যায়।
চলমান অবস্থা দেখা
docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose lsps শুধু বর্তমানে চলমান container তালিকাভুক্ত করে। কোনো service শুরু হওয়ার সময় crash করলে -a যোগ না করা পর্যন্ত সেটি সেখানে দেখা যায় না। তাই ps-এ কোনো container না থাকলেও ps -a সেটিকে Exited (1) হিসেবে দেখালে সেটিই startup failure-এর স্বাভাবিক চিত্র। প্রথমে exit code দেখুন। এরপর logs দেখুন।
logs -f একই সময়ে প্রতিটি service অনুসরণ করে এবং প্রতিটি লাইনের শুরুতে service-এর নাম যোগ করে। Service-গুলো পরস্পরের সঙ্গে যোগাযোগ করলে এবং event-এর ক্রম গুরুত্বপূর্ণ হলে এই view-টিই প্রয়োজন। তালিকা সংকুচিত করতে একটি service-এর নাম দিন। এক মাস ধরে চালু থাকা container-এর ক্ষেত্রে --tail=100 গুরুত্বপূর্ণ, কারণ default পুরো history দেখায় এবং terminal ভরে দেয়। আপনি সাধারণত যে প্রশ্নের উত্তর চান, --since 15m সেটিই দেয়: আপনি এইমাত্র যে restart করেছেন, তার সময় কী ঘটেছিল।
top প্রতিটি container-এর ভেতরের process তালিকাভুক্ত করে। এতে "container চলছে" এবং "container-এর ভেতরের process চলছে"—এই দুই অবস্থার পার্থক্য বোঝা যায়। ls বর্তমান directory-এর বাইরে গিয়ে host-এর সব Compose project-এর status দেখায়। তাই তিন মাস আগে শুরু করা stack খুঁজে বের করা যায়।
একটি service-এর ভিতরে shell খোলা
docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web shexec ইতিমধ্যে চালু থাকা container-এর ভিতরে একটি command চালায়। run একই service definition থেকে একটি নতুন container চালু করে। service যথেষ্ট সময় চালু না থাকলে exec করার জন্য এটিই প্রয়োজন। সবসময় run-এর সঙ্গে --rm ব্যবহার করুন। এটি না দিলে প্রতিটি invocation-এর পরে একটি stopped container থেকে যায়। এগুলো জমতে জমতে শেষ পর্যন্ত docker compose ps -a পড়া কঠিন হয়ে যায়।
bash-এর আগে sh চেষ্টা করুন। Alpine ভিত্তিক image-এ bash থাকে না, তাই ব্যর্থতার বার্তায় exec: "bash": executable file not found in $PATH দেখা যায়। --no-deps-কে run-এ যোগ করলে service-এর dependency শুরু না করেই কাজ হয়। এতে দ্রুত configuration check করার সময় পুরো database চালু হয় না।
প্রতিটি .env file, environment: block এবং shell variable একত্র করার পরে service আসলে যে environment পেয়েছে, তা দেখার দ্রুততম উপায় হলো run --rm web env। কোনো value ভুল হলে সাধারণত merge order-ই কারণ। Compose কীভাবে env file এবং secret resolve করে-এ কোন source অগ্রাধিকার পায় তা ব্যাখ্যা করা হয়েছে।
নেটওয়ার্ক, port এবং name resolution
docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networksCompose একই project network-এ প্রতিটি service যুক্ত করে এবং সেখানে প্রতিটি service-এর নাম একটি DNS name হিসেবে কাজ করে। web-এর ভিতরে getent hosts db চালালে resolution সফল হলে container IP দেখা যায়, আর ব্যর্থ হলে কিছুই দেখা যায় না। তাই দুই সেকেন্ডের মধ্যে বোঝা যায়, “এই container-গুলো কি একে অপরকে দেখতে পারে?” নাম resolve হলেও connection refused হলে db-এর ভিতরের process 0.0.0.0-এর বদলে 127.0.0.1-এ bind করা আছে। তাই অন্য container থেকে আসা কোনো packet এটি গ্রহণ করে না। একই সীমা ব্যাখ্যা করে কেন project-এর বাইরে চালানো কোনো container—docker run দিয়ে চালানো হোক বা নিজস্ব stack হিসেবে—jellyfin-এর মতো কোনো নাম resolve করতে পারে না। আপনার Jellyfin library-এর জন্য একটি Halcyon front end যে server-এ নির্দেশ করা আছে, সেখানে পৌঁছাতে না পারলে প্রথমে এটিই পরীক্ষা করুন। এই মডেলের বাকি অংশ Compose network এবং service DNS কীভাবে কাজ করে-এ ব্যাখ্যা করা হয়েছে।
port web 80 দেখায়, কোনো container port host-এর কোন address ও port-এ publish করা হয়েছে। Mapping কোনো variable থেকে এলে অনুমান করতে হয় না। কোনো port publish করলে Docker নিজে পরিচালিত একটি firewall rule-ও তৈরি করে। সেই rule আপনার rule-এর আগে প্রয়োগ হয়। ফলে আপনি যে service-কে private মনে করেছিলেন, সেটি Internet-এর জন্য উন্মুক্ত হয়ে যেতে পারে। এই পরিস্থিতি কেন published Docker port ufw এড়িয়ে যায়-এ ব্যাখ্যা করা হয়েছে। ওই port-গুলো unpublished রেখে project network-এ service-গুলোর সামনে authentication করা একটি proxy বসানো বেশি নিরাপদ। একটি single sign-on layer হিসেবে Authentik চালানো এই কাঠামোই দেয়।
ভলিউম ও ডেটা
docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -vconfig --volumes প্রকল্পে ঘোষিত named volume-গুলো প্রতি লাইনে একটি করে দেখায়। যে ডেটার backup নিতে হবে, সেই তালিকাই এটি দেয়। কোনো volume-এ পুনরায় তৈরি করা অসম্ভব এমন ডেটা থাকলে, সঠিক backup command-এর গুরুত্ব তালিকার মতোই বেশি। তাই PhotoPrism ও Immich-এর তুলনা-তে প্রতিটি photo server-এর জন্য dump ও copy command স্পষ্টভাবে দেওয়া হয়েছে। cp shell না খুলেই container-এর ভেতরে বা বাইরে file copy করে। এর জন্য container যে পাশে আছে, সেই পাশে service:path form ব্যবহার করতে হয়।
down -v container-এর সঙ্গে ওই named volume-গুলোও মুছে ফেলে। test stack সরিয়ে ফেলার জন্য এটি সঠিক command। কিন্তু গুরুত্বপূর্ণ ডেটা থাকা stack-এর ক্ষেত্রে এটি ব্যবহার করা ভুল। কারণ কোনো confirmation নেই এবং undo করার উপায়ও নেই। Bind mount এতে প্রভাবিত হয় না, কারণ সেগুলো host filesystem-এ থাকে। এই blast radius-এর পার্থক্যই bind mount ও named volume-এর মধ্যে সচেতনভাবে নির্বাচন করার একটি কারণ।
ডেটা না হারিয়ে disk খালি করার cleanup
docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune--remove-orphans project-এর অন্তর্ভুক্ত, কিন্তু file-এ আর দেখা যায় না—এমন container মুছে দেয়। কোনো service-এর নাম পরিবর্তন করার পর ঠিক এই পরিস্থিতিই তৈরি হয়। এটি ব্যবহার না করলে ওই container-গুলো চলতেই থাকে এবং docker compose ps-এ দেখা যায় না।
কিছু মুছে ফেলার আগে docker system df disk space কোথায় ব্যবহৃত হয়েছে তা দেখায়। এটি image, container, local volume এবং build cache আলাদা করে দেখায় এবং প্রতিটির জন্য reclaim করা সম্ভব এমন space-এর পরিমাণ দেয়। image prune -a এমন সব image মুছে দেয়, যেগুলো কোনো tag নির্দেশ করে না। বড় image-এর একাধিক version pull করা server-এ সাধারণত এটিই সবচেয়ে বেশি space উদ্ধার করে। builder prune build cache পরিষ্কার করে। নিজের image build করে এমন যেকোনো server-এ এই cache ধীরে ধীরে বড় হয়।
এগুলোর কোনোটিই named volume-এ প্রভাব ফেলে না। শুধু docker volume prune এবং docker compose down -v named volume-এ প্রভাব ফেলে।
কোনো সমস্যা তৈরি করার আগে ফাইল পরীক্ষা করা
docker compose config --quiet
docker compose config --services
docker compose --dry-run up -dconfig --quiet সফল হলে কোনো আউটপুট দেয় না, তাই এটি deploy-এর আগে কোনো ধাপে বা git hook-এ রাখা উপযুক্ত। সাধারণ config সম্পূর্ণ merge ও interpolate করা ফাইলটি দেখায়। এভাবেই নিশ্চিত করা যায় যে কোনো variable-এর মান সঠিকভাবে নির্ধারিত হয়েছে এবং override file প্রত্যাশামতো স্তরবিন্যাস হয়েছে। unset variable সেখানে খালি মান হিসেবে দেখা যায়, এবং পাশে The "X" variable is not set. Defaulting to a blank string. সতর্কবার্তা থাকে।
--dry-run একটি global flag, subcommand flag নয়। তাই এটি up-এর আগে দিতে হয়। এটি Compose যে প্রতিটি action নিত, তা দেখায় কিন্তু কোনো পরিবর্তন করে না। গুরুত্বপূর্ণ stack-এ down চালানোর আগে এই ত্রিশ সেকেন্ড ব্যয় করা যুক্তিসঙ্গত।
ফাইল, profile এবং project নিয়ে কাজ করা
docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -dএকাধিক -f flag ক্রমানুসারে merge হয়, এবং পরের ফাইলগুলো key অনুযায়ী আগের ফাইলের মান প্রতিস্থাপন করে। একটি ছোট production override-সহ একটি base file রাখার এটিই প্রচলিত পদ্ধতি। তবে list এবং map-এর ক্ষেত্রে নিয়ম আলাদা। কোনো অপ্রত্যাশিত ফলাফল বিশ্লেষণ করার আগে Compose কীভাবে একাধিক ফাইল merge করে পড়ুন।
--profile-এর মাধ্যমে ওই profile-এ tag করা service-গুলো untagged service-এর সঙ্গে চালু হয়। এতে সাধারণ up-এর বাইরে debug tooling রাখা যায়। -p project-এর নাম নির্ধারণ করে। তাই একই stack-এর দুটি কপি আলাদা network এবং আলাদা volume name ব্যবহার করে পাশাপাশি চালানো যায়। reboot-এর পরে stack ফিরিয়ে আনার জন্য কোনো command টাইপ করতে হয় না। এর জন্য একটি unit স্বয়ংক্রিয়ভাবে চালু হয়। এই unit-এর বিবরণ boot-এর সময় Compose stack চালু করা-এ দেওয়া আছে।
FAQ
হাইফেন-যুক্ত docker-compose-এর পরিবর্তে কী এসেছে?
স্পেস দিয়ে লেখা docker compose, যা Compose V2 চালায়। এটি Docker Engine-এর সঙ্গে bundled একটি plugin, এবং বর্তমান package-গুলোতে V1 Python tool আর ইনস্টল করা হয় না। স্পেস-যুক্ত রূপে কোনো output না এলে আপনার distribution-এর জন্য docker-compose-plugin package ইনস্টল করুন। Alias যোগ না করে পুরোনো script-গুলো স্পেস-যুক্ত রূপে আপডেট করুন, কারণ V2-তে V1-এ না থাকা flag রয়েছে।
docker compose restart কেন আমার configuration পরিবর্তন গ্রহণ করছে না?
restart বিদ্যমান container-কে সেটি যে configuration দিয়ে তৈরি হয়েছিল, তা ব্যবহার করে stop এবং start করে; এটি কখনও compose.yaml আবার পড়ে না। Environment variable, port, volume বা image tag পরিবর্তন করলে docker compose up -d প্রয়োজন। এটি প্রতিটি service-কে তার চলমান container-এর সঙ্গে তুলনা করে এবং যেগুলোর মধ্যে পার্থক্য আছে সেগুলো নতুন করে তৈরি করে। File-এ কোনো পরিবর্তন না থাকলেও replacement করতে চাইলে --force-recreate যোগ করুন।
কোনো service-কে নতুন image-এ কীভাবে আপডেট করব?
প্রথমে docker compose pull, তারপর docker compose up -d চালান। Pull command file-এ থাকা প্রতিটি tag-এর বর্তমান image নিয়ে আসে, এবং up -d যেসব service-এর image ID তাদের container-এর সঙ্গে আর মেলে না, সেগুলো নতুন করে তৈরি করে। শুধু up -d চালালে disk-এ আগে থেকে থাকা image পুনরায় ব্যবহার করা হয়। তাই latest-এ pinned একটি stack কোনো error না দেখিয়েই কয়েক মাস পুরোনো build-এ চলতে পারে।
Live server-এ কোন cleanup command-গুলো নিরাপদ?
docker system df, docker image prune -a এবং docker builder prune শুধু image ও cache সরায়। তাই চলমান service কাজ করতে থাকে এবং named volume অপরিবর্তিত থাকে। বিপজ্জনক জোড়াটি হলো docker compose down -v এবং docker volume prune; এগুলো কোনো prompt ছাড়াই named volume মুছে দেয়। কী ঝুঁকিতে আছে তা জানার জন্য আগে docker compose config --volumes চালান।
পুরো stack চালু না করে কি একটি command চালাতে পারি?
হ্যাঁ। docker compose run --rm --no-deps web sh web service definition থেকে একটি container চালু করে, তার dependency-গুলো এড়িয়ে যায় এবং আপনি বের হলে container-টি সরিয়ে দেয়। Container আগে থেকেই চলমান থাকলে এর পরিবর্তে exec ব্যবহার করুন, কারণ exec চলমান process-এ যুক্ত হয় এবং service-এর প্রকৃত বর্তমান অবস্থা দেখায়।