Настройка CI/CD пайплайна в GitLab: от монолита к модулям

Монолитный конвейер тормозит релизы: сборка тянет за собой весь проект, а мелкая правка превращается в ручную работу. Мы настраиваем GitLab CI/CD под ключ — переводим сборку на модули, убираем ручные шаги и заметно сокращаем время выпуска версий. Обсудим вашу задачу и вернёмся с планом перевода.

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1523
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1351
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1069
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1326
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    766
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1071

Настройка GitLab CI/CD: почему монолитный конвейер ломается

Пока в проекте один сервис и один репозиторий, единый сценарий сборки выглядит разумно: один файл конфигурации в корне, запуск на каждый коммит, внутри — тесты, сборка артефактов и выкладка по цепочке стадий. Проблема в том, что он растёт вместе с продуктом. Постепенно в нём десятки стадий, ветвления по rules, зависимости между шагами держатся на порядке объявления, а часть выкладки выполняется вручную из интерфейса.

Отсюда долгий релиз. Правка в одном модуле запускает полный прогон: пересобираются все компоненты, заново подтягиваются зависимости, повторно выполняются проверки, к изменению не относящиеся. Кэш не помогает, потому что ключ общий на весь сценарий и сбрасывается при первой же правке. Ожидание обратной связи растёт, инженеры начинают объединять коммиты в пачки, и цена ошибки в каждом прогоне увеличивается.

Хрупкость проявляется иначе: сценарий перестают менять, потому что боятся. Правка одной стадии роняет соседнюю, шаг с allow_failure маскирует падение, и ошибка всплывает уже на продакшене. Ручные шаги при выкладке добавляются как временное решение, обрастают устными договорённостями и в итоге держатся на одном человеке: порядок действий знает он, а не конвейер.

Узкое место сборки — это не мощность исполнителя, а связность. Пока логика сборки одна на все компоненты, любое изменение приходится проверять целиком, а разделить ответственность между командами невозможно. Дальше разбираем, как это закрывается: вынесенными модулями конфигурации, явными контрактами между этапами и предсказуемыми точками отката.

Что даёт модульная сборка: скорость релизов и класс отказов

Модульная сборка в GitLab CI/CD начинается с того, что повторяющиеся шаги — установка зависимостей, прогон тестов, сборка артефакта, публикация образа — выносятся в общие описания, которые подключаются в каждый проект. Конкретная сборка описывает только то, чем отличается: набор проверок, ветку, окружение. Одинаковые по смыслу задачи идут параллельно, а не выстраиваются в одну очередь, и время сборки падает не за счёт урезания проверок, а за счёт того, что они перестают ждать друг друга.

Время восстановления определяется тем, насколько узко локализован сбой. Пока шаги живут в одном длинном описании, любая правка — это перезапуск всего сценария с нуля. В модульной схеме падает конкретный блок, и перезапускается только он, с сохранённым кэшем зависимостей: восстановление измеряется минутами, а не повторным проходом всей цепочки.

Доля ручных операций сокращается до единичных точек согласования. Сборка артефакта, применение миграций, раскатка на окружение описываются декларативно и выполняются одинаково на стенде и в продуктивной среде — инженер не собирает релиз руками и не копирует файлы на сервер.

Уходит целый класс отказов: расхождения конфигураций между окружениями, забытые шаги, правки напрямую на сервере и «локально работает, на стенде нет». Одинаковые модули означают, что проверенный путь не меняется при выкатке. Побочный эффект переиспользования шагов — новый сервис подключается к готовой схеме за минуты, а не обрастает собственным набором команд, который потом никто не поддерживает.

Варианты организации сборки: монолит, модули, общий конвейер

Монолитная сборка — один файл конфигурации на все сервисы — перестаёт масштабироваться, когда над репозиторием работает больше одной команды. Правка общего блока затрагивает чужие этапы, а скопированные между проектами задачи расходятся уже через несколько релизов. Ниже — четыре альтернативы и границы, за которыми каждая начинает мешать.

В GitLab все варианты собираются из одного набора примитивов: шаблоны подключаются директивами include, переиспользуемые задачи описываются отдельными блоками с параметрами, изолированные среды задаются образом и набором переменных. Разница не в синтаксисе, а в том, где проходит граница ответственности между командами.

Вариант Когда подходит Ограничения
Монолитная сборка Один сервис, одна команда, редкие релизы Правка задачи затрагивает чужие этапы, задачи дублируются между проектами
Модульные шаблоны Несколько команд, общие этапы сборки и проверок Шаблоны нужно версионировать, иначе проекты расходятся по поведению
Общие библиотеки шагов Много однотипных сервисов, частые изменения правил проверок Изменение шага влияет на всех потребителей — библиотеку тестируют отдельно
Изолированные среды Разные стеки, жёсткие требования к воспроизводимости Больше ресурсов, обязательны кэш зависимостей и передача артефактов

На практике берут комбинацию: общая библиотека шагов плюс модульные шаблоны на уровне команд, а монолит остаётся для служебных проверок. Переиспользуемые задачи не переписываются в каждом проекте, изоляция сред не ломает соседние сборки.

Как перевести сборку на модули: этапы инженерной работы

Перевод сборки с монолита на модули — это не правка одного файла конфигурации, а последовательность работ, где каждый шаг проверяется на живом релизе. Порядок принципиален: если начать с настройки окружений, не разобравшись в связях между модулями, конвейер начнёт падать там, где раньше проходил целиком.

  1. Разбор текущего состояния. Считаем время полной сборки, находим повторяющиеся шаги, неработающий кэш и транзитивные зависимости. На выходе — карта узких мест с цифрами, а не с ощущениями.

  2. Проектирование схемы сборки. Определяем границы модулей, правила запуска по изменённым путям (rules:changes в GitLab) и то, что переиспользуется: общие шаблоны и подключаемые фрагменты конфигурации. Отдельно фиксируем, какие шаги идут параллельно, а какие обязаны остаться последовательными.

  3. Настройка окружений. Секреты и переменные выносим в защищённые наборы, разделяем среды, выравниваем исполнителей сборки — результат не должен зависеть от того, на какой машине запустился конвейер.

  4. Проверка на реальных релизах. Прогоняем схему на нескольких выпусках: замеряем время сборки, долю закэшированных шагов и поведение при падении одного модуля. Ошибка в модуле больше не блокирует остальные.

  5. Передача и обучение. Отдаём документацию по структуре конвейера, регламент правок и разбор с командой — чтобы изменения вносились по правилам, а не правкой наугад.

Что остаётся в репозитории и документации после передачи

Передача — это не «настроили и ушли», а набор файлов, по которым ваша команда вносит правки сама, без переписки с нами. Всё лежит в репозитории рядом с кодом и живёт в той же истории изменений, поэтому любая правка сборки проходит проверку как обычный коммит.

  • Конфигурация сборки: корневой файл в GitLab и подключаемые модули по стадиям — подготовка, тесты, публикация. У каждого блока комментарий: зачем он и что сломается, если его убрать.
  • Шаблоны типовых заданий: новый однотипный сервис подключается указанием пути и переменных, а не копированием сотни строк.
  • Схема окружений: какие ветки публикуются в тестовый и рабочий контур, где хранятся секреты и чем они отличаются от обычных переменных.
  • Регламент выпуска: кто инициирует релиз, какие проверки обязательны, как откатиться на предыдущую версию и когда выпуск блокируется автоматически.
  • Инструкции для команды: как добавить сервис в сборку, как воспроизвести падение локально, как читать журнал упавшего задания.
  • Политики хранения: сроки жизни артефактов, промежуточных данных сборки и временных окружений — чтобы объём хранилища не рос сам по себе.
  • Матрица доступов: роли в проекте, кто вправе менять конфигурацию, защищённые ветки и запускать выпуск.

Этого набора хватает, чтобы вести сборку своими силами с первого дня: типовые изменения делаются по инструкции, а не через нас.

Кейс: как ускорили релизы и убрали ручные шаги сборки

Релизы в проекте шли через один общий сборочный контур: правка в любом модуле запускала пересборку всего продукта, а выкладка на стенд выполнялась набором ручных команд — часть шагов держалась в голове у конкретного инженера. Выпуск занимал 40–60 минут, и примерно каждая четвёртая правка пересобиралась повторно из-за нестабильных окружений.

Что изменили

Сборку перенесли на GitLab и разделили по модулям: у каждого сервиса свой набор стадий, кеш зависимостей между запусками и матрица окружений, где тестовая и рабочая среды описаны одним кодом. Ручные операции стали декларативными шагами — миграции, прогрев кеша, переключение трафика на стенде. Артефакт собирается один раз и продвигается по средам без повторной сборки, поэтому в рабочий контур попадает ровно тот же билд, что прошёл проверки.

Метрики до и после

Показатель До После
Время выпуска релиза 40–60 мин 9–12 мин
Ручных шагов на выкладку 14 2
Доля повторных сборок 24% 4%
Отказы из-за нестабильной выкладки 3–4 за квартал единичные

Что ушло по классу отказов: расхождения между стендом и рабочим контуром, «забытые» миграции и пересборка после неудачного прогона. Откат теперь — повторный запуск предыдущей задачи, а не восстановление по инструкции: возврат к рабочему состоянию сократился с 30 минут до 2–3.

Что делать, если конвейер в GitLab уже развёрнут

Ломать работающую схему не нужно и невыгодно: пока она собирает артефакты, у команды есть запас времени на спокойную замену. Правильный путь — не переписывание с нуля, а постепенный переход, при котором новая конфигурация сосуществует со старой и в любой момент отключается одной ревизией.

Технически это параллельный запуск: новый конвейер описывается отдельным файлом конфигурации в том же репозитории, а GitLab подключает его по правилам — для части веток, тегов или по значению переменной запуска. Настройка GitLab CI/CD в таком режиме сводится к тому, что действующая схема сборки продолжает обслуживать релизные ветки, пока новая не докажет результат на реальном потоке изменений.

Ключевое условие — обратная совместимость на границах: имена стадий, кэш, раннеры и контракты артефактов сохраняются, чтобы задачи выкладки и внешние потребители не заметили подмены. Переход идёт по одному блоку — сначала линтеры и тесты, затем сборка образа, затем деплой, — и каждый шаг проверяется отдельно.

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

Отдельный выигрыш — модульность: вынесенные блоки переиспользуются между репозиториями через включаемые файлы шаблонов. Правка одного правила проверки делается в одном месте, а не в десяти конфигурациях, и новые проекты стартуют уже на готовой схеме.

Частые технические сомнения перед переводом на модули

Сомнения перед переводом конфигурации GitLab CI/CD на модули почти никогда не про синтаксис — они про эксплуатацию: где лежат секреты, кто вправе править общий шаблон, что будет, если один сервис отстанет от остальных, и с чем команда останется после передачи.

Где хранить секреты, если конфигурация стала общей?

Ключи и токены не попадают в репозиторий: они лежат в переменных группы с маскированием и привязкой к защищённым веткам и окружениям. Шаблон обращается к ним по имени, значения остаются в настройках — при ротации правится одна запись, а не каждый проект.

Как разделить доступы, чтобы общий шаблон не сломали случайно?

Модули выносим в отдельный репозиторий: писать в него может узкий круг инженеров, остальные подключают его как зависимость. Разработчик собирает свой сервис, но не правит общие правила и переменные защищённой ветки — изменения шаблона проходят ревью, как обычный код.

Что будет, если модули начнут расходиться по версиям?

Зависимости фиксируем: проект ссылается на конкретную версию шаблона, а не на его текущее состояние. Тогда обновление одного сервиса не тянет за собой чужие сборки, а откат — это смена ссылки на предыдущую версию. Раз в согласованный цикл модули обновляем пачкой.

Что останется команде после передачи?

Передаём не только файлы, но и правила работы: где менять переменные, как добавить новый модуль, что делать при падении общей задачи. Плюс проверки, которые ловят расхождение конфигурации до слияния, и документацию по каждому блоку.

Обсудим задачу: разберём ваш конвейер и вернёмся с планом

Оценка объёма работ строится на фактах, а не на общих словах: по текущему конвейеру видно, сколько стадий придётся разбирать на модули и где спрятаны ручные шаги. Доступ к рабочему контуру и остановка релизов для этого не нужны — хватит конфигурации и описания процессов.

  • Файл конфигурации сборки из репозитория — как он есть, со всеми подключёнными шаблонами и наследованиями.
  • Перечень репозиториев и сервисов, которые он собирает, с пометкой, какие связаны общими стадиями.
  • Хронология одной типовой сборки: сколько идут стадии, что выполняется руками, где чаще всего падает.
  • Список окружений и правил выкладки — кто и на каких условиях выпускает сборку в каждое из них.
  • Требования к секретам и правам: какие переменные зашиты прямо в конфигурацию, где хранятся ключи, что нельзя выносить наружу.
  • Внешние системы, с которыми связан конвейер: реестр образов, хранилище артефактов, мониторинг и оповещения.
  • Ограничения: окна релизов, допустимый простой, регламенты безопасности и требования аудита.

Опишите задачу в двух-трёх абзацах и приложите то, что уже есть, — даже частичный набор даёт понимание объёма. По этим данным вернёмся с планом перевода: этапы, сроки каждого, состав команды и точки, где потребуется ваш инженер.