انتقل إلى المحتوى الرئيسي
العودة إلى الفئة

النشر التلقائي مع GitHub Actions: إعداد CI/CD Pipeline

إنشاء CI/CD pipelines مع GitHub Actions: بناء ونشر Docker، النشر على الخادم عبر SSH، أتمتة الاختبارات، إدارة الأسرار وتحسين سير العمل.

وقت القراءة: 18 دقيقة DevOps والأتمتة
github-actionsci/cddeploymentdevopsأتمتةdockerssh
الكاتب
REXE Teknoloji Network & Security Team
المحرر
REXE Teknoloji Technical Editorial
أول نشر
آخر تحديث

النشر التلقائي مع GitHub Actions: إعداد CI/CD Pipeline

GitHub Actions منصة CI/CD قوية تختبر تغييرات الكود تلقائياً وتبنيها وتنشرها على الخادم. في هذا الدليل سنبني pipeline جاهزاً للإنتاج من الصفر.

ما هو GitHub Actions؟

GitHub Actions منصة أتمتة مدمجة في مستودعات GitHub:

  • يستجيب لأحداث مثل push وPR والجدولة
  • يشغّل سير عمل متوازية ومتسلسلة
  • 2,000 دقيقة/شهر مجاناً (غير محدود للمستودعات العامة)
  • قابل للتوسع بآلاف الـ actions الجاهزة

تُخزَّن ملفات سير عمل GitHub Actions بتنسيق YAML في مجلد .github/workflows/.

هيكل سير العمل الأساسي

hljs yaml
# .github/workflows/deploy.yml
name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: إعداد Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: تثبيت التبعيات
        run: npm ci
      - name: تشغيل الاختبارات
        run: npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - name: النشر
        run: echo "خطوات النشر هنا"

هيكل on / jobs / steps

المحفزات (on)

hljs yaml
on:
  # Push إلى فرع
  push:
    branches: [main, develop]
    paths:
      - 'src/**'
      - 'package.json'

  # Pull request
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened]

  # تشغيل مجدول (cron)
  schedule:
    - cron: '0 2 * * *'  # كل ليلة الساعة 02:00

  # تشغيل يدوي
  workflow_dispatch:
    inputs:
      environment:
        description: 'بيئة النشر'
        required: true
        default: 'staging'
        type: choice
        options: [staging, production]

  # عند اكتمال سير عمل آخر
  workflow_run:
    workflows: ["Build"]
    types: [completed]

تكوين المهمة

hljs yaml
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      NODE_ENV: test
    timeout-minutes: 30
    strategy:
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest, windows-latest]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

بناء ونشر Docker

النشر إلى Docker Hub

hljs yaml
jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: بيانات Docker الوصفية
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: username/myapp
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=sha,prefix=sha-

      - name: إعداد Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: تسجيل الدخول إلى Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: البناء والنشر
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

GitHub Container Registry (GHCR)

hljs yaml
      - name: تسجيل الدخول إلى GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: البناء والنشر (GHCR)
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository }}:latest

النشر على الخادم عبر SSH

استخدام appleboy/ssh-action

hljs yaml
  deploy:
    needs: docker
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: النشر عبر SSH
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          port: ${{ secrets.SERVER_PORT }}
          script: |
            cd /root/myapp
            git pull origin main
            docker compose pull
            docker compose up -d --remove-orphans
            docker image prune -f
            echo "اكتمل النشر: $(date)"

النشر مع Docker Compose

hljs yaml
      - name: نشر Docker Compose
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            # سحب الصورة الجديدة
            docker pull ghcr.io/${{ github.repository }}:latest

            # نشر بدون توقف
            docker compose -f /root/app/docker-compose.yml up -d \
              --no-deps \
              --build \
              --remove-orphans

            # تنظيف الصور القديمة
            docker image prune -af --filter "until=24h"

            # فحص الصحة
            sleep 10
            curl -f http://localhost:3000/health || exit 1

إدارة الأسرار

يخزّن GitHub Secrets المعلومات الحساسة بأمان:

hljs yaml
steps:
  - name: تكوين التطبيق
    env:
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
      JWT_SECRET: ${{ secrets.JWT_SECRET }}
      API_KEY: ${{ secrets.API_KEY }}
    run: |
      echo "تم تحميل التكوين"
      # لا تُطبع الأسرار في السجلات، تُخفى تلقائياً

الأسرار المطلوبة:

  • SERVER_HOST: عنوان IP للخادم
  • SERVER_USER: اسم مستخدم SSH
  • SSH_PRIVATE_KEY: المفتاح الخاص لـ SSH
  • DOCKERHUB_USERNAME: اسم مستخدم Docker Hub
  • DOCKERHUB_TOKEN: رمز وصول Docker Hub

استخدام التخزين المؤقت

hljs yaml
      - name: تخزين تبعيات Node.js مؤقتاً
        uses: actions/cache@v4
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - name: npm ci (مع التخزين المؤقت)
        run: npm ci

      # تخزين طبقات Docker مؤقتاً
      - name: البناء والنشر
        uses: docker/build-push-action@v5
        with:
          cache-from: type=gha
          cache-to: type=gha,mode=max

Matrix Builds

hljs yaml
jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        node: [18, 20]
        os: [ubuntu-latest, macos-latest]
        include:
          - node: 20
            os: ubuntu-latest
            coverage: true
        exclude:
          - node: 18
            os: macos-latest
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci
      - run: npm test
      - name: تقرير التغطية
        if: matrix.coverage
        run: npm run coverage

قواعد حماية البيئة

hljs yaml
jobs:
  deploy-production:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://example.com
    steps:
      - name: نشر الإنتاج
        run: echo "النشر إلى الإنتاج"

في GitHub تحت Settings > Environments > production:

  • Required reviewers (يتطلب موافقة)
  • Wait timer (وقت الانتظار)
  • Deployment branches (main فقط)

مثال كامل لـ CI/CD Pipeline

hljs yaml
name: Full CI/CD

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npm test -- --coverage
      - name: رفع التغطية
        uses: codecov/codecov-action@v4

  build:
    needs: test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      - uses: docker/build-push-action@v5
        with:
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment:
      name: production
      url: https://example.com
    steps:
      - uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main
            docker compose -f /root/app/docker-compose.yml up -d
            docker image prune -f

الخلاصة

بإعداد CI/CD pipeline مؤتمت بالكامل مع GitHub Actions، يمكنك تحسين جودة الكود وتقليل أخطاء النشر وتسريع عملية التطوير. مع إدارة الأسرار وتحسين التخزين المؤقت وقواعد حماية البيئة، ستحصل على pipeline بمستوى الإنتاج.

الأسئلة الشائعة

هل GitHub Actions مجاني؟

مجاني تماماً وغير محدود للمستودعات العامة. تحصل المستودعات الخاصة على 2,000 دقيقة مجانية شهرياً. إذا تجاوز هذا الحد في خطة GitHub Free، تتوقف سير العمل. تتضمن خطط GitHub Pro وTeam دقائق أكثر.

كيف أنشئ مفتاح SSH الخاص وأضيفه إلى GitHub؟

أنشئ زوج مفاتيح على جهازك المحلي بالأمر 'ssh-keygen -t ed25519 -C "github-actions"'. أضف المفتاح العام (~/.ssh/id_ed25519.pub) إلى ~/.ssh/authorized_keys على خادمك. احفظ المفتاح الخاص (~/.ssh/id_ed25519) في مستودع GitHub تحت Settings > Secrets باسم SSH_PRIVATE_KEY.

كيف تعمل تبعية المهام مع needs؟

'needs: test' يعني أن هذه المهمة لن تعمل حتى تكتمل مهمة 'test' بنجاح. استخدم 'needs: [test, build]' لتبعيات متعددة. إذا فشلت مهمة، تُلغى المهام التابعة تلقائياً.

هل يمكن تشغيل سير العمل فقط عند تغيير ملفات محددة؟

نعم، استخدم 'on.push.paths' لمراقبة ملفات أو مجلدات محددة. مثلاً 'paths: ["src/**", "package.json"]' يشغّل سير العمل فقط عند تغيير هذه الملفات. استخدم 'paths-ignore' لاستبعاد ملفات معينة.

لماذا يعد تخزين بناء Docker مؤقتاً مهماً؟

يمنع تخزين بناء Docker المؤقت إعادة بناء الطبقات غير المتغيرة. 'cache-from: type=gha' يستخدم تخزين GitHub Actions المؤقت. يمكن أن يقلل وقت البناء بنسبة 50-80%. يحدث فرقاً كبيراً خاصة لخطوات تثبيت التبعيات (npm install, pip install).

ماذا تفعل قواعد حماية البيئة؟

تضيف آلية موافقة للبيئات الحرجة مثل الإنتاج. مع 'Required reviewers' لا يمكن النشر بدون موافقة أشخاص محددين. 'Wait timer' يحدد وقت انتظار قبل النشر. هذا يمنع النشر العرضي إلى الإنتاج.

مقالات ذات صلة

حركة الشبكةالداخل Gbpsالخارج Gbps