أتمتة النسخ الاحتياطي كخط دفاع أول
النسخة الاحتياطية اللي محدش بيتحقق منها = مفيش نسخة احتياطية. الهدف هنا مش بس تشغّل pg_dump، الهدف تبني دورة مغلقة: تنفيذ، تحقق، تنبيه. لو الـ backup فشل الساعة 3 الصبح، لازم تعرف قبل ما توصل الشغل.
المشكلة باختصار
الفرق المبتدئة غالباً بتبدأ بواحد من تلات أنماط فاشلة: نسخة محلية بس على نفس السيرفر، أو pg_dump بدون retention policy فبيتراكم لساعة ما يملا الـ disk، أو cron job بيشتغل لكن مفيش حد بيتابع logs. النتيجة واحدة في التلاتة: لما بتحصل كارثة (drop table بالغلط أو corruption) بتكتشف إن آخر backup شغال من شهرين.
مثال بسيط قبل ما ندخل في التقني: تخيل إن عندك خزنة فيها فلوسك، وبتحط فيها كوبي من مفتاح شقتك كل يوم. لكن الخزنة دي جوا نفس الشقة. لو حصل حريق، راح المفتاح راحت الخزنة. النسخة الاحتياطية المحلية نفس الفكرة بالظبط — لازم تكون في مكان تاني فعلي.
المفهوم بشكل علمي: قاعدة الـ 3-2-1 في صناعة التخزين بتقول: 3 نسخ من البيانات، على 2 أنواع تخزين مختلفة، 1 منهم off-site (خارج الموقع الأصلي). الـ workflow اللي هنا بيحقق الـ 1 off-site من خلال S3، وبيخلي الـ cron + Telegram يضمنوا التحقق اليومي.
المكوّنات اللي هنستخدمها
pg_dump— أداة PostgreSQL الرسمية لتصدير قاعدة البيانات.aws-cli— لرفع الملف على S3 bucket.cron— لجدولة التشغيل اليومي.- Telegram Bot API — لإرسال إشعار التأكيد.
gzip— لضغط الملف قبل الرفع (بيوفر من 60% إلى 80% من الحجم في أغلب الحالات).
الافتراضات قبل ما نبدأ
الشرح ده مبني على فرضية إن قاعدة بياناتك حجمها أقل من 50GB، وبتشتغل على Ubuntu أو Debian، وعندك حساب AWS مع IAM user ليه صلاحية s3:PutObject على bucket محدد. لو القاعدة أكبر من كده، الأسلوب ده هيشتغل لكن زمن الـ dump هيتخطى 15 دقيقة وهتحتاج تفكر في pg_basebackup أو WAL archiving بدل الـ logical dump.
السكربت الكامل
احفظ الملف ده في /opt/scripts/pg_backup.sh واعمله chmod +x.
#!/usr/bin/env bash
set -euo pipefail
DB_NAME="production_db"
DB_USER="postgres"
BUCKET="s3://my-backups-bucket/postgres"
TELEGRAM_TOKEN="123456:ABC-DEF..."
TELEGRAM_CHAT_ID="987654321"
TIMESTAMP=$(date +%Y-%m-%d_%H-%M)
FILENAME="${DB_NAME}_${TIMESTAMP}.sql.gz"
TMP_PATH="/tmp/${FILENAME}"
START=$(date +%s)
notify() {
local msg="$1"
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage" \
-d "chat_id=${TELEGRAM_CHAT_ID}" \
-d "text=${msg}" > /dev/null
}
trap 'notify "❌ Backup فشل لـ ${DB_NAME} على $(hostname)"' ERR
pg_dump -U "$DB_USER" -d "$DB_NAME" -F p | gzip -9 > "$TMP_PATH"
SIZE_MB=$(du -m "$TMP_PATH" | cut -f1)
aws s3 cp "$TMP_PATH" "${BUCKET}/${FILENAME}" --storage-class STANDARD_IA
DURATION=$(( $(date +%s) - START ))
rm -f "$TMP_PATH"
notify "✅ Backup ناجح — ${DB_NAME} — ${SIZE_MB}MB — ${DURATION}s"