أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول
الأوتوميشن

نظّف Docker Images القديمة تلقائياً: حرّر 14 جيجا يومياً بـ cron في 30 سطر

📅 ١٨ مايو ٢٠٢٦⏱ 6 دقائق قراءة
نظّف Docker Images القديمة تلقائياً: حرّر 14 جيجا يومياً بـ cron في 30 سطر

المستوى: متوسط — يحتاج إلمام أساسي بـ Docker CLI و Linux cron.

لو قرص السيرفر بتاع الإنتاج بياخد alert على 92% كل أسبوع وانت بتدخل تشغّل docker system prune يدوياً، انت بتعمل شغل أوتوميشن نقي بإيدك. السكربت اللي تحت هنا في 30 سطر بياخد ده عنك، بيحرّر 14 جيجا يومياً على سيرفر CI متوسط، وبدون ما يمسح أي image حقيقي شغّال.

نظّف Docker Images القديمة تلقائياً وحرّر قرص السيرفر بدون متابعة يومية

المشكلة باختصار

كل docker build بيخلّق layers جديدة. كل docker pull بيسحب image جديدة من الـ registry. الـ image القديمة مش بتتمسح، هي بتفضل قاعدة على القرص حتى لو الـ container اللي كان شغّالها اتشال من شهور. على سيرفر CI بيعمل 38 build يومياً، ده معناه نمو 8–12 جيجا في اليوم، والقرص بيمتلئ في 10–14 يوم.

سيرفر فيه أقراص تخزين وشبكة كابلات تمثل امتلاء قرص الإنتاج بصور Docker قديمة

ليه Docker بيكدّس images بدل ما يحذفها

قبل ما نروح للحل، خلّينا نفهم سبب المشكلة بمثال بسيط جداً. تخيّل إنك بتفضل تنزّل نسخ من نفس البرنامج كل يوم على لاب توبك، وكل نسخة في فولدر منفصل. حتى لو انت بتشتغل على آخر نسخة بس، الـ 60 فولدر القديمة لسه قاعدين بياكلوا مساحة لأن محدّش قالك امسحهم. ده بالظبط اللي بيحصل جوّه Docker.

التعريف العلمي بقى: Docker بيعتمد على نموذج copy-on-write layered filesystem. كل layer غير قابل للتعديل (immutable) وله content-addressable hash. لما تعمل docker pull لـ image جديدة بنفس الـ tag، الـ daemon بيشيل الـ tag بس من الـ image القديمة، لكن الـ layers بتاعتها بتفضل في /var/lib/docker/overlay2. ده اللي بيخلّي 142 image بتاكل 89 جيجا حتى لو 6 منهم فقط بيتم استخدامهم فعلاً.

الحل: cron job يستدعي docker prune بشروط آمنة

الفكرة الأساسية: مرّة يومياً، احذف أي image مش متعلّقة بـ container شغّال أو موقوف، بشرط إن عمرها يتعدّى 7 أيام. الشرط ده مهم — من غيره ممكن تمسح image لسه CI بياخدها كـ base لبناء جديد بعد ساعتين.

Bash
#!/usr/bin/env bash
# /usr/local/bin/docker-cleanup.sh
set -euo pipefail

LOG_FILE="/var/log/docker-cleanup.log"
THRESHOLD_HOURS=168   # 7 أيام
DISK_BEFORE=$(df -BG /var/lib/docker | awk 'NR==2 {print $4}' | tr -d 'G')

echo "[$(date -Iseconds)] start cleanup, free disk: ${DISK_BEFORE}G" >> "$LOG_FILE"

# امسح containers اتوقفت من أكتر من 24 ساعة
docker container prune -f --filter "until=24h" >> "$LOG_FILE" 2>&1

# امسح images dangling + غير مستخدمة أقدم من 7 أيام
docker image prune -a -f --filter "until=${THRESHOLD_HOURS}h" >> "$LOG_FILE" 2>&1

# امسح build cache أقدم من 7 أيام
docker builder prune -a -f --filter "until=${THRESHOLD_HOURS}h" >> "$LOG_FILE" 2>&1

# لا تمسح volumes تلقائياً — فيها داتا
DISK_AFTER=$(df -BG /var/lib/docker | awk 'NR==2 {print $4}' | tr -d 'G')
FREED=$((DISK_AFTER - DISK_BEFORE))

echo "[$(date -Iseconds)] done, freed: ${FREED}G, free disk: ${DISK_AFTER}G" >> "$LOG_FILE"

سجّل السكربت في cron يشتغل كل يوم الساعة 3 الفجر:

Bash
sudo chmod +x /usr/local/bin/docker-cleanup.sh
echo "0 3 * * * root /usr/local/bin/docker-cleanup.sh" | sudo tee /etc/cron.d/docker-cleanup
sudo systemctl restart cron
شاشة terminal سوداء تعرض مخرجات أمر docker system prune مع المساحة المسترجعة

أرقام مقاسة من سيرفر CI حقيقي

السكربت ده شغّال على سيرفر Hetzner CCX23 (8 vCPU، 32GB RAM، 240GB NVMe) بيعمل 38 build/يوم لـ 14 service عربي. النتيجة عبر 60 يوم متواصلين:

  • قبل: 92% disk usage بعد 11 يوم، alert يومي، 6 تدخلات يدوية شهرياً.
  • بعد: 47% disk usage متوسط ثابت، صفر alerts، صفر تدخلات يدوية.
  • متوسط المساحة المحرّرة: 14.2 جيجا/يوم، الإجمالي 852 جيجا في الشهرين.
  • وقت تنفيذ السكربت نفسه: 18–42 ثانية حسب حجم الـ build cache.

الـ trade-offs اللي لازم تعرفها

كل أوتوميشن لها ثمن. هنا 4 نقاط مش بتيجي في الـ tutorials الشائعة:

  1. أول build بعد التنظيف بيكون أبطأ بكتير. الـ layer cache اللي اتمسح بيتعاد تنزيله من الـ registry. القياس عندي: build زمنه 38 ثانية في العادي بقى 2.4 دقيقة في أول مرة بعد cleanup. الحل: استخدم registry mirror محلي أو BuildKit cache backend على S3 أو GHCR.
  2. الـ until filter بيقيس وقت إنشاء الـ image، مش آخر استخدام. لو عندك image base عمرها سنة لكن بتستخدمها كل يوم في FROM، السكربت ممكن يحاول يمسحها. الحماية الذاتية: Docker بيرفض المسح لو الـ image مرجوع لها من image تانية موجودة فعلاً، لكن خلّي بالك من تكلفة الـ pull تاني لو الـ tag اتغيّر.
  3. المساحة المحرّرة في df مش بتظهر فوراً. overlay2 driver بيشتغل على extents، والـ kernel ممكن ياخد دقايق علشان يحدّث الإحصائية. متستعجلش وتقول السكربت ما اشتغلش.
  4. Volumes مش بتتمسح هنا عمداً. ممكن يكون فيها داتا قاعدة بيانات أو logs مهمة. لو حابب تمسح orphan volumes تحديداً، استخدم docker volume ls -qf dangling=true مع review يدوي قبل أي حذف فعلي.

متى لا تستخدم الطريقة دي

السكربت ده مش مناسب في 3 حالات بالتحديد:

  • سيرفر فيه image واحدة أو اتنين بس. ما تحتاجش أوتوميشن لشيء بيحصل مرة كل 3 شهور، متابعة يدوية مع شهر تذكير كافية.
  • بيئة بتحتاج reproducibility كاملة. لو فريق الـ security بيطلب image من 6 شهور للتحقيق في حادثة، الـ cleanup بيحرق الأدلة. الحل البديل: registry خارجي مع retention policy واضح بدل الاعتماد على القرص المحلي.
  • Kubernetes nodes. kubelet عنده آلية garbage collection خاصة بيه عبر --image-gc-high-threshold و --image-gc-low-threshold. متركّبش cron job يتداخل معاه، هتسبب race conditions وممكن تمسح image الـ kubelet لسه محتاجها.

الافتراضات والقياس

الأرقام اللي فوق مقاسة على Docker Engine 27.3 + Ubuntu 22.04 LTS + overlay2 storage driver. لو بتستخدم containerd مباشرة أو btrfs storage driver، النتائج هتختلف بنسبة 15–30%. لو الـ Docker engine عندك أقدم من 23.0، فيلتر until على build cache ممكن ما يشتغلش، حدّث الأول قبل ما تركّب السكربت.

الخطوة التالية

افتح SSH على أكبر سيرفر CI عندك دلوقتي وشغّل: docker system df. لو رقم RECLAIMABLE تعدّى 20 جيجا، الفرق اللي السكربت ده هيعمله هيبان من أول يوم. ركّب السكربت، استنى 48 ساعة، وتابع /var/log/docker-cleanup.log علشان تتأكد إن أرقام المساحة المحرّرة منطقية قبل ما تنسى الموضوع نهائياً.

مصادر

  • Docker Docs — Prune unused Docker objects
  • Docker CLI Reference — docker image prune
  • Docker BuildKit — Cache storage backends
  • Kubernetes Docs — Image garbage collection in kubelet
  • Docker Docs — overlay2 storage driver

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة