Продвинутый 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или actionsynk/actions. - Ограничение времени выполнения: Используйте
timeout-minutes: 15для каждой job, чтобы избежать бесконечных процессов. - Логирование и уведомления: Настройте отправку статуса сборки в Slack или Telegram через webhook.
- Работа с метками (tags): Запускайте деплой только при создании git-