الجدولة (Cron Jobs) في GitHub Actions لتشغيل المهام الاحتياطية ليلاً

دقائق القراءة: 6

الجدولة الليلية في GitHub Actions ولماذا تُستخدم للنسخ الاحتياطي

عندما تبدأ الفرق بتبنّي CI/CD بشكل ناضج، لا تبقى الأتمتة محصورة في الاختبارات والنشر فقط، بل تمتد إلى المهام التشغيلية الحساسة مثل النسخ الاحتياطي الليلي، تنظيف السجلات، تدوير الملفات، وتصدير البيانات المهمة خارج بيئة الإنتاج.

ميزة الجدولة عبر Cron Jobs داخل GitHub Actions تمنحك نقطة تحكم مركزية يمكن مراجعتها بالإصدارات، وتوثيقها داخل المستودع نفسه، مع سجل تشغيل واضح وإشعارات فورية عند الفشل.

بدلاً من الاعتماد على crontab محلي على خادم واحد قد يُنسى أو يُعاد تهيئته، يمكن نقل منطق الجدولة إلى مسار عمل قابل للتدقيق، ومتكامل مع الأسرار، والمراجعات، وسياسات الفريق.

كيف تعمل schedule داخل Workflow

في GitHub Actions يتم تعريف التشغيل المجدول داخل الحدث on.schedule باستخدام صيغة cron. هذه الصيغة تتكون من خمس خانات: الدقيقة، الساعة، يوم الشهر، الشهر، ويوم الأسبوع.

أغلب الفرق تضبط النسخ الاحتياطي خلال وقت منخفض الحمل، مثل بعد منتصف الليل بتوقيت UTC. ويجب الانتباه إلى أن التنفيذ السحابي قد لا يكون مطابقاً حرفياً للثانية نفسها، لذا لا يُنصح باستخدامه لمهام تتطلب دقة زمنية بالمللي ثانية.

name: Nightly Backup

on:
  schedule:
    - cron: "0 1 * * *"
  workflow_dispatch:

jobs:
  backup:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

السطر workflow_dispatch مهم جداً، لأنه يسمح لك بتشغيل المهمة يدوياً لاختبارها قبل الانتظار حتى الليل. وهذا يقلل من خطر اكتشاف الأخطاء بعد أول تشغيل فعلي على بيئة الإنتاج.

بنية معمارية موصى بها لنسخ احتياطي ليلي آمن

أفضل تصميم لا يجعل GitHub Actions يخزن البيانات داخله، بل يجعله منسقاً لعملية النسخ. بمعنى آخر: يتصل بالخادم، ينفذ سكربت النسخ، يضغط المخرجات، ثم يرسلها إلى تخزين خارجي مثل S3 أو خادم أرشفة منفصل.

هذا النمط مناسب جداً عندما تكون تطبيقاتك منشورة عبر Linux أو عبر حاويات Docker. وإذا كنت تعمل ضمن بيئات حاويات، ففهم التخزين الدائم يصبح أساسياً، ويمكنك التوسع أكثر عبر مقال التخزين الدائم Docker Volumes.

مكونات التدفق الليلي

  • مستودع يحتوي ملف workflow وسكربتات التشغيل.
  • خادم تطبيق أو قاعدة بيانات يستقبل اتصال SSH.
  • تخزين خارجي لحفظ النسخ بعيداً عن نفس الخادم.
  • أسرار مخزنة في إدارة الأسرار GitHub Secrets.
  • تنبيه عند الفشل إلى Slack أو Telegram.

مثال عملي: تشغيل سكربت نسخ احتياطي على الخادم ليلاً

السيناريو التالي شائع في المشاريع المتوسطة: لديك قاعدة بيانات على خادم إنتاج، وتريد تنفيذ تصدير ليلي ثم رفع الملف الناتج إلى مساحة تخزين آمنة. هنا يتولى runner الاتصال بالخادم بدلاً من تشغيل قاعدة البيانات محلياً.

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/var/backups/myapp"
DATE="$(date +%F-%H-%M)"
FILE_NAME="db-backup-${DATE}.sql.gz"

mkdir -p "$BACKUP_DIR"

mysqldump -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" | gzip > "${BACKUP_DIR}/${FILE_NAME}"

find "$BACKUP_DIR" -type f -name "*.sql.gz" -mtime +7 -delete

echo "Backup created: ${BACKUP_DIR}/${FILE_NAME}"

هذا السكربت يطبق ممارسات مفيدة: فشل صارم عند الخطأ، تسمية زمنية للنسخ، وضغط فوري لتقليل الحجم، مع سياسة حذف للملفات الأقدم من سبعة أيام. ويمكن استبدال MySQL بـ PostgreSQL أو حتى نسخ ملفات تطبيق ثابتة.

name: Nightly Server Backup

on:
  schedule:
    - cron: "0 1 * * *"
  workflow_dispatch:

jobs:
  remote-backup:
    runs-on: ubuntu-latest

    steps:
      - name: Install SSH key
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SERVER_SSH_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H "${{ secrets.SERVER_HOST }}" >> ~/.ssh/known_hosts

      - name: Execute backup script on server
        run: |
          ssh "${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}" \
          "export DB_USER='${{ secrets.DB_USER }}' && \
           export DB_PASSWORD='${{ secrets.DB_PASSWORD }}' && \
           export DB_NAME='${{ secrets.DB_NAME }}' && \
           /usr/local/bin/run-nightly-backup.sh"

      - name: Verify latest backup file
        run: |
          ssh "${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}" \
          "ls -lah /var/backups/myapp | tail -n 5"

إذا كنت تبني مساراتك بشكل تدريجي، فمقال بناء أوامر YAML لأتمتة تشغيل السكربتات يوضح طريقة تنظيم الخطوات وتحسين القراءة والصيانة.

إدارة الأسرار والصلاحيات بدون تعريض البنية للخطر

أخطر خطأ شائع هو استخدام حساب خادم بصلاحيات جذرية كاملة فقط لتشغيل النسخ الاحتياطي. الصحيح هو إنشاء مستخدم مخصص بامتيازات محددة، يمتلك فقط ما يحتاجه لقراءة البيانات المطلوبة وكتابة مخرجات النسخ في مجلد معروف.

لا تضع أي كلمة مرور أو مفتاح SSH أو رمز وصول داخل ملف YAML نفسه. استخدم GitHub Secrets حصراً، وفعّل تدوير المفاتيح دورياً، وقيّد عنوان المصدر إن كانت بنيتك تدعم ذلك عبر جدار ناري أو طبقة VPN.

يفضل أيضاً فصل سر قاعدة البيانات عن سر الخادم، وعدم إعادة استخدام نفس المفاتيح بين بيئات staging وproduction. هذا يقلل من نطاق الضرر عند التسريب أو سوء التهيئة.

التحقق من نجاح النسخ الاحتياطي بدلاً من افتراضه

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

خطوات التحقق الموصى بها

  1. فحص حجم الملف الناتج ومقارنته بحد أدنى منطقي.
  2. حساب قيمة checksum لضمان سلامة النقل.
  3. رفع النسخة إلى تخزين خارجي ثم التحقق من نجاح الرفع.
  4. إجراء اختبار استعادة دوري على بيئة معزولة.

النسخ الاحتياطي غير القابل للاستعادة يساوي عملياً عدم وجود نسخ احتياطي. اختبر عملية restore شهرياً على الأقل في بيئة منفصلة، ولا تكتفِ بمراقبة نجاح مهمة الجدولة فقط.

الدمج مع الإشعارات والمراقبة التشغيلية

حتى أفضل جدول زمني يفقد قيمته إذا فشل بصمت. لذلك من الحكمة ربط مهمة النسخ الاحتياطي مع قنوات تنبيه مباشرة. ويمكنك الاستفادة من مقال إرسال إشعارات فورية إلى Telegram أو Slack لإضافة تنبيه عند الفشل أو حتى عند النجاح.

كما يمكن دمج التقارير مع لوحات مراقبة خارجية عبر webhook أو واجهات API، بحيث تتحول مهمة النسخ الاحتياطي من سكربت صامت إلى عملية مرئية ضمن المنظومة التشغيلية كاملة.

متى تكون GitHub Actions مناسبة ومتى لا تكون كذلك؟

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

لكن إن كانت العملية تتطلب وصولاً داخلياً جداً داخل شبكة خاصة معزولة، أو تحتاج جدولة دقيقة للغاية، أو تعمل على بيانات ضخمة جداً تتجاوز الحدود العملية لبيئة التنفيذ السحابية، فقد يكون من الأفضل استخدام self-hosted runner أو نظام جدولة داخلي على مستوى البنية.

خاتمة

الجدولة عبر Cron Jobs في GitHub Actions ليست مجرد وسيلة لتشغيل سكربت ليلي، بل أسلوب هندسي لنقل المهام التشغيلية الحساسة إلى بيئة قابلة للتدقيق، والتحكم، والاختبار. وعندما تُبنى مع إدارة أسرار سليمة، وصلاحيات مقيدة، وتحقق فعلي من نتائج النسخ، فإنها تصبح جزءاً ناضجاً من استراتيجية الاستمرارية والتعافي من الكوارث.

إذا أتقنت هذا النمط، فأنت لا تؤتمت النسخ الاحتياطي فقط، بل تؤسس لمسار تشغيلي متقدم يربط بين الأمان، والموثوقية، والسرعة، وهي نفس المبادئ التي يقوم عليها عالم DevOps الحديث.

3 comments

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *