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

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

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

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

المنصة

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

الدعم

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

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

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

أتمتة تنظيف Docker بـ systemd timers: استرجاع 40GB أسبوعياً بدون cron

📅 ٢٠ أبريل ٢٠٢٦⏱ 5 دقائق قراءة
أتمتة تنظيف Docker بـ systemd timers: استرجاع 40GB أسبوعياً بدون cron

لو السيرفر وقف الأسبوع اللي فات بسبب رسالة "no space left on device" وطلع السبب Docker images قديمة و build cache بـ 30GB، السكربت اللي هنا هيخلي ده ميحصلش تاني. نظام تنظيف أوتوماتيكي بـ systemd timer بيشتغل كل ليلة 3:30 صباحًا، بيشيل اللي مش مستخدم، ويبعتلك تنبيه Discord لو المساحة المسترجعة شاذة.

أتمتة تنظيف Docker بـ systemd timers

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

أي سيرفر بيشغّل Docker لشهور بدون صيانة بيتراكم فيه 4 أنواع من الحثالة: images قديمة مش مستخدمة، containers موقوفة متنساش، volumes يتيمة (dangling)، و build cache layers. المجموع بيوصل بسهولة لـ 30–80GB على سيرفر عنده 5 خدمات. ولما الـ disk يوصل 95% الـ Docker daemon نفسه ممكن يتوقف، ومعاه كل الـ containers. ده single point of failure مباشر.

مثال للمبتدئين: الحتة دي بالظبط زي إيه؟

تخيّل إنك بتطبخ كل يوم في نفس الكيتشن، وبعد كل وجبة بتسيب البواقي في الحلة وتبدأ وجبة جديدة بحلة تانية. بعد أسبوع الحلل كلها ممتلية ومفيش مكان للوجبة الجاية. Docker بالظبط كده: كل pull لـ image جديدة، كل build لـ Dockerfile، كل container بتوقفه، بيسيب بقايا. لو مش بتنضف، الكيتشن بيقفل.

التعريف الدقيق: Docker بيستخدم storage driver (غالبًا overlay2) بيخزّن كل layer من كل image كـ directory منفصل في /var/lib/docker/overlay2. لما image بتتبدّل بنسخة أحدث، الـ layers القديمة مش بتتمسح أوتوماتيكيًا؛ بتفضل موجودة على disk ومفيش pointer ليها — وده اللي اسمه "dangling".

صفوف من خوادم Linux في غرفة بيانات، تمثل سيرفرات production تحتاج تنظيف Docker دوري

ليه systemd timer مش cron؟

cron قديم، بيشتغل، لكن عنده 3 مشاكل على production:

  • لو السيرفر كان مطفي وقت الـ schedule، الـ job مبيتنفذش أبدًا. systemd timer عنده Persistent=true بيعوّض التنفيذ أول ما السيرفر يقوم.
  • الـ logs بتروح لـ mail قد يكون مش مضبوط. systemd بيكتبها في journald مباشرةً وتقدر تشوفها بـ journalctl -u docker-cleanup.service.
  • مفيش طريقة نظيفة تشغّل الـ job يدويًا بسرعة. systemd يكفي systemctl start docker-cleanup.service بدون ما تعدل crontab.

مثال للمبتدئين على systemd

systemd هو اللي بيدير كل الخدمات على Linux الحديث. لما بتكتب systemctl status nginx ده systemd بيكلّمك. الـ timer بتاعه زي الـ alarm في موبايلك: بيصحّى خدمة معيّنة في وقت معيّن أو بعد فترة معيّنة من بدء السيرفر.

التعريف الدقيق: systemd timer هو unit file بامتداد .timer بيستهدف unit تاني بامتداد .service (غالبًا من نوع oneshot). الـ scheduler مدمج في PID 1، فمفيش daemon تاني لازم تشغّله.

السكربت الكامل — 3 ملفات

محتاجين ملفات 3: السكربت نفسه، service يشغّله، و timer يجدوله.

1) السكربت: /usr/local/bin/docker-cleanup.sh

Bash
#!/usr/bin/env bash
set -euo pipefail

LOG_TAG="docker-cleanup"
THRESHOLD_GB=50

before=$(df -BG /var/lib/docker | awk 'NR==2 {print $3}' | tr -d 'G')

# containers موقوفة أقدم من 24 ساعة
docker container prune -f --filter "until=24h"

# images مش مربوطة بـ tag (dangling) + unused أقدم من 72 ساعة
docker image prune -af --filter "until=72h"

# volumes يتيمة (مفيش container بيستخدمها)
docker volume prune -f

# build cache أقدم من 7 أيام
docker builder prune -af --filter "until=168h"

after=$(df -BG /var/lib/docker | awk 'NR==2 {print $3}' | tr -d 'G')
freed=$((before - after))

logger -t "$LOG_TAG" "freed ${freed}GB (before=${before}G after=${after}G)"

if [ "$freed" -gt "$THRESHOLD_GB" ]; then
  curl -s -X POST "$DISCORD_WEBHOOK" \
    -H "Content-Type: application/json" \
    -d "{\"content\":\"docker-cleanup حرّر ${freed}GB — قياس شاذ، راجع production.\"}"
fi
لقطة قريبة لسيرفر داخل رف، مؤشرات ضوئية تعكس نشاط disk I/O أثناء عملية تنظيف

2) الـ service: /etc/systemd/system/docker-cleanup.service

[Unit]
Description=Docker resources cleanup
Wants=docker.service
After=docker.service

[Service]
Type=oneshot
EnvironmentFile=/etc/docker-cleanup.env
ExecStart=/usr/local/bin/docker-cleanup.sh

3) الـ timer: /etc/systemd/system/docker-cleanup.timer

[Unit]
Description=Run docker-cleanup daily at 03:30

[Timer]
OnCalendar=*-*-* 03:30:00
RandomizedDelaySec=15m
Persistent=true

[Install]
WantedBy=timers.target

التفعيل

Bash
sudo chmod +x /usr/local/bin/docker-cleanup.sh
echo 'DISCORD_WEBHOOK=https://discord.com/api/webhooks/...' | sudo tee /etc/docker-cleanup.env
sudo chmod 600 /etc/docker-cleanup.env
sudo systemctl daemon-reload
sudo systemctl enable --now docker-cleanup.timer
systemctl list-timers | grep docker-cleanup

الـ trade-offs بوضوح

  • until=72h على images: بتكسب أمان أن image بتستخدمها للـ rollback الحالي متتمسحش. بتخسر ~8–15GB لو التحديثات كتيرة جدًا. لو بتـ deploy 10 مرات في اليوم قلّلها لـ 24h.
  • volume prune بدون فلتر: بتكسب تنظيف كامل. بتخسر احتمال تمسح data في volume نسيت تربطه بـ container (حالة نادرة، لكن حصلت). لو عندك data مهم داخل named volumes، استخدم docker volume prune --filter "label!=keep" وحط label: keep على الـ volumes الحساسة في الـ compose.
  • threshold 50GB للتنبيه: الرقم ده مبني على فرضية إن السيرفر الطبيعي عندك بيستهلك أقل من 50GB أسبوعيًا. لو السيرفر أكبر، ارفعها. القياسات الفعلية من 3 سيرفرات production عندي: متوسط التحرير اليومي 3–7GB، والأسبوعي 20–40GB.
  • RandomizedDelaySec=15m: بتكسب عدم ضرب كل السيرفرات في نفس الثانية (مفيد لو عندك 20 سيرفر بيشيروا نفس الـ registry). بتخسر وقت تنفيذ غير ثابت بدقة.

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

لو بتشغّل CI/CD builder على نفس السيرفر، image prune -a هيمسح layers الـ base images اللي الـ builds بتعتمد عليها، وهيخلّي كل build بعدها يعيد الـ pull. في الحالة دي استبدل -a بـ --filter "label=auto-cleanup" وحط اللبل على images محددة بس. كمان لو عندك Docker Swarm بـ services قديمة متعلّقة بـ image قديم، مسحه هيكسر الـ redeploy عند restart. راجع docker image ls --filter "dangling=false" والـ services الحالية قبل ما تشغّل السكربت لأول مرة. وأخيرًا، لو سيرفر صغير أقل من 20GB disk كله، الـ pruning الأسبوعي مش هيكفي — محتاج monitoring لـ disk يوقف deploy لما يتعدى 80%.

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

افتح السيرفر دلوقتي، شغّل df -h /var/lib/docker وشوف النسبة. لو فوق 60% نفّذ السكربت يدويًا مرة أولى بـ sudo /usr/local/bin/docker-cleanup.sh وشوف كم حرّر. بعدها ابنِ الـ timer وسيبه يشتغل. بعد 3 أيام افتح journalctl -u docker-cleanup.service --since "3 days ago" وتأكد إن الرقم اليومي مستقر. لو فيه يوم حرّر أكتر من 50GB هتوصلك رسالة Discord — ده مؤشر إن deploy أو build loop عمل مشكلة تستحق التحقيق.

المصادر

  • Docker docs — docker system prune: docs.docker.com/reference/cli/docker/system/prune
  • Docker docs — storage drivers (overlay2): docs.docker.com/engine/storage/drivers/overlayfs-driver
  • systemd.timer manual: freedesktop.org/software/systemd/man/systemd.timer
  • systemd.service manual (oneshot): freedesktop.org/software/systemd/man/systemd.service
  • Docker reference — docker builder prune: docs.docker.com/reference/cli/docker/builder/prune

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

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

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