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

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

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

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

المنصة

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

الدعم

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

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

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

أتمتة Backup PostgreSQL إلى R2 مع اختبار Restore حقيقي

📅 ٢٤ أبريل ٢٠٢٦⏱ 5 دقائق قراءة
أتمتة Backup PostgreSQL إلى R2 مع اختبار Restore حقيقي

أتمتة Backup PostgreSQL إلى R2 مع اختبار Restore حقيقي

هتطلع من المقال بـ workflow عملي يعمل Backup PostgreSQL يومي، يرفعه إلى Cloudflare R2، ويختبر restore صغير قبل ما تعتبر النسخة صالحة. مستوى القارئ: متوسط.

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

الطريقة الشائعة بتقول: شغّل pg_dump وارفع الملف لأي storage. الطريقة دي بتفشل في نقطة مهمة: النسخة الاحتياطية لا تساوي شيء لو لم تختبر استعادتها. اللي بيحصل فعلاً إن الفريق يكتشف وقت العطل إن الملف ناقص، أو credentials غلط، أو dump قديم من قاعدة ثانية.

الافتراض هنا إن عندك PostgreSQL واحد، حجمه بين 1GB و80GB، وتحتاج نسخة يومية. لو عندك موقع SaaS صغير بـ 50K زائر يوميًا، فتعطل قاعدة البيانات لمدة ساعتين ممكن يوقف تسجيل الدخول والدفع والدعم. هدفنا مش disaster recovery كامل، هدفنا طبقة backup واضحة بتتكشف أخطاؤها بدري.

خوادم وقاعدة بيانات مع تخزين سحابي لنسخ PostgreSQL الاحتياطية الآلية

الفكرة الأساسية: 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.

خطوات التنفيذ

  1. أنشئ bucket في Cloudflare R2 باسم واضح مثل prod-postgres-backups.
  2. أنشئ API token بصلاحية Object Read & Write على هذا bucket فقط. بدل ما تعطي صلاحية على الحساب كله.
  3. أضف الأسرار في GitHub Secrets: DATABASE_URL، R2_ACCOUNT_ID، R2_ACCESS_KEY_ID، R2_SECRET_ACCESS_KEY، R2_BUCKET.
  4. شغّل workflow يومي في وقت ضغط قليل. مثلًا 02:30 UTC لو جمهورك الأساسي في الشرق الأوسط.
  5. بعد الرفع، نزّل نفس الملف وشغّل اختبار restore سريع على PostgreSQL service داخل GitHub Actions.

ملف GitHub Actions قابل للنسخ

هذا المثال يستخدم pg_dump وrclone. الرقم العملي: قاعدة 8GB غالبًا تتحول إلى dump مضغوط بين 1.5GB و3GB حسب نوع البيانات. على runner عادي، توقع 6 إلى 15 دقيقة. لو الوقت زاد عن 30 دقيقة يوميًا، راجع WAL archiving أو backup managed من مزود قاعدة البيانات.

YAML
name: postgres-r2-backup

on:
  schedule:
    - cron: '30 2 * * *'
  workflow_dispatch:

jobs:
  backup:
    runs-on: ubuntu-latest
    services:
      restore-db:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: restore_pass
          POSTGRES_DB: restore_check
        ports:
          - 5433:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - name: Install tools
        run: |
          sudo apt-get update
          sudo apt-get install -y postgresql-client rclone

      - name: Create backup
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
        run: |
          set -euo pipefail
          TS=$(date -u +%Y-%m-%dT%H-%M-%SZ)
          echo "BACKUP_FILE=postgres-$TS.dump" >> $GITHUB_ENV
          pg_dump "$DATABASE_URL" --format=custom --no-owner --file "postgres-$TS.dump"
          ls -lh "postgres-$TS.dump"

      - name: Configure rclone for R2
        run: |
          mkdir -p ~/.config/rclone
          cat > ~/.config/rclone/rclone.conf <<EOF
          [r2]
          type = s3
          provider = Cloudflare
          access_key_id = ${{ secrets.R2_ACCESS_KEY_ID }}
          secret_access_key = ${{ secrets.R2_SECRET_ACCESS_KEY }}
          endpoint = https://${{ secrets.R2_ACCOUNT_ID }}.r2.cloudflarestorage.com
          acl = private
          EOF

      - name: Upload backup to R2
        run: |
          rclone copy "$BACKUP_FILE" "r2:${{ secrets.R2_BUCKET }}/daily/" --checksum

      - name: Restore smoke test
        env:
          PGPASSWORD: restore_pass
        run: |
          rclone copy "r2:${{ secrets.R2_BUCKET }}/daily/$BACKUP_FILE" ./restore-check --checksum
          pg_restore --list "./restore-check/$BACKUP_FILE" | head -40
          pg_restore --host localhost --port 5433 --username postgres --dbname restore_check --clean --if-exists "./restore-check/$BACKUP_FILE"
          psql --host localhost --port 5433 --username postgres --dbname restore_check -c "select count(*) from information_schema.tables;"
شاشة أوامر تعرض تدفق تشغيل نسخ احتياطي واختبار استعادة تلقائي

ما الذي تكسبه وما الذي تدفعه

المكسب الأول إن الفشل يظهر بدري. لو token اتلغى، أو endpoint غلط، أو dump غير صالح، الـ workflow يفشل في نفس اليوم. المكسب الثاني إن R2 يستخدم endpoint بنمط S3: https://ACCOUNT_ID.r2.cloudflarestorage.com، فتقدر تغير الأداة لاحقًا بدون إعادة تصميم كاملة.

الـ trade-off هنا واضح. أنت تضيف 5 إلى 10 دقائق يوميًا لاختبار restore، وتستهلك مساحة تخزين إضافية. في المقابل، تقلل احتمال إن أول restore حقيقي يحصل تحت ضغط production. بدل ما تثق في وجود الملف، أنت تختبر قابلية استخدامه.

في فرق مهم بين backup وreplication. النسخة اليومية تحميك من حذف جدول بالغلط أو فساد بيانات اتشاف بعد ساعات. لكنها لا تعطيك RPO قريب من الصفر. لو مشروعك يقبل خسارة آخر 24 ساعة، هذا مناسب. لو لا، تحتاج PITR وWAL archiving أو خدمة managed backup من المزود.

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

لا تستخدمها كحل وحيد لو قاعدة البيانات أكبر من 100GB وتتغير بكثافة طوال اليوم. pg_dump منطقي ومفيد، لكنه يصبح بطيئًا ومكلفًا على قواعد ضخمة. لا تستخدمها أيضًا لو عندك أكثر من database وتحتاج roles وtablespaces؛ توثيق PostgreSQL يوضح أن pg_dump ينسخ قاعدة واحدة، بينما cluster كامل يحتاج أدوات أخرى مثل pg_dumpall أو استراتيجية physical backup.

كذلك، لا تعتمد عليها لو مطلوب منك retention قانوني مع immutability قوي. هنا تحتاج تصميم مختلف: lifecycle policy، صلاحيات فصل بين من يكتب ومن يحذف، وربما bucket lock حسب المزود.

المصادر

  • توثيق PostgreSQL لـ pg_dump: يشرح النسخ المتسق، صيغة custom، وحدود نسخ قاعدة واحدة.
  • توثيق Cloudflare R2 مع S3 tools: يوضح endpoint وصلاحيات Object Read & Write.
  • توافق Cloudflare R2 مع S3 API: مهم قبل الاعتماد على ميزات S3 المتقدمة.
  • توثيق GitHub Actions schedule: يوضح cron، UTC، وأقل تكرار للجدولة.

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

الخطوة التالية: شغّل الـ workflow يدويًا مرة واحدة من workflow_dispatch، وافتح logs خطوة Restore smoke test. لو فشلت، لا تصلح الرفع الأول. أصلح restore الأول، لأن ده الاختبار اللي هينقذك وقت العطل.

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

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

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