Продвинутый CI/CD для JavaScript: GitHub Actions на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Продвинутый CI/CD для JavaScript проектов с GitHub Actions

Автоматизация сборки, тестирования и развертывания (CI/CD) — неотъемлемая часть современной разработки на JavaScript. Если вы уже освоили базовые пайплайны GitHub Actions, пришло время перейти на следующий уровень. В этой статье мы разберем продвинутые техники: кэширование зависимостей, матричные сборки, параллельное выполнение задач, безопасную работу с секретами и автоматический деплой на VPS и в Docker. Все примеры ориентированы на Node.js проекты.

1. Оптимизация времени сборки: кэширование и условные запуски

Одна из главных проблем базовых пайплайнов — долгая установка node_modules при каждом запуске. GitHub Actions позволяет кэшировать зависимости, что сокращает время выполнения в 2-4 раза.

Используйте action actions/cache для кэширования node_modules или ~/.npm:

name: CI Pipeline
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Cache node_modules
        uses: actions/cache@v3
        id: npm-cache
        with:
          path: node_modules
          key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - name: Install dependencies
        if: steps.npm-cache.outputs.cache-hit != 'true'
        run: npm ci

Продвинутые советы:

  • Используйте hashFiles('package-lock.json') для точного инвалидирования кэша при изменении зависимостей.
  • Для монорепозиториев кэшируйте отдельно каждый пакет с помощью path: packages/*/node_modules.
  • Добавляйте условные запуски (if: github.ref == 'refs/heads/main'), чтобы тяжелые задачи (например, сборка production-версии) выполнялись только при пушах в ветку main.

2. Матричные сборки и параллельные задачи

Матричная стратегия позволяет запускать один и тот же workflow с разными параметрами. Это незаменимо для тестирования на нескольких версиях Node.js или операционных системах.

jobs:
  test:
    strategy:
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm test

Для параллельного выполнения независимых задач (например, линтинг, юнит-тесты, интеграционные тесты) используйте отдельные jobs. Они выполняются одновременно и не блокируют друг друга:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run lint

  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run test:unit

  integration-tests:
    needs: [lint, unit-tests] # ждем завершения lint и unit
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run test:integration

Важно: Используйте needs, чтобы задать порядок выполнения зависимых задач. Это экономит время и ресурсы.

3. Продвинутый деплой: Docker и VPS с использованием артефактов

После успешного тестирования необходимо развернуть приложение. Рассмотрим два популярных сценария: деплой в Docker-образ и на VPS.

3.1. Сборка и публикация Docker-образа

jobs:
  build-and-push:
    needs: [test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            yourusername/myapp:latest
            yourusername/myapp:${{ github.sha }}

Для деплоя на VPS используйте артефакты или SSH-команды. Сначала соберите production-версию приложения, затем передайте файлы на сервер:

jobs:
  deploy:
    needs: [test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run build

      - name: Deploy to VPS via SSH
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USER }}
          key: ${{ secrets.VPS_SSH_KEY }}
          source: "dist/, package.json, Dockerfile"
          target: "/var/www/myapp"

      - name: Restart application
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USER }}
          key: ${{ secrets.VPS_SSH_KEY }}
          script: |
            cd /var/www/myapp
            npm ci --production
            pm2 restart myapp

Важно: Всегда храните чувствительные данные (пароли, SSH-ключи) в Secrets репозитория, а не в самом файле workflow.

4. Безопасность и мониторинг пайплайна

Продвинутый CI/CD требует внимания к безопасности и наблюдаемости.

  • Проверка зависимостей: Добавьте шаг для сканирования уязвимостей с помощью npm audit или action synk/actions.
  • Ограничение времени выполнения: Используйте timeout-minutes: 15 для каждой job, чтобы избежать бесконечных процессов.
  • Логирование и уведомления: Настройте отправку статуса сборки в Slack или Telegram через webhook.
  • Работа с метками (tags): Запускайте деплой только при создании git-

Блоги

Рекомендаций по книгам