رفتن به محتوا
LoopX

پاک‌سازی و مدیریت فضا

توی این درس یاد می‌گیری داکر در طول زمان چه چیزهایی روی دیسک جمع می‌کند (کانتینرهای متوقف، image های بی‌صاحب، volume ها و کش build)، چطور با docker system df میزان فضا را می‌بینی و با docker image prune، docker system prune و docker volume prune تمیزش می‌کنی، و مهم‌تر: چه چیزی را هرگز بی‌فکر پاک نکنی. همه‌ی دستورهای این درس روی یک daemon آزمایشی و ایزوله اجرا شده‌اند تا داکر اصلی‌ات دست نخورد.

داکر مثل انباری است که هر بار چیزی می‌خری (image می‌گیری)، کار می‌کنی (کانتینر می‌سازی) یا چیزی ذخیره می‌کنی (volume)، به آن اضافه می‌شود. آدم‌ها اغلب چیزهای بی‌مصرف را نگه می‌دارند: جعبه‌های خالی (کانتینر متوقف)، وسایلی که نسخه‌ی جدیدشان آمده (image های قدیمی)، و پوشه‌های ناشناس. تمیزکاری لازم است، ولی باید بدانی کدام جعبه‌ها خالی‌اند و کدام عکس‌های خانوادگی (داده‌ی volume).

چه چیزهایی جمع می‌شود؟

Section titled “چه چیزهایی جمع می‌شود؟”
چهار دسته چیزی که داکر روی دیسک نگه می‌دارد؛ هر کدام دستور پاک‌سازی و سطح خطر خودش را دارد.

همه‌ی مثال‌ها داخل یک daemon آزمایشی هستند. اول یک وضعیت «شلوغ» می‌سازیم:

مثال ۱: ببین چقدر جا گرفته (docker system df)

Section titled “مثال ۱: ببین چقدر جا گرفته (docker system df)”
Terminal window
docker system df
خروجی
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 3 1 13.62MB 23.29kB (0%)
Containers 3 1 12.29kB 8.192kB (66%)
Local Volumes 3 0 14B 14B (100%)
Build Cache 5 0 13.54MB 12.29kB

چهار ردیف: Images، Containers، Local Volumes و Build Cache. ستون RECLAIMABLE یعنی «چقدرش را می‌شود بدون آسیب به چیزهای در حال استفاده پاک کرد». برای جزئیات هر مورد -v را اضافه می‌کنی:

Terminal window
docker system df -v 2>/dev/null | head -14
خروجی
Images space usage:
REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS
lx-app latest fda8fde4ab76 4 seconds ago 13.5MB 13.5MB 11.72kB 0
<none> <none> 31e7285c9ab6 6 seconds ago 13.5MB 13.5MB 11.58kB 0
alpine latest 294b683cb724 2 weeks ago 13.6MB 13.5MB 87.52kB 3
Containers space usage:
CONTAINER ID IMAGE COMMAND LOCAL VOLUMES SIZE CREATED STATUS NAMES
240eda947938 alpine "true" 0 4.1kB 3 seconds ago Exited (0) 2 seconds ago old2
21fdac2c6385 alpine "true" 0 4.1kB 3 seconds ago Exited (0) 2 seconds ago old1
5a5c907ecbaf alpine "sleep 600" 0 4.1kB 3 minutes ago Up 3 minutes live1

image ای که اسم و tag ندارد (مثلاً نتیجه‌ی docker build . بدون -t، یا نسخه‌ی قدیمی‌ای که اسمش را از دست داده) dangling (آویزان) است. در این نسخه‌ی داکر به‌صورت پیش‌فرض در docker images دیده نمی‌شوند و باید فیلتر بدهی:

Terminal window
docker images
echo "--- فقط dangling:"
docker images -f dangling=true
خروجی
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
alpine:latest 294b683cb724 13.6MB 4.28MB U
lx-app:latest fda8fde4ab76 13.5MB 4.19MB
--- فقط dangling:
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
<untagged> 31e7285c9ab6 13.5MB 4.19MB

بدون فیلتر فقط alpine و lx-app (که اسم دارند) را می‌بینی، ولی فیلتر یک image با اسم <untagged> نشان می‌دهد؛ همان docker build . اولی. این‌ها بی‌صاحب‌اند و پاک کردنشان امن است:

Terminal window
docker image prune -f | tail -1
echo "dangling باقی‌مانده: $(docker images -f dangling=true -q | wc -l | tr -d ' ')"
خروجی
Total reclaimed space: 12.32kB
dangling باقی‌مانده: 0

مثال ۳: کانتینرهای متوقف‌شده

Section titled “مثال ۳: کانتینرهای متوقف‌شده”
Terminal window
docker ps -a --format 'table {{.Names}}\t{{.Status}}'
docker container prune -f
echo "--- بعد از prune:"
docker ps -a --format 'table {{.Names}}\t{{.Status}}'
خروجی
NAMES STATUS
old2 Exited (0) 2 seconds ago
old1 Exited (0) 3 seconds ago
live1 Up 3 minutes
Deleted Containers:
240eda9479387d0814ea01e08ccbfc00e2f6770cf2703f709d63e13d8ae0ad0a
21fdac2c6385638bca2c779c68ed184c54f3e7ba05404c75cd411b53be35355d
Total reclaimed space: 8.192kB
--- بعد از prune:
NAMES STATUS
live1 Up 3 minutes

کانتینرهای old1 و old2 (متوقف) پاک شدند و live1 (در حال اجرا) دست نخورد. docker container prune هرگز کانتینر در حال اجرا را پاک نمی‌کند. می‌توانی با --filter "until=24h" فقط قدیمی‌ها را حذف کنی.

⚡ بررسی سریع

docker container prune کدام کانتینرها را حذف می‌کند؟

مثال ۴: volume ها، جایی که باید دقت کنی

Section titled “مثال ۴: volume ها، جایی که باید دقت کنی”
Terminal window
docker volume ls
docker volume prune -f
echo "--- بعد از prune:"
docker volume ls
خروجی
DRIVER VOLUME NAME
local 41d6ccee33d53ac0bf32c7fd7e9b265e08e084e14a1c72a605cc05bdc0673965
local important
local keepme
Deleted Volumes:
41d6ccee33d53ac0bf32c7fd7e9b265e08e084e14a1c72a605cc05bdc0673965
Total reclaimed space: 0B
--- بعد از prune:
DRIVER VOLUME NAME
local important
local keepme

volume ناشناس (با اسم طولانی هش‌مانند، که با -v /d ساخته شد و کانتینرش حذف شد) پاک شد، ولی volume نام‌دار keepme (که داده‌ی ارزشمندی داشت) ماند. از نسخه‌های جدید داکر، docker volume prune به‌صورت پیش‌فرض فقط volume های ناشناس را حذف می‌کند و برای پاک کردن همه‌ی volume های بدون کانتینر باید -a بدهی. ببین اگر -a بدهی چه می‌شود:

Terminal window
docker volume prune -a -f
docker volume ls
خروجی
Deleted Volumes:
keepme
important
Total reclaimed space: 14B
DRIVER VOLUME NAME

حالا keepme هم رفت، و با آن precious که داخلش بود. این پاک کردن برگشت‌پذیر نیست. (برای همین گفتیم قبل از -a مطمئن شو.)

مثال ۵: پاک‌سازی عمومی (docker system prune)

Section titled “مثال ۵: پاک‌سازی عمومی (docker system prune)”

اگر بدون -f اجرا کنی، اول یک هشدار و درخواست تأیید می‌بینی. ببین چه چیزی قرار است پاک شود (من «n» می‌دهم تا چیزی پاک نشود):

Terminal window
docker run --rm alpine true
docker run --name old3 alpine true >/dev/null
echo n | docker system prune 2>&1 | head -9
خروجی
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- unused build cache
Are you sure you want to continue? [y/N]

متن هشدار فهرست دسته‌های قابل پاک شدن را می‌گوید. بعد با -f (تأیید خودکار) اجرا می‌کنیم:

Terminal window
docker system prune -f
خروجی
Deleted Containers:
09da0c11e69e5b79cae4b343b26c8c6139fe2ed97d77988e2fa904224894e0c0
Deleted build cache objects:
jxk643n34rvothnh1lnbsqhah
oz4lozpokb6yfnw4giepo3jjw
kafkqjzmmlgss8m73n5ba1xqt
Total reclaimed space: 28.78kB

دقت کن که این دستور volume ها را پاک نمی‌کند (مگر --volumes بدهی) و image های در حال استفاده هم دست نمی‌خورند. گزینه‌ی -a علاوه بر dangling، همه‌ی image های «بدون کانتینر» را هم پاک می‌کند.

مثال ۶: image های unused با -a و کش build

Section titled “مثال ۶: image های unused با -a و کش build”
Terminal window
docker images --format 'table {{.Repository}}\t{{.Tag}}'
docker image prune -a -f
echo "--- بعد از prune -a:"
docker images --format 'table {{.Repository}}\t{{.Tag}}'
خروجی
REPOSITORY TAG
lx-app latest
alpine latest
Deleted Images:
untagged: lx-app:latest
deleted: sha256:fda8fde4ab7695470c973df6035268db53cab310e7cac7b4c47c7d7e8a622ec6
deleted: sha256:01aedb111fb5cf1351b0aa428b73b3ea44ea1c0771426690d118129f3bee30dc
deleted: sha256:2ab380819c686cb0656fa1beaa6428fdbb3b98613b56399c00b5d6c3378be721
Total reclaimed space: 12.47kB
--- بعد از prune -a:
REPOSITORY TAG
alpine latest

image lx-app که هیچ کانتینری از آن نمی‌ساخت پاک شد؛ ولی alpine که کانتینر live1 در حال استفاده از آن است ماند. و کش build:

Terminal window
docker builder prune -f
docker system df | head -2
خروجی
ID RECLAIMABLE SIZE LAST ACCESSED
xmjzy00wrf9k58vhiu4cxyj26 true 12.39kB 6 seconds ago
Total: 12.39kB
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 1 1 13.6MB 0B (0%)

پشت پرده: «بی‌استفاده» یعنی چه؟

Section titled “پشت پرده: «بی‌استفاده» یعنی چه؟”

داکر هر چیزی را از نظر ارجاع می‌سنجد:

  • image dangling: بدون اسم و tag (<none>).
  • image unused: هیچ کانتینری (حتی متوقف) از آن ساخته نشده.
  • volume unused: هیچ کانتینری به آن وصل نیست.
  • کانتینر: متوقف‌شده.

چون لایه‌ها بین image ها مشترک‌اند، پاک کردن یک image فقط لایه‌هایی را آزاد می‌کند که هیچ image دیگری استفاده نمی‌کند؛ پس مجموع RECLAIMABLE همیشه با جمع حجم‌های روی کاغذ نمی‌خواند. و چون volume ها داده‌ی کاربر هستند، داکر آن‌ها را جدا از بقیه حساب می‌کند.

دستور چه چیزی را پاک می‌کند ریسک
docker container prune کانتینرهای متوقف کم
docker image prune image های dangling کم
docker image prune -a همه‌ی image های بدون کانتینر متوسط (دوباره دانلود)
docker volume prune volume های ناشناس بی‌کانتینر متوسط
docker volume prune -a همه‌ی volume های بی‌کانتینر زیاد (داده)
docker builder prune کش build کم
docker network prune شبکه‌های بدون استفاده کم
docker system prune کانتینر + image dangling + شبکه + کش کم تا متوسط
docker system prune -a --volumes کانتینر متوقف + همه‌ی image های بدون کانتینر + volume های ناشناس متوسط تا زیاد

گزینه‌های مفید: -f (بدون سؤال)، --filter "until=24h" (فقط قدیمی‌تر از ۲۴ ساعت).

Terminal window
docker volume create important >/dev/null
docker run --rm -v important:/d alpine sh -c 'echo data > /d/f'
docker system prune -af --volumes >/dev/null
echo "بعد از system prune --volumes: $(docker volume ls -q | grep -c important)"
docker volume prune -a -f >/dev/null
echo "بعد از volume prune -a: $(docker volume ls -q | grep -c important)"
خروجی
بعد از system prune --volumes: 1
بعد از volume prune -a: 0

system prune --volumes فقط volume های ناشناس را می‌برد و important ماند؛ ولی docker volume prune -a آن را (چون کانتینری نداشت) برای همیشه پاک کرد. راه‌حل: -a را هیچ‌وقت در اسکریپت‌های خودکار نگذار؛ از volume های مهم جدا بکاپ بگیر.

۲) docker rm $(docker ps -aq) به‌جای prune

Section titled “۲) docker rm $(docker ps -aq) به‌جای prune”
Terminal window
docker run -d --name keep1 alpine sleep 600 >/dev/null
docker run --name gone1 alpine true >/dev/null
docker rm $(docker ps -aq) 2>&1 | tail -3
خروجی
036648fe48a4
Error response from daemon: cannot remove container "f5fd4c7cf056": container is running: stop the container before removing or force remove
Error response from daemon: cannot remove container "5a5c907ecbaf": container is running: stop the container before removing or force remove

این الگوی قدیمی همه‌ی کانتینرها را هدف می‌گیرد؛ برای در حال اجرا خطا می‌دهد (و آنچه ممکن است حذف می‌کند). راه‌حل: docker container prune فقط متوقف‌شده‌ها را می‌گیرد.

۳) پاک کردن image در حال استفاده

Section titled “۳) پاک کردن image در حال استفاده”
Terminal window
docker rmi alpine 2>&1 | head -2
docker rm -f keep1 gone1 >/dev/null
خروجی
Error response from daemon: conflict: unable to delete alpine:latest (must be forced) - container f5fd4c7cf056 is using its referenced image 294b683cb724

تا کانتینری از image استفاده می‌کند، docker rmi آن را پاک نمی‌کند (conflict). راه‌حل: اول کانتینر را حذف کن.

۴) تعجب از اینکه prune فضا را آزاد نکرد

Section titled “۴) تعجب از اینکه prune فضا را آزاد نکرد”

چیزی که هنوز یک ارجاع دارد (یک کانتینر متوقف، یک image دیگر روی همان لایه‌ها) آزاد نمی‌شود. با docker system df -v ببین چه چیزی هنوز به چه چیزی وصل است.

✎ تمرینآسان

روی daemon آزمایشی وضعیت فضا را با docker system df نشان بده.

دیدن جواب
Terminal window
docker system df
خروجی
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 1 1 13.6MB 0B (0%)
Containers 1 1 4.096kB 0B (0%)
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
✎ تمرینمتوسط

تمرین اصلی: فضای داکر را بررسی و امن پاک‌سازی کن. دو کانتینر متوقف بساز، فهرستشان کن، فقط آن‌ها را پاک کن و ثابت کن کانتینر در حال اجرا (runner) دست نخورد.

دیدن جواب
Terminal window
docker run -d --name runner alpine sleep 300 >/dev/null
docker run --name s1 alpine true >/dev/null
docker run --name s2 alpine true >/dev/null
docker ps -a --format '{{.Names}}: {{.Status}}'
docker container prune -f >/dev/null
echo "--- بعد:"
docker ps -a --format '{{.Names}}: {{.Status}}'
docker rm -f runner >/dev/null
خروجی
s2: Exited (0) Less than a second ago
s1: Exited (0) Less than a second ago
runner: Up 1 second
live1: Up 3 minutes
--- بعد:
runner: Up 1 second
live1: Up 4 minutes
✎ تمرینسخت

یک volume نام‌دار precious با فایلی داخلش بساز. ثابت کن docker volume prune -f (بدون -a) آن را پاک نمی‌کند، ولی docker volume prune -a -f پاکش می‌کند. بعد توضیح بده چرا برای سرور production هیچ‌وقت نباید -a در اسکریپت خودکار باشد.

دیدن جواب
Terminal window
docker volume create precious >/dev/null
docker run --rm -v precious:/d alpine sh -c 'echo data > /d/f'
docker volume prune -f >/dev/null
echo "بعد از prune ساده: $(docker volume ls --format '{{.Name}}' | grep -c precious)"
docker volume prune -a -f >/dev/null
echo "بعد از prune -a: $(docker volume ls --format '{{.Name}}' | grep -c precious)"
خروجی
بعد از prune ساده: 1
بعد از prune -a: 0

با -a هر volume ای که الان به کانتینری وصل نباشد حذف می‌شود، حتی اگر داده‌ی ارزشمند باشد؛ در یک اسکریپت خودکار ممکن است لحظه‌ای که کانتینر دیتابیس متوقف است اجرا شود و داده را نابود کند.

؟ آزمونک
  1. image «dangling» چیست؟

  2. docker system prune به‌طور پیش‌فرض کدام را پاک نمی‌کند؟

  3. ستون RECLAIMABLE در docker system df یعنی…

  4. کدام دستور می‌تواند داده‌ی ارزشمند volume را برای همیشه پاک کند؟

  5. قبل از prune روی سرور واقعی اول چه کنی؟

  • داکر کانتینر متوقف، image های dangling/unused، volume ها و کش build را جمع می‌کند؛ با docker system df ببین.
  • docker container prune و docker image prune امن‌اند؛ docker image prune -a image های بدون کانتینر را هم می‌برد.
  • volume ها داده‌ی تو هستند: docker volume prune فقط ناشناس‌ها را می‌برد و -a همه‌ی بی‌کانتینرها را.
  • docker system prune کانتینر + dangling + شبکه + کش را پاک می‌کند؛ --volumes فقط volume های ناشناس را می‌برد و -a همه‌ی image های بدون کانتینر را. docker volume prune -a است که volume های نام‌دار را هم می‌برد.
  • همیشه اول بخوان، بعد پاک کن؛ و از volume های مهم بکاپ بگیر.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
docker system dfخلاصه‌ی فضای اشغال‌شده
docker system df -vجزئیات هر image/کانتینر/volume
docker container prune -fحذف کانتینرهای متوقف
docker image prune -fحذف image های dangling
docker image prune -a -fحذف همه‌ی image های بدون کانتینر
docker volume prune -fحذف volume های ناشناس بی‌کانتینر
docker volume prune -a -fحذف همه‌ی volume های بی‌کانتینر (خطرناک!)
docker builder prune -fپاک کردن کش build
docker system prune -fپاک‌سازی عمومی (بدون volume)
docker system prune --filter "until=24h"فقط چیزهای قدیمی‌تر از ۲۴ ساعت