اعمل تنظيف آمن لمساحة Docker بدل ما القرص يتملي
هتطلع من المقال بروتين واضح ينضف مساحة Docker بدون ما تمسح volumes مهمة أو تكسر بيئة التطوير.
مستوى القارئ: متوسط
المشكلة باختصار
اللي بيحصل فعلاً إن Docker بيحتفظ بـ images وcontainers وcache لفترة طويلة. ده مفيد لو بتبني نفس المشروع كتير، لكنه بيتحول لمشكلة لما لابتوب المطور أو runner بتاع CI يوصل لـ 90% disk usage.
سيناريو واقعي: عندك runner بيبني 12 branch يوميًا، وكل build بيسيب image حجمها 1.5GB. بعد أسبوع واحد ممكن تلاقي 42GB مستخدمة في Docker لو مفيش تنظيف دوري. الطريقة الشائعة الغلط هي تشغيل docker system prune -a --volumes وخلاص. الطريقة دي بتفشل لأنها ممكن تمسح volumes فيها قواعد بيانات محلية أو ملفات test fixtures محتاجها.
الفكرة: قِس، اعرض، ثم احذف بحذر
ركز: التنظيف الآمن مش أمر واحد. هو 3 مراحل. الأول تقيس باستخدام docker system df. بعد كده تعرض images القديمة اللي هتتشال. وفي الآخر تستخدم docker image prune مع فلتر زمني واضح مثل until=168h.
حسب توثيق Docker، أمر docker image prune يحذف dangling images افتراضيًا، ومع -a يحذف كل images غير المستخدمة بواسطة containers. الفلتر until يخلي الحذف مرتبطًا بعمر image بدل قرار عشوائي. الـ trade-off هنا واضح: هتكسب مساحة بسرعة، لكن أول build بعد التنظيف ممكن يكون أبطأ من 2 إلى 8 دقائق لأنه هيعيد تنزيل layers.
الخطوات التنفيذية
- افتح terminal على machine فيها Docker شغال.
- قِس الوضع الحالي قبل أي حذف.
- اعرض images القديمة قبل الحذف، وراجع القائمة بعينك.
- احذف images الأقدم من 7 أيام فقط.
- اقرأ المساحة بعد الحذف وسجل الفرق.
- لو النتيجة مناسبة، شغّلها أسبوعيًا من cron أو GitHub runner maintenance job.
#!/usr/bin/env bash
set -euo pipefail
AGE="${AGE:-168h}"
MODE="${1:-dry-run}"
echo "== Docker disk before =="
docker system df
echo "\n== Images older than $AGE and not used by containers =="
docker image ls --filter "before=$(docker image ls -q | tail -n 1)" --format 'table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedSince}}\t{{.Size}}' || true
if [ "$MODE" != "execute" ]; then
echo "\nDry-run فقط. للتنفيذ: ./safe-docker-clean.sh execute"
exit 0
fi
echo "\n== Pruning old unused images =="
docker image prune -a --force --filter "until=$AGE"
echo "\n== Docker disk after =="
docker system dfاحفظ الملف باسم safe-docker-clean.sh ثم شغّله كده:
chmod +x safe-docker-clean.sh
./safe-docker-clean.sh
AGE=240h ./safe-docker-clean.sh executeتعديل مهم على السكربت
السطر الخاص بعرض الصور قبل الحذف هدفه يساعدك تراجع القائمة، لكنه ليس محاكاة كاملة لما سيحذفه Docker. Docker نفسه لا يوفر dry-run حقيقي لـ image prune. عشان كده أفضل طريقة عملية هي استخدام dry-run كمرحلة مراجعة، ثم تنفيذ أمر prune مضبوط بفلتر زمني.
لو عايزها تدعم CI runners، خليك أكثر تحفظًا. استخدم AGE=240h أو AGE=336h بدل 168h. الافتراض إن runner عنده builds متكررة يوميًا، ومساحة Docker وصلت لأكثر من 30GB. لو استخدامك أقل من كده، شغّل التنظيف يدويًا بدل جدول ثابت.
التحقق من أنه يعمل
قبل التنظيف، سجّل رقم SIZE وRECLAIMABLE من docker system df. بعد التنفيذ، شغّل نفس الأمر. مثال قياس معقول: من 42GB إلى 18GB، يعني استرجعت 24GB. لو أول build بعد كده زاد من 3 دقائق إلى 7 دقائق، ده طبيعي لأن layers اتحملت من جديد.
استخدم docker system df -v لما تحتاج تفاصيل أكبر عن images وcontainers وvolumes. لكن متبدأش بـ --volumes. الـ volumes مختلفة عن images. image تقدر تعيد بناءها. volume ممكن يكون فيه PostgreSQL محلي أو ملفات لا يمكن تعويضها بسهولة.
متى لا تستخدم هذه الطريقة
لا تستخدمها على production host إلا لو فاهم lifecycle لكل container وimage. لا تستخدم --volumes في سكربت دوري عام. لا تستخدم until=24h على runner بيعمل builds كبيرة، لأنك هتخسر cache بسرعة وممكن تزود زمن الـ pipeline 20% إلى 50%.
استخدمها على أجهزة التطوير، runners المؤقتة، أو machines مخصصة للـ build. التكلفة: builds أبطأ أحيانًا واستهلاك network أعلى. المكسب: مساحة مستقرة وتقليل أعطال “no space left on device”.
مصادر راجعتها
- Docker: Prune unused Docker objects
- Docker CLI: docker image prune
- Docker CLI: docker system commands
- Docker: formatting command output
الخطوة التالية
شغّل docker system df الآن. لو Docker مستخدم أكثر من 25GB، احفظ السكربت وشغّله dry-run الأول. نفّذ التنظيف فقط بعد ما تراجع الصور القديمة وتختار AGE مناسب.