تفاوت docker compose stop و down چیست؟
با تفاوت docker compose stop و down آشنا شوید: stop کانتینرها را نگه میدارد، down شبکه پروژه را حذف میکند و فقط down --volumes دادههای volume نامگذاریشده را پاک میکند.
پاسخ کوتاه
docker compose stop کانتینرها را متوقف میکند و آنها را روی دیسک باقی میگذارد. docker compose down کانتینرها را متوقف میکند و سپس کانتینرها و شبکهای را که Compose برای پروژه ایجاد کرده است حذف میکند. هیچیک از این فرمانها روی volume نامگذاریشده تأثیر نمیگذارند. پایگاه داده فقط زمانی حذف میشود که -v را اضافه کنید؛ مانند docker compose down -v که volumeهای نامگذاریشده اعلامشده در بخش volumes فایل Compose را حذف میکند.
تمام تفاوت در همین یک پاراگراف خلاصه میشود. در ادامه این راهنما، این تفاوت با یک volume مربوط به Postgres اثبات میشود؛ میتوانید باقیماندن آن پس از down و حذفشدن آن در اثر down -v را مشاهده کنید. همچنین دو موردی را توضیح میدهد که در آنها به --force-recreate نیاز دارید.
docker compose stop: کانتینرها باقی میمانند
stop به پردازش اصلی هر کانتینر SIGTERM ارسال میکند، مدتی منتظر میماند و اگر پردازش همچنان فعال باشد، سپس SIGKILL ارسال میکند. زمان انتظار پیشفرض 10 ثانیه است و -t آن را تغییر میدهد. هیچ چیزی حذف نمیشود. کانتینر شناسه، لایه قابلنوشتن، رزرو IP و گزارشهای خود را حفظ میکند.
docker compose stop
docker compose ps -adocker compose ps بهتنهایی فقط کانتینرهای در حال اجرا را نمایش میدهد. بنابراین پس از اجرای stop، یک جدول خالی نمایش داده میشود و ممکن است تصور کنید کانتینرها حذف شدهاند. ps -a کانتینرهای متوقفشده را نیز شامل میشود. در آنجا کنار هر سرویس، Exited (0) را مشاهده میکنید. کانتینرها را با docker compose start دوباره اجرا کنید؛ این دستور دقیقاً از همان کانتینرها استفاده میکند.
از آنجا که کانتینرها همچنان وجود دارند، هر چیزی که خارج از یک volume درون آنها نوشته شده باشد، باقی میماند. این موارد شامل بستهای است که با docker compose exec بهصورت دستی نصب کردهاید و فایل پیکربندیای که داخل کانتینر ویرایش کردهاید. به همین دلیل عملی، هنگام اشکالزدایی بهتر است از stop استفاده کنید: میتوانید سیستم را با همان وضعیت قبلی دوباره راهاندازی کنید.
docker compose down: کانتینرها و شبکهها حذف میشوند
down کانتینرها را متوقف میکند و سپس آنها را همراه با شبکه پیشفرضی که Compose برای پروژه ایجاد کرده است، حذف میکند. مستندات Docker این فرمان را بهصورت متوقفکردن کانتینرها و حذف کانتینرها، شبکهها، volumeها و imageهایی توصیف میکند که up ایجاد کرده است؛ اما حذف volumeها و imageها فقط زمانی انجام میشود که آنها را با -v و --rmi درخواست کنید.
docker compose down
docker compose ps -a
docker network lsپس از اجرای down، ps -a برای پروژه چیزی نمایش نمیدهد و شبکه <project>_default نیز حذف شده است. نام پروژه از نام پوشه گرفته میشود، مگر اینکه name: را در فایل Compose تنظیم کنید یا -p را ارسال کنید. هر تغییری که داخل لایه قابلنوشتن یک کانتینر ایجاد کردهاید، اکنون غیرقابلبازیابی است. بنابراین down را فرمانی در نظر بگیرید که کانتینر را کنار میگذارد و دادههایی را که در volumeها قرار دادهاید حفظ میکند.
اگر این فرمان را در پوشه اشتباه اجرا کنید، no configuration file provided: not found را دریافت میکنید. Compose نمیداند منظور شما کدام پروژه است و در نتیجه از ادامه کار خودداری میکند. وقتی در پوشه پروژه نیستید، از docker compose -f /srv/myapp/compose.yaml down استفاده کنید.
آیا volumes مربوط به down، volumeهای من را حذف میکند؟
خیر. یک volume نامگذاریشده که زیر کلید سطح بالای volumes تعریف شده است، پس از down نیز باقی میماند و از containerای که به آن متصل بوده است نیز بیشتر عمر میکند. این رایجترین نگرانی درباره این command است و پاسخ در Compose v2 ثابت است.
یک stack برای آزمایش آماده کنید. محتوای زیر را در فایل compose.yaml، داخل یک دایرکتوری خالی با نام voltest، قرار دهید.
services:
db:
image: postgres:16.4
restart: unless-stopped
environment:
POSTGRES_PASSWORD: example
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:آن را اجرا کنید و یک ردیف بنویسید تا بعداً بتوانید آن را تشخیص دهید.
docker compose up -d
sleep 10
docker compose exec -T db psql -U postgres -c "create table marker (note text);"
docker compose exec -T db psql -U postgres -c "insert into marker values ('survived');"اکنون container را حذف کنید و volume را بررسی کنید.
docker compose down
docker volume lsخروجی همچنان voltest_pgdata را فهرست میکند. container حذف شده است، اما دادهها باقی ماندهاند. stack را دوباره اجرا کنید و ردیف را بخوانید.
docker compose up -d
sleep 10
docker compose exec -T db psql -U postgres -c "select * from marker;"یک ردیف شامل survived دریافت میکنید. container جدید، container متفاوتی با ID متفاوت است که به همان volume متصل شده است. برای آشنایی با تصویر کلیتر، راهنمای مبانی Compose تفاوت volumeهای نامگذاریشده با bind mountها و محل واقعی هرکدام روی host را توضیح میدهد.
آنچه down -v دقیقاً از بین میبرد
-v (شکل کامل --volumes) volumeهای نامگذاریشدهای را که در بخش volumes فایل Compose تعریف شدهاند، بههمراه volumeهای ناشناس متصل به containerها حذف میکند. آن را روی همان stack اجرا کنید.
docker compose down -v
docker volume lsvoltest_pgdata دیگر فهرست نمیشود. stack را دوباره اجرا کنید تا entrypoint مربوط به Postgres یک data directory خالی پیدا کند و یک cluster جدید را مقداردهی اولیه کند. لاگ container این موضوع را بهصراحت نشان میدهد.
The files belonging to this database system will be owned by user "postgres".
PostgreSQL init process complete; ready for start up.دیدن این بخش در stackای که ماهها در حال اجرا بوده است، یعنی volume حذف شده است. جدول marker شما از بین رفته است و تنها راه بازگشت، استفاده از backup است.
برخی storageها هرگز با -v حذف نمیشوند. bind mount یک مسیر روی host است؛ بنابراین Docker فقط آن را unmount میکند و فایلهای شما در محل خود باقی میمانند. volumeای که با external: true علامتگذاری شده است، متعلق به چیزی خارج از این پروژه اعلام میشود و Compose هرگز آن را حذف نمیکند. named volumeای که پیش از اجرای down -v از فایل Compose حذف کردهاید، دیگر در فایل تعریف نشده است؛ بنابراین Compose از وجود آن برای حذفکردن آگاه نیست و آن volume بهعنوان orphan برای docker volume prune باقی میماند.
این حالت هنگام refactor افراد را دچار مشکل میکند. یک service و volume آن را از فایل حذف کنید و down -v را اجرا کنید؛ volume باقی میماند، چون فایل دیگر به آن اشاره نمیکند. down -v را پیش از ویرایش فایل اجرا کنید، نه پس از آن.
چه زمانی واقعاً به --force-recreate نیاز دارید
docker compose up -d هر بار همهچیز را از نو ایجاد نمیکند. Compose یک hash از پیکربندی نهایی هر service را بهعنوان label روی container ذخیره میکند. اگر hash و image ID یکسان باشند، container بدون تغییر باقی میماند و بهجای Recreated، Container voltest-db-1 Running را دریافت میکنید. این رفتار تقریباً همیشه مطلوب است، چون اجرای مکرر up -d را ایمن میکند.
به همین دلیل است که بعضی ویرایشها ظاهراً هیچ اثری ندارند. Compose تعریف نهایی service را hash میکند، نه محتوای فایلهایی را که این تعریف به آنها اشاره میکند. اگر یک config file در container mount شده باشد و فقط هنگام startup خوانده شود، ویرایش آن باعث recreate نمیشود، چون مسیر mount تغییر نکرده است. service با همان مقادیری که هنگام boot خوانده بود به اجرای خود ادامه میدهد.
docker compose up -d --force-recreateاین دستور هر container را متوقف و حذف میکند و سپس container جدیدی را بر اساس همان تعریف ایجاد میکند. پس از ویرایش یک config file که mount شده است، و همچنین زمانی که وضعیت یک container به حالتی نامشخص تغییر کرده است، از آن استفاده کنید. Volumes دستنخورده باقی میمانند؛ بنابراین database در force recreate حفظ میشود. برای دریافت image جدیدتر با همان tag، باید pull را نیز اجرا کنید.
docker compose pull
docker compose up -dpull image ID جدید را دریافت میکند و سپس up -d متوجه میشود image ID با container در حال اجرا متفاوت است و container را بهصورت خودکار recreate میکند. افزودن --force-recreate بدون pull، container جدیدی را از همان image قدیمی ایجاد میکند. به همین دلیل، شکایت «force recreate کردم، اما هنوز همان نسخه قدیمی است» بسیار رایج است.
docker compose restart هیچیک از این کارها را انجام نمیدهد. این دستور containerهای موجود را restart میکند و اصلاً فایل Compose را دوباره نمیخواند؛ بنابراین تغییر environment variable یا تغییر port mapping اعمال نخواهد شد. اگر فایل را ویرایش کردهاید، از up -d استفاده کنید.
الگوی ذهنی مهم
کانتینرها قابل جایگزینی هستند. کانتینر از یک فرایند و یک لایه قابلنوشتن نازک تشکیل میشود و Compose میتواند نمونهای یکسان را از فایل، تقریباً در 1 ثانیه ایجاد کند. Volumeها قابل جایگزینی نیستند، زیرا تنها نسخه وضعیت را نگه میدارند؛ هیچ فایلی در مخزن شما نمیتواند این وضعیت را دوباره ایجاد کند.
هر فعل Compose با همین تفکیک مطابقت دارد. stop و start کانتینر را حفظ میکنند. down و up کانتینر را جایگزین میکنند و Volume را حفظ میکنند. down -v تنها فرمان معمولی است که وضعیت را حذف میکند؛ به همین دلیل به یک flag صریح نیاز دارد. پیش از اجرای آن روی هر محیط واقعی، تأیید کنید که یک backup دارید و دستکم یک بار آن را بازیابی کردهاید.
همین منطق درباره secretها نیز صدق میکند. گذرواژهای که از طریق POSTGRES_PASSWORD تنظیم میشود، فقط هنگام نخستین راهاندازی database خوانده میشود. بنابراین، اگر آن را در فایل environment تغییر دهید و up -d را اجرا کنید، نتیجه password authentication failed for user "postgres" خواهد بود. کانتینر جدید است، اما Volume قدیمی است و Volume قدیمی همچنان گذرواژه قبلی را نگه میدارد. نحوه resolve کردن فایلهای env و secretها توسط Compose توضیح میدهد وقتی یک متغیر دو بار تنظیم شده باشد، کدام لایه اولویت دارد.
حالتهای خرابی و پیامهایی که مشاهده خواهید کرد
no configuration file provided: not found به این معناست که Compose در پوشهای اجرا میشود که نه compose.yaml و نه docker-compose.yml را دارد. -f را همراه با مسیر کامل وارد کنید.
network voltest_default has active endpoints روی down به این معناست که یک کانتینر خارج از این پروژه به شبکه پروژه متصل است. این کانتینر معمولاً با docker run --network بهصورت دستی راهاندازی شده است. آن کانتینر را حذف کنید، سپس دوباره down را اجرا کنید.
Found orphan containers ([voltest-old-1]) for this project پس از تغییر نام یا حذف یک سرویس ظاهر میشود. کانتینر قدیمی هنوز برچسب پروژه را دارد. docker compose down --remove-orphans آنها را پاک میکند و اجرای آن روی یک پشته سالم بیخطر است.
Error response from daemon: remove voltest_pgdata: volume is in use هنگام اجرای دستی docker volume rm به این معناست که یک کانتینر هنوز به volume ارجاع میدهد؛ حتی اگر متوقف شده باشد. ابتدا docker compose down را اجرا کنید، سپس volume را حذف کنید، یا فقط از down -v استفاده کنید. در پروژههای بزرگتر، یک پشته چندسرویسی Compose نشان میدهد که یک پروژه ممکن است چه تعداد volume ایجاد کند.
FAQ
آیا down پایگاه داده من را حذف میکند؟
اگر پایگاه داده در یک volume نامگذاریشده یا bind mount قرار داشته باشد، حذف نمیشود. down کانتینرها و network پروژه را حذف میکند، اما volume همراه با دادههای سالم روی دیسک باقی میماند. اجرای بعدی docker compose up -d یک کانتینر جدید را به همان volume متصل میکند و دادهها در دسترس هستند. فقط docker compose down -v volumeهای نامگذاریشده را حذف میکند؛ آن هم فقط volumeهایی را که در بخش volumes فایل Compose تعریف شدهاند.
تفاوت stop و down برای کانتینری که میخواهم دوباره از آن استفاده کنم چیست؟
stop کانتینر را حفظ میکند؛ بنابراین docker compose start شما را به همان کانتینر، با همان لایه قابلنوشتن، بازمیگرداند. هر چیزی که بهصورت دستی داخل کانتینر نصب یا ویرایش کرده باشید، همچنان باقی میماند. down کانتینر را حذف میکند؛ بنابراین اجرای بعدی up -d یک کانتینر جدید را از image ایجاد میکند و تغییرات دستی از بین میروند. هنگام عیبیابی از stop استفاده کنید.
چگونه همه چیزهایی را که یک پروژه Compose ایجاد کرده است حذف کنم؟
docker compose down -v --rmi all --remove-orphans کانتینرها، network پروژه، volumeهای نامگذاریشده تعریفشده در فایل، imageهای استفادهشده توسط سرویسها و هر کانتینری را که هنوز با نام پروژه برچسبگذاری شده باشد حذف میکند. این دستور به bind mountها یا volumeهای علامتگذاریشده با external: true دست نمیزند. پیش از اجرای آن، با docker volume ls مواردی را که قرار است از دست بدهید بررسی کنید.
چرا کانتینر من تغییری را که در فایل پیکربندی mountشده ایجاد کردهام نادیده میگیرد؟
Compose برای تصمیمگیری درباره ایجاد دوباره کانتینر، hash مربوط به تعریف resolveشده سرویس را مقایسه میکند. محتوای فایل mountشده در این hash لحاظ نمیشود. چون مسیر تغییر نکرده است، Compose کانتینر را در حال اجرا نگه میدارد و همان مقادیری را استفاده میکند که هنگام راهاندازی خوانده بود. docker compose up -d --force-recreate را اجرا کنید تا کانتینر جدیدی ایجاد شود که فایل را دوباره بخواند.
چرا POSTGRES_PASSWORD جدید من پس از تغییر، کار نمیکند؟
image مربوط به Postgres فقط هنگام مقداردهی اولیه یک data directory خالی، POSTGRES_PASSWORD را میخواند. volume شما از قبل یک cluster مقداردهیشده دارد؛ بنابراین این متغیر نادیده گرفته میشود و رمزعبور قبلی همچنان معتبر است. password authentication failed for user "postgres" را مشاهده خواهید کرد. رمزعبور را با ALTER USER در پایگاه داده در حال اجرا تغییر دهید، یا اگر پذیرش از دست رفتن دادهها برایتان قابلقبول است، با docker compose down -v از ابتدا شروع کنید.