DevOps and Infrastructure

ایجاد پایپ‌لاین‌های CI/CD مقاوم با GitHub Actions برای میکروسرویس‌های غیر کوبرنِتِس

همان‌طور که معماری‌های میکروسرویس همچنان در توسعه نرم‌افزار مدرن مسلط هستند، پیچیدگی مدیریت چرخه عمر سرویس‌های فردی به صورت نمایی افزایش می‌یابد. در حالی که بسیاری از تیم‌ها به سمت کوبرنِتِس برای ارکستراسیون می‌روند، بخش قابل توجهی از صنعت همچنان به اهداف استقرار ساده‌تر مانند ماشین‌های مجازی، ارائه‌دهندگان PaaS (مانند AWS Elastic Beanstalk یا Heroku)، یا سرورهای بدون واسطه (bare-metal) متکی است. برای این محیط‌ها، پایپ‌لاین CI/CD باید نه تنها ساخت‌ها را خودکار کند، بلکه منطق استقرار، پیکربندی محیط و استراتژی‌های بازگشت به عقب (rollback) را نیز با دقت مدیریت نماید.

GitHub Actions رویکردی قدرتمند و کد-محور برای یکپارچه‌سازی مداوم و تحویل مداوم (CI/CD) ارائه می‌دهد. در این مقاله، بررسی خواهیم کرد که چگونه می‌توان یک پایپ‌لاین مقاوم برای میکروسرویس‌های غیر کوبرنِتِس ساخت، با تمرکز بر ماژولار بودن، امنیت و قابلیت اطمینان.

فلسفه پایپ‌لاین‌های ماژولار

یکی از رایج‌ترین اشتباهاتی که توسعه‌دهندگان مرتکب می‌شوند، کدنویسی سخت (hardcode) هر مرحله از فرآیند استقرار در یک فایل YAML تک‌تکه و بزرگ است. برای یک معماری میکروسرویس، این رویکرد به سرعت غیرقابل مدیریت می‌شود. در عوض، باید کارگاه‌های (workflows) GitHub Actions خود را به عنوان واحدهای ترکیب‌پذیر در نظر بگیریم.

با بهره‌گیری از کارگاه‌های قابل استفاده مجدد و پیکربندی خاص محیط، می‌توانیم یک منبع حقیقت واحد برای منطق ساخت خود حفظ کنیم در حالی که اهداف استقرار را متغیر نگه می‌داریم. این موضوع برای محیط‌های غیر کوبرنِتِس به ویژه حیاتی است، جایی که زیرساخت به عنوان کد ممکن است در سراسر سرویس‌ها به روش‌های متفاوتی مدیریت شود (برای مثال، برخی از Terraform و برخی دیگر از اسکریپت‌های ساده shell استفاده می‌کنند).

اجزای اصلی پایپ‌لاین

یک پایپ‌لاین مقاوم برای سرویس‌های غیر کوبرنِتِس معمولاً شامل سه فاز متمایز است: ساخت، تست و استقرار. بیایید نگاهی بیندازیم که چگونه می‌توان یک کارگاه GitHub Actions را ساخت که این فازها را به طور کارآمد در بر بگیرد.

1. فاز ساخت و تست

پیوند اصلی هر پایپ‌لاین CI/CD، سرعت و قابلیت اطمینان است. ما می‌خواهیم در صورت خرابی تست‌ها، سریعاً شکست بخوریم (fail fast). با استفاده از GitHub Actions، می‌توانیم اجرای تست‌ها را موازی‌سازی کنیم تا حلقه‌های بازخورد را کاهش دهیم.

در اینجا نمونه‌ای از یک کارگاه که نصب وابستگی‌ها، بررسی سبک کد (linting) و تست واحد را مدیریت می‌کند آورده شده است:

name: Build and Test

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

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18.x, 20.x]

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run linter
        run: npm run lint

      - name: Run unit tests
        run: npm test -- --coverage

2. کانتینرسازی برای یکپارچگی

حتی اگر از کوبرنِتِس استفاده نمی‌کنید، کانتینرسازی همچنان استاندارد طلایی برای اطمینان از یکپارچگی بین محیط‌های توسعه، پیش‌تولید (staging) و تولید است. استفاده از داکر به میکروسرویس شما اجازه می‌دهد تا بدون توجه به سیستم‌عامل میزبان زیرین، به صورت قابل پیش‌بینی اجرا شود.

ما می‌توانیم ساخت و ارسال (push) داکر را مستقیماً در پایپ‌لاین ادغام کنیم. این اطمینان حاصل می‌کند که اثری که استقرار داده می‌شود، دقیقاً همان چیزی است که تمام تست‌ها را با موفقیت پشت سر گذاشته است.

      - name: Build and Push Docker Image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

3. استقرار خاص محیط

برای سرویس‌های غیر کوبرنِتِس، استقرار اغلب شامل SSH زدن به یک سرور یا تماس با API یک ارائه‌دهنده PaaS است. امنیت در اینجا حیاتی است. ما نباید هرگز اعتبارنامه‌ها را به صورت سخت‌کد شده قرار دهیم. در عوض، از GitHub Secrets ترکیب شده با قوانین محافظت از محیط استفاده کنید.

بیایید فرض کنیم که ما از طریق SSH به یک سرور لینوکس استقرار می‌دهیم. می‌توانیم از `appleboy/ssh-action` برای اجرای اسکریپت‌های استقرار استفاده کنیم.

  deploy-staging:
    needs: build
    runs-on: ubuntu-latest
    environment: staging

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Deploy to Staging Server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.STAGING_HOST }}
          username: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /opt/my-service
            docker pull ghcr.io/${{ github.repository }}:${{ github.sha }}
            docker-compose up -d --no-deps my-service
            # Perform health check
            curl -f http://localhost:8080/health || exit 1

بهترین شیوه‌ها برای تاب‌آوری

  • آیدمپوتنس (Idempotency): اطمینان حاصل کنید که اسکریپت‌های استقرار شما می‌توانند چندین بار بدون عوارض جانبی اجرا شوند. داکر این کار را آسان‌تر می‌کند، اما آیدمپوتنس در سطح برنامه برای مهاجرت‌های پایگاه داده همچنان مورد نیاز است.
  • استراتژی بازگشت به عقب (Rollback Strategy): در محیط‌های غیر کوبرنِتِس، بازگشت به عقب می‌تواند دستی باشد. این کار را با برچسب‌گذاری تصاویر داکر با نسخه‌های معنایی (semantic versions) و در دسترس نگه داشتن نسخه‌های قبلی خودکار کنید. اگر بررسی سلامت ناموفق باشد، پایپ‌لاین باید به طور خودکار یک کارگاه بازگشت به عقب را راه‌اندازی کند.
  • مدیریت رازها (Secret Management): کلیدهای SSH و توکن‌های API خود را به طور منظم تغییر دهید. از محیط‌های GitHub برای محدود کردن کسانی که می‌توانند استقرار به تولید را تأیید کنند، استفاده کنید.

نتیجه‌گیری

ساخت پایپ‌لاین‌های CI/CD برای میکروسرویس‌های غیر کوبرنِتِس نیازمند تغییر نگرش است. به جای تکیه بر موتور ارکستراسیون برای مدیریت استقرارها و بازگشت‌ها، مسئولیت کاملاً به خود پایپ‌لاین منتقل می‌شود. با بهره‌گیری از ماهیت ماژولار GitHub Actions، کانتینرسازی و مدیریت امن رازها، می‌توانید سیستمی استقرار ایجاد کنید که به اندازه همتایان کوبرنِتِس خود مقاوم و مقیاس‌پذیر باشد. خودکارسازی را بپذیرید، امنیت را در اولویت قرار دهید و همیشه استقرارهای خود را با بررسی‌های سلامت خودکار اعتبارسنجی کنید.

Share: