2. Продвинутая логика pipeline
Эта тема учит управлять сложными сценариями в GitLab CI/CD: условный запуск job’ов (rules), управление графом выполнения через needs (DAG), параллельные задачи через parallel:matrix, динамические пайплайны (включение шаблонов/файлов и child pipelines), а также разбиение конфигурации на несколько файлов через include.
Термины и сущности
| Термин | Определение |
|---|---|
| rules | Условия запуска job’а: if, changes, exists, плюс when. Позволяют точно контролировать, где и когда выполнять шаг. |
| Dynamic pipeline | Пайплайн, который “складывается” из условий: включаемые шаблоны, разные ветки исполнения, child pipelines. |
| DAG (Directed Acyclic Graph) | Граф зависимостей без циклов. В GitLab выражается через needs, когда job’и могут стартовать раньше окончания stage. |
| parallel / matrix | Параллельные job’ы, параметризованные матрицей переменных. Удобно для сборки/тестов в разных средах. |
| Child pipeline | Вложенный пайплайн, запускаемый через trigger:. Может иметь собственные stages и jobs. |
| Parent pipeline | “Верхний” пайплайн, который запускает child pipeline и ожидает его по стратегии. |
| include | Механизм подключения дополнительных конфигураций из локальных/удалённых файлов или шаблонов GitLab. |
rules: if, changes, exists (production-подход)
Определение
rules оцениваются до запуска job’а. Рекомендуется использовать rules вместо only/except, потому что логика становится читабельнее и предсказуемее.
Пример: условный deploy только на main + с учётом изменений
deploy:
stage: deploy
script:
- ./deploy.sh
rules:
# 1) Разрешаем деплой только при коммитах в main
- if: '$CI_COMMIT_BRANCH == "main"'
when: on_success
# 2) Дополнительно: деплой только если затронуты файлы приложения
- changes:
- app/**/*
- Dockerfile
when: on_success
# 3) Всё остальное — не запускать
- when: never
Комментарий (production):
- держите правила жёсткими (последнее
when: never) — так job не “случится” в неожиданном сценарии; - минимизируйте количество условий: проще сопровождать.
needs: DAG вместо “ждать весь stage”
Идея
В классическом варианте job’и ждут завершения всех job’ов в предыдущем stage. needs позволяет запускать job’и раньше, как только готовы конкретные зависимости.
Мини-проект (lint → build → test параллельно с подготовкой)
stages:
- build
- test
build-image:
stage: build
script:
- docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" .
artifacts:
paths:
- build-manifest.json
unit-tests:
stage: test
needs:
- job: build-image
artifacts: true
script:
- pytest -q
Best practice:
- используйте
needsдля ускорения и уменьшения длительности pipeline; - не добавляйте
needs“на всякий случай” — это усложняет граф.
Параллельные job’ы: parallel:matrix
Зачем
Когда нужно выполнить одну и ту же задачу для нескольких комбинаций переменных (версии языка, среды, регионы).
Пример: тесты на нескольких версиях Python
test:
stage: test
image: python:3.12-slim
parallel:
matrix:
- PY_VERSION: ["3.10", "3.11", "3.12"]
script:
- python --version
- pip install -r requirements.txt
- pytest -q
rules:
- if: '$CI_PIPELINE_SOURCE != "schedule"'
Production best practice:
- не делайте матрицу слишком широкой (это быстро раздувает время и стоимость);
- делайте переменные матрицы детерминированными и используйте кэш зависимостей (cache) при необходимости.
Dynamic pipelines: include и child pipelines
Include: разбиение на файлы
Используйте include, чтобы вынести повторяющиеся определения (например, общие job’ы или шаблоны сборки).
include:
- local: '/.gitlab/ci/common.yml'
- local: '/.gitlab/ci/backend.yml'
- template: Security/SAST.gitlab-ci.yml
stages:
- lint
- build
- test
- deploy
Best practice:
- включайте только то, что действительно нужно этому проекту;
- держите структуру
/.gitlab/ci/аккуратной (меньше “магии”).
Child pipeline: триггер микросервиса
Сценарий: parent pipeline собирает “монорепо”, а каждый микросервис запускает свои job’ы как child.
stages:
- build
- deploy
deploy-microservice-a:
stage: deploy
trigger:
include:
- local: '/services/a/.gitlab-ci.yml'
strategy: depend # parent ждёт результат child
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: on_success
- when: never
Production best practice:
- стратегия
dependполезна, когда deploy microservice должен считаться “частью” общего результата; - всегда добавляйте
rulesу trigger job’а, иначе child pipeline может стартовать неожиданно.
Production чеклист для сложных pipeline’ов
- Используйте
rulesс финальнымwhen: never. - Применяйте
needsдля DAG и ускорения. - Масштабируйте с
parallel:matrix, но держите матрицу разумной. - Разделяйте конфиг через
include, не превращая.gitlab-ci.ymlв “простыню”. - Для микросервисов используйте child pipelines с
triggerи понятной стратегией ожидания.