راهنمای کاربردی دستورات Docker Compose برای سرور
لیست دستورات ضروری Docker Compose برای مدیریت چرخه حیات، لاگها و شبکهها در سرور. این راهنما بر اساس نسخه V2 تنظیم شده و از خطای رایج docker-compose.yml not found جلوگیری میکند.
دستورات Compose که واقعاً به آنها نیاز دارید
Docker Compose بیش از 40 زیردستور دارد. کارهای روزمره روی سرور تنها به حدود 12 مورد از آنها نیاز دارد. این صفحه دستورات را بر اساس وظیفهای که انجام میدهید دستهبندی کرده، برای هر کدام یک دلیل ساده ارائه میدهد و در مواردی که دستور ممکن است حاوی نکتهای پیچیده باشد، به بررسی دقیقتر ارجاع میدهد.
تمام موارد در اینجا از Compose V2 استفاده میکنند: docker compose با یک فاصله، نه اسکریپت قدیمی docker-compose. نسخه V2 یک پلاگین Go است که همراه با Docker Engine نصب میشود و نسخه V1 از بستههای فعلی حذف شده است، بنابراین اجرای docker-compose: command not found روی یک سیستمعامل Ubuntu تازه در ژوئیه 2026، مورد انتظار است و نباید با خطا مواجه شود. با استفاده از docker compose version وضعیت را بررسی کنید. اگر این دستور خروجی نداشت، بسته docker-compose-plugin را نصب کنید.
هر دستوری که در ادامه میآید باید از دایرکتوری حاوی فایل compose.yaml اجرا شود، زیرا Compose نام پروژه را از آن دایرکتوری میگیرد و فایل را نسبت به همان مسیر پیدا میکند. اگر همان دستور را یک سطح بالاتر اجرا کنید، Compose با خطای no configuration file provided: not found متوقف میشود. اگر فرمت فایل برای شما جدید است، با اولین فایل Compose روی یک VPS شروع کنید و سپس برای یادگیری دستورات به اینجا بازگردید.
چرخه حیات: چهار دستوری که تایپ میکنید و دستوری که کانتینرها را حذف میکند
docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose downup -d شبکه را ایجاد میکند، کانتینرها را میسازد، آنها را استارت میزند و سپس بازمیگردد. این دستور بلافاصله پس از ایجاد کانتینرها خاتمه مییابد؛ به همین دلیل است که اسکریپتهای استقرار که بلافاصله پس از آن از curl برای بررسی وضعیت استفاده میکنند، اغلب در تلاش اول با خطا مواجه میشوند. up -d --wait تا زمانی که تمام سرویسهایی که healthcheck تعریف کردهاند وضعیت سالم (healthy) را گزارش نکنند، منتظر میماند و اگر یکی از آنها به این وضعیت نرسد، با کد خروجی غیر صفر خارج میشود. کارایی این فلگ به کیفیت چکِ پشت آن بستگی دارد، بنابراین پیش از تکیه بر آن در اتوماسیون، یک healthcheck قابل اعتماد برای Compose بنویسید.
stop کانتینرها را متوقف میکند اما آنها را نگه میدارد، بنابراین start همان کانتینرها را با همان لایه قابل نوشتن (writable layer) دوباره بالا میآورد. down آنها را متوقف کرده و سپس کانتینرها و شبکه پروژه را حذف میکند. هر چیزی که داخل کانتینر و خارج از یک volume نوشته شده باشد، همراه با آنها از بین میرود. این پرهزینهترین سوءتفاهم در Compose است و تفاوت کامل بین down و stop توضیح میدهد که این موضوع کجا میتواند مشکلساز شود.
restart یک دستور reload نیست. این دستور همان کانتینر را با پیکربندی فعلیاش متوقف و دوباره استارت میزند، بنابراین تغییر در متغیرهای محیطی (environment variable)، تگ جدید image یا ویرایش نگاشت پورتها هیچ تأثیری نخواهد داشت. برای اعمال تغییرات فایل، باید دوباره up -d را اجرا کنید. Compose هر سرویس را با کانتینر در حال اجرای آن مقایسه کرده و فقط مواردی را که پیکربندیشان تغییر کرده است، بازسازی (recreate) میکند.
اعمال تغییرات: بازسازی، دریافت (pull) یا ساخت مجدد
docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build webدستور up -d بهتنهایی در صورت عدم تغییر، هیچ کاری انجام نمیدهد؛ همین ویژگی باعث میشود اجرای مکرر آن ایمن باشد. دستور --force-recreate این مقایسه را نادیده گرفته و تمام کانتینرها را حتی در صورت یکسان بودن پیکربندی جایگزین میکند، بنابراین سریعترین راه برای پاکسازی وضعیتهای غیرعادی درون کانتینر است.
بهروزرسانی یک ایمیج نیازمند دو دستور است زیرا دو کار متفاوت انجام میدهند. دستور pull ایمیج فعلی را برای هر تگ ذکر شده در فایل دانلود میکند. سپس up -d تشخیص میدهد که شناسه ایمیج سرویس با کانتینر در حال اجرای آن مطابقت ندارد و آن را بازسازی میکند. اگر مرحله pull را نادیده بگیرید، up -d همان نسخه ماه گذشته latest را بدون هیچ خطایی اجرا نگه میدارد. ریسک معکوس در stackهای چندسرویسی نمایان میشود؛ جایی که pull کردن latest برای همه سرویسها بهطور همزمان، میتواند برنامهای را که ده ثانیه پیش کار میکرد از کار بیندازد. به همین دلیل است که یک فضای کاری AFFiNE خودمیزبان هر یک از چهار تگ ایمیج خود را ثابت (pin) میکند.
دستور build برای سرویسهایی اعمال میشود که بهجای image:، بخش build: را تعریف کردهاند. دستور up -d --build در یک مرحله عملیات ساخت و اجرا را انجام میدهد که چرخه معمول هنگام تغییر کد است. تنها زمانی از --no-cache استفاده کنید که یک لایه کششده بهوضوح قدیمی شده باشد، زیرا این دستور تمام لایهها را از ابتدا بازسازی میکند.
مشاهده وضعیت سرویسهای در حال اجرا
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 فقط کانتینرهای در حال اجرا را فهرست میکند. سرویسی که در حین شروع دچار کرش شده باشد، تا زمانی که از -a استفاده نکنید در این لیست دیده نمیشود. بنابراین، اگر کانتینری در ps غایب است اما ps -a آن را با وضعیت Exited (1) نشان میدهد، این وضعیت معمولاً نشاندهنده شکست در فرآیند راهاندازی است. کد خروج (exit code) را بخوانید و سپس لاگها را بررسی کنید.
top پردازشهای داخل هر کانتینر را فهرست میکند؛ این کار باعث میشود وضعیت «کانتینر در حال اجراست» از وضعیت «پردازش داخل آن در حال اجراست» تفکیک شود. ls از دایرکتوری فعلی خارج شده و تمام پروژههای Compose موجود روی میزبان را به همراه وضعیتشان فهرست میکند تا بتوانید stackای را که سه ماه پیش راهاندازی کردهاید، پیدا کنید.
logs -f لاگهای تمام سرویسها را بهصورت همزمان دنبال میکند و نام سرویس را به ابتدای هر خط اضافه میکند؛ این همان نمایی است که هنگام تعامل سرویسها با یکدیگر و زمانی که ترتیب رویدادها اهمیت دارد، به آن نیاز دارید. برای محدود کردن خروجی، نام یک سرویس خاص را ذکر کنید. --tail=100 برای کانتینری که یک ماه است در حال اجرا بوده اهمیت دارد، زیرا حالت پیشفرض تمام تاریخچه را چاپ کرده و ترمینال را پر میکند. --since 15m به سوالی پاسخ میدهد که معمولاً در ذهن دارید: در طول restartای که همین الان انجام دادید، چه اتفاقی افتاده است؟
دسترسی به شل داخل یک سرویس
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 shدستور exec یک فرمان را درون کانتینری که از قبل در حال اجراست، اجرا میکند. دستور run یک کانتینر جدید از روی همان تعریف سرویس ایجاد میکند؛ این همان چیزی است که وقتی سرویس به اندازه کافی برای اجرای exec فعال نمیماند، به آن نیاز دارید. همیشه run را با --rm همراه کنید، زیرا بدون آن، هر بار اجرا یک کانتینر متوقفشده باقی میگذارد و این کانتینرها آنقدر انباشته میشوند که docker compose ps -a غیرقابل خواندن میشود.
پیش از bash، دستور sh را امتحان کنید. ایمیجهای مبتنی بر Alpine فاقد bash هستند و خطا به صورت exec: "bash": executable file not found in $PATH نمایش داده میشود. افزودن --no-deps به run باعث نادیده گرفتن وابستگیهای سرویس میشود که از راهاندازی کل دیتابیس شما هنگام یک بررسی سریع پیکربندی جلوگیری میکند.
دستور run --rm web env سریعترین راه برای مشاهده محیطی است که سرویس واقعاً دریافت کرده است؛ این پس از ادغام تمامی فایلهای .env، بلوکهای environment: و متغیرهای شل انجام میشود. وقتی مقداری اشتباه است، معمولاً دلیل آن ترتیب ادغام است و نحوه حل کردن فایلهای env و secret توسط Compose مشخص میکند که کدام منبع اولویت دارد.
شبکهها، پورتها و وضوح نام (Name Resolution)
docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networksابزار Compose هر سرویس را در یک شبکه پروژه قرار میدهد و هر نام سرویس، یک نام DNS در آن شبکه محسوب میشود. اجرای getent hosts db در داخل web، در صورت عملکرد صحیح وضوح نام، IP کانتینر را چاپ میکند و در صورت عدم موفقیت، خروجی خالی برمیگرداند؛ بنابراین این دستور در عرض 2 ثانیه پاسخ میدهد که «آیا این کانتینرها یکدیگر را میبینند یا خیر». اگر نام به درستی Resolve شود اما اتصال رد (Refused) شود، به این معناست که پردازش داخل db به جای 0.0.0.0، روی 127.0.0.1 متصل (Bind) شده است و به همین دلیل هرگز بستهای را از کانتینر دیگر نمیپذیرد. جزئیات بیشتر این مدل در نحوه عملکرد شبکههای Compose و DNS سرویسها آمده است.
دستور port web 80 آدرس میزبان و پورتی که پورت کانتینر روی آن منتشر شده است را چاپ میکند؛ این کار باعث میشود هنگام استفاده از نگاشتهای متغیر، نیازی به حدس زدن نباشد. انتشار یک پورت همچنین یک قانون فایروال ایجاد میکند که Docker خود آن را مدیریت میکند. این قانون پیش از قوانین شما قرار میگیرد، بنابراین سرویسی که تصور میکردید خصوصی است، ممکن است برای اینترنت باز باشد. این مورد در چرا پورتهای منتشر شده Docker از ufw عبور میکنند بررسی شده است. امنترین حالت این است که پورتها را منتشر نکنید و به جای آن، یک پروکسی احراز هویتکننده را در شبکه پروژه و در مقابل سرویسها قرار دهید؛ این همان چیزی است که در اجرای Authentik به عنوان لایه Single Sign-On به دست میآورید.
Volumeها و دادهها
docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -vconfig --volumes نام volumeهایی را که در پروژه تعریف شدهاند، به صورت یک مورد در هر خط چاپ میکند. این همان لیستی است که باید از آن نسخه پشتیبان تهیه کنید. زمانی که volumeها حاوی دادههای غیرقابل جایگزین هستند، دستور دقیق پشتیبانگیری به اندازه خودِ لیست اهمیت دارد؛ به همین دلیل است که مقایسه PhotoPrism و Immich دستورات dump و copy مورد نیاز برای هر سرور عکس را به تفصیل شرح میدهد. cp فایلی را بدون نیاز به باز کردن shell، به داخل یا خارج از یک container کپی میکند؛ برای این کار کافی است از فرمت service:path در سمتی که container قرار دارد استفاده کنید.
down -v آن volumeهای نامگذاری شده را به همراه containerها حذف میکند. این دستور برای پاکسازی یک stack آزمایشی مناسب است، اما برای هر چیزی که دادههای مهمی در آن دارید، دستور اشتباهی محسوب میشود؛ چرا که هیچ تأییدیهای دریافت نمیکند و امکان بازگشت (undo) نیز وجود ندارد. Bind mountها از این دستور جان سالم به در میبرند، زیرا روی فایلسیستم میزبان قرار دارند. این تفاوت در دامنه تخریب، یکی از دلایل انتخاب آگاهانه بین bind mountها و volumeهای نامگذاری شده است.
پاکسازی فضای دیسک بدون از دست دادن دادهها
docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune--remove-orphans کانتینرهایی را حذف میکند که متعلق به پروژه هستند اما دیگر در فایل تعریف نشدهاند؛ این دقیقاً همان وضعیتی است که پس از تغییر نام یک سرویس با آن مواجه میشوید. بدون استفاده از این دستور، آن کانتینرها به اجرای خود ادامه میدهند و برای docker compose ps غیرقابل مشاهده باقی میمانند.
docker system df پیش از حذف هر فایلی، نشان میدهد که فضای دیسک چگونه اشغال شده است و آن را به تفکیک تصاویر (images)، کانتینرها، volumeهای محلی و کش ساخت (build cache) به همراه مقدار فضای قابل بازیابی برای هر بخش نمایش میدهد. image prune -a تمام تصاویری را که هیچ تگی به آنها اشاره نمیکند حذف میکند؛ در سروری که نسخههای متعددی از یک تصویر حجیم را دریافت کرده است، این دستور معمولاً بیشترین فضای خالی را ایجاد میکند. builder prune کش ساخت را پاک میکند؛ این کش در هر سروری که تصاویر خود را میسازد، بهطور بیسروصدا رشد میکند.
هیچکدام از این دستورات به volumeهای نامگذاری شده (named volumes) دست نمیزنند. تنها docker volume prune و docker compose down -v این کار را انجام میدهند.
بررسی فایل پیش از بروز اختلال
docker compose config --quiet
docker compose config --services
docker compose --dry-run up -dدستور config --quiet فایل را اعتبارسنجی میکند و در صورت موفقیت خروجی نمیدهد؛ بنابراین باید در مرحله پیش از استقرار (pre-deploy) یا در یک git hook استفاده شود. دستور ساده config فایل نهایی که ادغام و جایگذاری شده است را نمایش میدهد؛ این روشی است که با آن تأیید میکنید متغیرها مقداردهی شدهاند و فایلهای override طبق انتظار اعمال شدهاند. متغیرهای مقداردهینشده در این خروجی به صورت مقدار خالی و در کنار هشدار The "X" variable is not set. Defaulting to a blank string. ظاهر میشوند.
پرچم --dry-run یک پرچم سراسری (global) است و نه یک پرچم زیردستور (subcommand)، بنابراین باید پیش از up قرار بگیرد. این پرچم تمام اقداماتی که Compose قصد انجام آن را دارد چاپ میکند و هیچ تغییری اعمال نمیکند؛ صرف 30 ثانیه زمان برای این کار پیش از اجرای down روی یک stack حساس، بسیار ارزشمند است.
کار با فایلها، پروفایلها و پروژهها
docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -dچندین فلگ -f به ترتیب با هم ادغام میشوند و فایلهای بعدی، کلیدهای فایلهای قبلی را بازنویسی میکنند. این روش استاندارد برای نگهداری یک فایل پایه به همراه یک فایل override کوچک برای محیط production است؛ هرچند قوانین برای لیستها و نگاشتها (maps) متفاوت است، بنابراین پیش از عیبیابی موارد غیرمنتظره، نحوه ادغام چندین فایل در Compose را مطالعه کنید.
فلگ --profile سرویسهای دارای آن پروفایل را در کنار سرویسهای بدون برچسب اجرا میکند، که باعث میشود ابزارهای دیباگ از اجرای عادی up دور بمانند. فلگ -p نام پروژه را تعیین میکند، بنابراین دو نسخه از یک stack میتوانند در کنار هم با شبکهها و نامهای volume مجزا اجرا شوند. بازگرداندن stack پس از reboot دستوری نیست که شما تایپ کنید، بلکه یک unit است که این کار را برای شما انجام میدهد و در اجرای stackهای Compose در زمان بوت توضیح داده شده است.
FAQ
چه چیزی جایگزین docker-compose با خط تیره شد؟
نسخه Compose V2 که با docker compose و با استفاده از فاصله فراخوانی میشود. این یک پلاگین است که همراه با Docker Engine ارائه میشود و ابزار پایتونی V1 دیگر در بستههای فعلی نصب نمیشود. اگر دستور با فاصله خروجی نداشت، بسته docker-compose-plugin را برای توزیع سیستمعامل خود نصب کنید. اسکریپتهای قدیمی را به جای تعریف alias، به فرمت جدید با فاصله بهروزرسانی کنید، زیرا V2 دارای فلگهایی است که V1 هرگز نداشت.
چرا docker compose restart تغییرات پیکربندی من را اعمال نمیکند؟
دستور restart کانتینر موجود را با همان پیکربندی اولیه متوقف و دوباره اجرا میکند و هرگز فایل compose.yaml را مجدداً نمیخواند. هر تغییری در متغیرهای محیطی، پورتها، ولومها یا تگ ایمیج نیازمند docker compose up -d است؛ این دستور هر سرویس را با کانتینر در حال اجرای آن مقایسه کرده و مواردی که تفاوت دارند را بازسازی میکند. اگر میخواهید جایگزینی حتماً انجام شود، حتی اگر تغییری در فایل ایجاد نشده باشد، از --force-recreate استفاده کنید.
چگونه یک سرویس را به ایمیج جدیدتر بهروزرسانی کنم؟
ابتدا docker compose pull و سپس docker compose up -d را اجرا کنید. دستور pull، ایمیج فعلی برای هر تگ موجود در فایل را دریافت میکند و up -d هر سرویسی که ID ایمیج آن با کانتینر در حال اجرا مطابقت نداشته باشد را بازسازی میکند. اجرای تنها دستور up -d باعث استفاده مجدد از ایمیج موجود روی دیسک میشود؛ به همین دلیل است که یک stack که روی latest قفل شده، ممکن است ماهها روی یک بیلد قدیمی باقی بماند بدون اینکه خطایی نمایش دهد.
کدام دستورات پاکسازی روی یک سرور زنده ایمن هستند؟
دستورات docker system df، docker image prune -a و docker builder prune فقط ایمیجها و کش را حذف میکنند، بنابراین سرویسهای در حال اجرا به کار خود ادامه میدهند و ولومهای نامگذاریشده (named volumes) دستنخورده باقی میمانند. جفت خطرناک، docker compose down -v و docker volume prune هستند که ولومهای نامگذاریشده را بدون پرسش حذف میکنند. ابتدا docker compose config --volumes را اجرا کنید تا بدانید چه چیزی در معرض خطر است.
آیا میتوانم یک دستور را بدون اجرای کل stack اجرا کنم؟
بله. دستور docker compose run --rm --no-deps web sh یک کانتینر تکی را از تعریف سرویس web اجرا میکند، وابستگیهای آن را نادیده میگیرد و پس از خروج، کانتینر را حذف میکند. زمانی که کانتینر از قبل در حال اجراست، از exec استفاده کنید، زیرا exec به پروسه در حال اجرا متصل میشود و وضعیت واقعی سرویس را به شما نشان میدهد.