GitRiver GitRiver
EN
Навигация

CI/CD - продвинутое

Matrix-сборки, retry, concurrency, условия запуска, runner'ы, K8s auto-scaling

Этот раздел описывает продвинутые возможности CI/CD: матричные сборки, повторы при сбоях, управление параллельностью, условия запуска, внешние раннеры и автомасштабирование в Kubernetes.

Базовые понятия (workflow, jobs, triggers, artifacts, cache) описаны в разделе CI/CD пайплайны.

Матричные сборки

Когда нужно протестировать проект на нескольких версиях языка, ОС или конфигурациях - используйте матрицу. GitRiver создаст отдельную задачу для каждой комбинации.

jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu, alpine]
        rust: ['1.80', '1.93', stable]
      fail_fast: false
      max_parallel: 4
    image: rust:${{ matrix.rust }}
    steps:
      - run: cargo test

Это создаст 6 задач (2 ОС × 3 версии Rust). Значения доступны через ${{ matrix.ключ }}.

  • fail_fast - если true (по умолчанию), при первом провале остальные задачи отменяются. Установите false чтобы дождаться всех.
  • max_parallel - ограничение параллельности (по умолчанию без лимита).

Добавление и исключение комбинаций

strategy:
  matrix:
    os: [ubuntu, alpine]
    rust: [stable, nightly]
    include:
      - os: ubuntu
        rust: nightly
        features: experimental
    exclude:
      - os: alpine
        rust: nightly

include добавляет комбинации с дополнительными переменными. exclude убирает ненужные.


Условия запуска задач

По значению переменной

Запускать деплой только из ветки main:

jobs:
  deploy:
    if: $CI_COMMIT_BRANCH == "main"
    steps:
      - run: ./deploy.sh

При ошибке предыдущей задачи

Отправить уведомление если тесты провалились:

jobs:
  notify:
    needs: [test]
    if: failure()
    steps:
      - run: curl -X POST $SLACK_WEBHOOK -d '{"text":"Тесты упали!"}'

Доступные выражения

ВыражениеКогда срабатывает
$CI_COMMIT_BRANCH == "main"Точное сравнение строк
$CI_COMMIT_TAG =~ /^v\d+/Совпадение по регулярному выражению
success()Все предыдущие задачи успешны
failure()Хотя бы одна предыдущая задача провалилась
always()Всегда (даже при отмене пайплайна)
cancelled()Пайплайн был отменён

Правила запуска (rules)

Правила - более гибкий вариант условий. Они проверяются сверху вниз; первое совпавшее определяет, что произойдёт с задачей.

Зачем нужны: когда одно условие if недостаточно - например, для main деплоить автоматически, при изменении src/ - ждать ручного запуска, а для всего остального - не запускать.

rules:
  - if: "$CI_COMMIT_BRANCH == 'main'"
    when: always
  - changes:
      - "src/**"
    when: manual
  - when: never
Значение whenЧто происходит
alwaysЗадача запускается автоматически
neverЗадача не запускается
manualЗадача ждёт ручного запуска (кнопка «Запустить» в интерфейсе)
on_successЗапуск если зависимости успешны (по умолчанию)
on_failureЗапуск если зависимости провалились

Повторы при сбоях (retry)

Если задача может упасть из-за нестабильной сети или flaky-тестов - настройте автоматический повтор:

jobs:
  test:
    retry:
      max: 2
      when: [script_failure, stuck_or_timeout_failure]
    steps:
      - run: npm test
  • max - максимум повторов (0-2)
  • when - при каких ошибках повторять:
    • script_failure - команда вернула ненулевой код
    • stuck_or_timeout_failure - задача зависла или превысила таймаут
    • always - при любой ошибке (пустой список = always)

Управление параллельностью (concurrency)

Проблема: при быстрых push подряд запускается несколько пайплайнов одновременно, и деплой может выполняться параллельно - это опасно.

Решение: группа параллельности. Задачи с одинаковым group не запускаются параллельно.

concurrency:
  group: deploy-$CI_COMMIT_BRANCH
  cancel_in_progress: true

Если cancel_in_progress: true - при новом запуске предыдущий автоматически отменяется. Это полезно для CI-тестов: зачем дождёмся старый результат, если уже есть новый push.


Допускаемый сбой (allow_failure)

Если задача не критична для пайплайна (например, линтер, который вы только внедряете):

jobs:
  lint:
    allow_failure: true
    steps:
      - run: cargo clippy -- -D warnings

Провал этой задачи не сделает пайплайн красным - он останется зелёным.


Прерываемые задачи (interruptible)

Чтобы задача автоматически отменялась при новом push в тот же ref:

jobs:
  test:
    interruptible: true
    steps:
      - run: cargo test

Работает вместе с concurrency - при новом push в ветку старая задача прерывается.


Передача данных между задачами (outputs)

Задача может передать значения следующим задачам. Например, одна задача определяет версию, а другая использует её при деплое.

Запись - через файл $CI_OUTPUT:

jobs:
  prepare:
    steps:
      - run: |
          VERSION=$(cat VERSION)
          echo "version=$VERSION" >> $CI_OUTPUT

  deploy:
    needs: [prepare]
    steps:
      - run: echo "Деплой версии $NEEDS_PREPARE_OUTPUTS_VERSION"

Имя переменной формируется автоматически: NEEDS_<ИМЯ_ЗАДАЧИ>_OUTPUTS_<КЛЮЧ> (всё в верхнем регистре).


Внешние раннеры

По умолчанию GitRiver выполняет CI-задачи на том же хосте через Docker. Для масштабирования или изоляции можно подключить внешние раннеры - отдельные машины, которые забирают задачи с сервера.

Регистрация раннера

  1. Откройте Администрирование -> «Раннеры»
  2. Нажмите «Добавить раннер»
  3. Укажите имя, описание и метки (например: linux, gpu, arm64)
  4. Сохраните токен - он показывается только один раз

Установка раннера

На машине, где будет выполняться раннер:

gitriver-runner --token <ТОКЕН> --server https://git.example.com

Раннер регулярно опрашивает сервер (каждые 3 секунды по умолчанию), забирает задачи с подходящими метками и выполняет их в Docker.

Маршрутизация задач по меткам

В workflow укажите, на каком раннере выполнять задачу:

jobs:
  gpu-test:
    runs_on: [self-hosted, linux, gpu]
    steps:
      - run: python train.py

Задача будет назначена раннеру, у которого есть все указанные метки.


K8s Auto-Scaling Runners

Для автоматического масштабирования раннеров в Kubernetes - GitRiver создаёт K8s Jobs по мере поступления CI-задач и удаляет поды после завершения.

Настройка

  1. Подключите кластер: Администрирование -> «Кластеры» -> «Добавить кластер»
    • Укажите API URL и сертификат CA, или загрузите kubeconfig
    • Нажмите «Тест подключения» для проверки
  2. Создайте конфигурацию: Администрирование -> «K8s Runners» -> «Добавить»
  3. Укажите:
    • Кластер - в каком кластере создавать поды
    • Namespace - в каком namespace
    • Docker image - образ для раннера
    • Label (runs_on) - метка для маршрутизации задач
    • Макс. pods - ограничение одновременных подов
    • Ресурсы CPU/RAM, tolerations, node selector (опционально)

Как это работает

  1. CI-задача с меткой runs_on: [k8s] попадает в очередь
  2. GitRiver создаёт K8s Job в указанном кластере/namespace
  3. Pod запускается, забирает задачу, выполняет и отправляет результат
  4. После завершения pod удаляется

Веб-терминал (Web Terminal)

Веб-терминал позволяет подключиться к работающему CI-контейнеру в реальном времени - для отладки, проверки состояния файловой системы или ручного запуска команд.

Когда доступен

  • Задача выполняется (Running)
  • У задачи указан Docker-образ (image:)
  • У вас есть права на запись в репозиторий

Как использовать

  1. Откройте выполняющуюся задачу во вкладке «CI/CD»
  2. Нажмите кнопку «Терминал» (появляется рядом с логами)
  3. Откроется интерактивный терминал в браузере
  4. Вы можете выполнять любые команды внутри контейнера

Терминал поддерживает полноценный PTY: автодополнение по Tab, стрелки для навигации по истории, Ctrl+C для прерывания.

Ограничения

  • Терминал закрывается автоматически при завершении задачи
  • Размер терминала: 24×80 символов
  • Доступен только для Docker-задач (не для задач без image:)

Множественные workflow-файлы

В одном репозитории может быть несколько workflow:

.gitriver/
  workflows/
    ci.yml          - тесты при каждом push
    release.yml     - сборка при push тега
    nightly.yml     - ночные тесты по расписанию
    deploy.yml      - деплой в production

При push GitRiver проверяет все файлы и запускает те, чьи триггеры совпали.

Максимум 20 workflow-файлов на репозиторий.