أتمتة Backup PostgreSQL إلى R2 مع اختبار Restore حقيقي
هتطلع من المقال بـ workflow عملي يعمل Backup PostgreSQL يومي، يرفعه إلى Cloudflare R2، ويختبر restore صغير قبل ما تعتبر النسخة صالحة. مستوى القارئ: متوسط.
المشكلة باختصار
الطريقة الشائعة بتقول: شغّل pg_dump وارفع الملف لأي storage. الطريقة دي بتفشل في نقطة مهمة: النسخة الاحتياطية لا تساوي شيء لو لم تختبر استعادتها. اللي بيحصل فعلاً إن الفريق يكتشف وقت العطل إن الملف ناقص، أو credentials غلط، أو dump قديم من قاعدة ثانية.
الافتراض هنا إن عندك PostgreSQL واحد، حجمه بين 1GB و80GB، وتحتاج نسخة يومية. لو عندك موقع SaaS صغير بـ 50K زائر يوميًا، فتعطل قاعدة البيانات لمدة ساعتين ممكن يوقف تسجيل الدخول والدفع والدعم. هدفنا مش disaster recovery كامل، هدفنا طبقة backup واضحة بتتكشف أخطاؤها بدري.
الفكرة الأساسية: backup لا ينجح إلا بعد restore
ركز في الفرق. pg_dump يعمل export منطقي لقاعدة واحدة. توثيق PostgreSQL يوضح أن pg_dump يأخذ نسخة متسقة حتى لو القاعدة عليها قراءة وكتابة، ولا يمنع المستخدمين من الوصول لها أثناء التشغيل. دي ميزة ممتازة لتطبيقات صغيرة ومتوسطة.
لكن pg_dump وحده لا يثبت إنك تعرف ترجع الخدمة. أفضل طريقة هي: dump بصيغة custom، رفع الملف، تنزيل آخر نسخة في بيئة مؤقتة، تشغيل pg_restore --list أو restore فعلي على قاعدة اختبار. الصيغة custom عبر -Fc مناسبة هنا لأنها مضغوطة افتراضيًا وتشتغل مع pg_restore.
Cloudflare R2 مناسب لأنه يدعم S3-compatible API، فالأدوات الموجودة مثل rclone أو AWS SDK تقدر تتعامل معه بتغيير endpoint. الـ trade-off هنا إنك تكسب بساطة وتوافق مع أدوات S3، لكن لازم تراجع حدود توافق S3 في R2 قبل استخدام features متقدمة مثل بعض خصائص object locking أو tagging.
خطوات التنفيذ
- أنشئ bucket في Cloudflare R2 باسم واضح مثل
prod-postgres-backups. - أنشئ API token بصلاحية Object Read & Write على هذا bucket فقط. بدل ما تعطي صلاحية على الحساب كله.
- أضف الأسرار في GitHub Secrets:
DATABASE_URL،R2_ACCOUNT_ID،R2_ACCESS_KEY_ID،R2_SECRET_ACCESS_KEY،R2_BUCKET. - شغّل workflow يومي في وقت ضغط قليل. مثلًا 02:30 UTC لو جمهورك الأساسي في الشرق الأوسط.
- بعد الرفع، نزّل نفس الملف وشغّل اختبار restore سريع على PostgreSQL service داخل GitHub Actions.
ملف GitHub Actions قابل للنسخ
هذا المثال يستخدم pg_dump وrclone. الرقم العملي: قاعدة 8GB غالبًا تتحول إلى dump مضغوط بين 1.5GB و3GB حسب نوع البيانات. على runner عادي، توقع 6 إلى 15 دقيقة. لو الوقت زاد عن 30 دقيقة يوميًا، راجع WAL archiving أو backup managed من مزود قاعدة البيانات.