Почему собственные раннеры CI/CD срывают релизы на пиках
Общие машины сборки обслуживают сразу все проекты — и это работает ровно до первого пика. Стоит совпасть нескольким событиям: массовому слиянию веток перед релизом, ночному прогону регрессии и плановому обновлению зависимостей — и очередь сборки на пиках растёт, а задания подолгу стоят в ожидании свободной машины. Прогон, который в спокойные часы укладывался в считанные минуты, к вечеру растягивается в разы, и предсказать его длительность уже нельзя.
Пока в GitLab один пул с общим тегом по умолчанию, все задания претендуют на одни и те же ресурсы. Машины делят между собой кэш и рабочие каталоги, поэтому проверки начинают падать на ровном месте — таймауты, нехватка памяти, чужой мусор в сборочной директории. Это нестабильные прогоны проверок: инженер перезапускает задачу, очередь удлиняется ещё сильнее, а к красному статусу пропадает доверие — его привыкают «дожимать» повторным запуском.
Цена такой схемы — срыв окна релиза. Изменение, полностью готовое к выкатке, ждёт сборку дольше, чем длится само окно, и уезжает в следующее; срочная правка уходит вне регламента, руками и без полного набора проверок. Разбираем, как это закрывается: выделенные раннеры под профиль нагрузки, разведение заданий по тегам и изоляция рабочих мест.
Что даёт свой контур сборки: скорость, изоляция, контроль
Свой контур сборки — это пул машин под нашим управлением, где задания выполняются рядом с кодом, кэшем зависимостей и локальным зеркалом пакетов. Раннеры GitLab в такой схеме стартуют за секунды: образ окружения предзагружен, установка зависимостей сводится к проверке контрольных сумм. Время ожидания в очереди перестаёт зависеть от чужой нагрузки — оно определяется числом машин в пуле и приоритетами, которые мы задаём сами.
Изоляция задач — второй эффект. Каждое задание получает одноразовое окружение: контейнер или виртуальную машину, которая уничтожается после прогона. Параллельные ветки не делят общий каталог и переменные, поэтому сборка одной команды не может повлиять на другую. Лимиты процессора, памяти и диска выставляются на уровне исполнителя, и тяжёлая задача не вытесняет остальные.
Отсюда уходит целый класс отказов — расхождение окружений и «грязное» состояние между прогонами: недописанные файлы, чужие переменные, залипшие блокировки, разные версии системных библиотек. На пиках, когда за час проходит серия изменений от нескольких команд, пул масштабируется, а очередь не растёт лавинообразно.
В цифрах это выглядит так: доля прогонов, требующих ручного перезапуска, падает в разы, медианное время сборки сокращается за счёт кэша и параллельных шагов. Сбой отдельной машины не останавливает контур — задание переезжает на свободный исполнитель, и это видно по времени восстановления.
Варианты размещения раннеров: облако, свои машины, гибрид
Раннер — это место, где сходятся скорость конвейера, доступ к внутренним стендам и режим обращения с исходниками. Три схемы ниже не теоретический набор: каждую мы разворачивали, и у каждой своя цена в сопровождении.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Облачные машины сборки | Загрузка неравномерна, нужен быстрый старт, зависимости тянутся из интернета | Исходники и секреты уходят за пределы контура, кэш теряется вместе с машиной, нет прямого доступа к внутренним реестрам и стендам |
| Своё железо под сборку | Поток задач постоянный, нужны внутренние реестры, стабильный кэш и предсказуемое время сборки | Пиковую параллельность задаёт парк машин, простой между релизами нечем занять, обновления и изоляцию задач держит своя команда |
| Гибридная схема сборки | Часть задач чувствительна к данным, часть ресурсоёмкая и не требует внутренних зависимостей | Нужна явная маршрутизация задач, два набора секретов, сводная картина по метрикам собирается отдельно |
Отдельно стоит закрытый контур разработки: если регламент запрещает выход кода и артефактов наружу, облачные машины отпадают целиком, а гибрид сводится к своим мощностям с локальными зеркалами зависимостей. Гибрид окупается только тогда, когда маршрутизация описана явно — по меткам, путям или чувствительности данных. Иначе команда получает две несогласованные системы вместо одной: разные переменные окружения, разные правила кэширования, и как следствие — воспроизводимость сборки, которую невозможно гарантировать.
Этапы внедрения: от аудита сборки до передачи в эксплуатацию
Внедрение начинается не с установки агентов, а с разбора того, что уже происходит на сборочном контуре: где теряется время, какие шаги дублируются, какие задачи идут на общих исполнителях с чужими доступами. Мы идём по фиксированной последовательности — каждый этап заканчивается проверяемым артефактом, поэтому проект не растягивается на неопределённый срок.
- Аудит процессов сборки. Собираем длительность шагов, очереди в пиковые часы, долю падений по инфраструктуре, а не по коду. Результат — карта узких мест и список задач, которые стоит вынести на выделенные исполнители.
- Схема контура сборки. Проектируем топологию: сколько групп раннеров нужно, где они размещаются, как разделены сети и доступы между командами, как устроены кэш зависимостей и хранилище образов.
- Настройка раннеров. Разворачиваем исполнителей с изоляцией задач, метками под типы сборок, лимитами по ресурсам и автоскейлом под очередь. Секреты выдаются на время задачи и не лежат на хосте.
- Миграция сборок. Переводим проекты группами, начиная с наименее рискованных, с параллельной работой старого контура и быстрым возвратом на него при расхождении результатов.
- Проверка под нагрузкой. Прогоняем несколько релизных циклов на пиковом числе одновременных сборок: смотрим деградацию кэша, поведение автоскейла и время до старта задачи.
- Передача в эксплуатацию. Отдаём конфигурации, схему контура, регламент обновления и порядок действий при отказе, обучаем дежурных и фиксируем метрики, по которым контур принимается.
Что остаётся у команды: конфигурации, схемы, регламенты
Контур сборки передаём как работающую систему, а не как набор устных договорённостей: всё, что нужно для поддержки и развития, лежит в вашем репозитории и внутренней документации. Инженер вашей команды сможет менять шаги конвейера, добавлять новые проекты и разбирать сбои без обращения к нам.
- Конфигурации сборки — описания конвейеров, шаблоны для типовых приложений и наборы переменных окружения. К каждому шагу приложен комментарий: зачем он нужен, что кэшируется и какие проверки блокируют выпуск.
- Схема доступа и ключей — карта, где живут учётные данные, как агент получает доступ к реестру образов и хранилищу артефактов, какие права у каждой роли и как они выдаются новому инженеру.
- Регламент обслуживания — периодичность обновления агентов, чистка кэшей и старых образов, ротация секретов, порядок действий при исчерпании места на диске или зависшем исполнителе.
- Документация по контуру — схема размещения агентов, сетевые зоны и правила доступа, точки отказа и что делать при недоступности внешнего сервиса.
- Инструкция по восстановлению — как поднять агент с нуля по шагам, где взять конфигурацию и как проверить, что конвейер снова собирает и публикует артефакт.
- Передача знаний команде — разбор контура с вашими инженерами, включая разбор типовых сбоев и порядка их диагностики, плюс запись встречи.
Отдельно фиксируем, что осталось вне автоматизации и почему: это список задач на развитие, а не скрытый долг. Через месяц после сдачи отвечаем на вопросы по переданным материалам — дальше контур живёт на вашей стороне.
Кейс: время сборки сократили втрое, очередь на пиках ушла
Сборки шли через общий набор раннеров: коммит после слияния вставал в одну очередь с ночным регрессом и сборкой образов. Средний прогон занимал 14 минут, а на пиках ожидание доходило до 22 минут — ресурсы держали задания, которых уже никто не ждал. Доля упавших прогонов держалась на 18%: таймауты и гонки за общим кэшем зависимостей заставляли перезапускать проверки, и перезапуски ещё сильнее удлиняли очередь — пик накладывался на пик.
Что изменили
Развели раннеры по группам нагрузки: короткие проверки, сборка образов и тяжёлый ночной регресс получили отдельные наборы машин и лимиты на одновременные задания. Автоматическое масштабирование по длине очереди на Kubernetes поднимает разовых агентов под пик и убирает их в простое — окружение каждой сборки чистое, а кэш зависимостей вынесен на постоянный том и не перетирается соседними заданиями.
Что стало
Средняя сборка — 14 → 4 минуты, ожидание на пиках — 22 минуты → 40 секунд, доля упавших прогонов — 18 → 5%. Ночной регресс укладывается до начала рабочего дня, а патч по инциденту проходит полный прогон перед выпуском, а не урезанный набор проверок. Очередь перестала быть узким местом: её длина в отчётах стабильна, а новые репозитории подключаются без ручного расширения парка машин — агенты добавляются под фактическую нагрузку.
Что делать, если собственные раннеры CI/CD уже развёрнуты
Если контур уже развёрнут, начинать стоит не с переписывания, а с ревизии текущей схемы: инвентарь машин, выполняемые задачи, учётные записи, доступ к секретам. Обычно выясняется, что часть раннеров запущена вручную, метки проставлены «на глаз», а задания ходят в продовые хранилища с общим токеном. Это первый слой проблем, и виден он только на карте контура, а не в отдельных конфигурациях.
Второй шаг — разделение прав на машинах. Раннеры разносят по пулам: сборка, тесты, публикация артефактов и развёртывание получают разные учётные записи и разные области доступа. Секреты выдаются задаче на время выполнения, а не лежат в переменных машины, а исполнители делают одноразовыми — после сборки рабочая среда уничтожается вместе с временными данными.
Масштабирование под нагрузку держится на очередях и метках: машины добавляются по длине очереди, а не «на глазок», тяжёлые сборки уходят в отдельный пул и не блокируют быстрые проверки. Зависимости и общие тома выносятся наружу, поэтому новый исполнитель включается в работу сразу, без повторной загрузки всего окружения.
Доработка существующего контура идёт по одному пулу за раз с сохранением совместимости: старые задания продолжают работать, пока новый пул не подтвердит стабильность на реальном потоке, а откат остаётся возможным на любом шаге.
Заодно контур перестаёт держаться на одном инженере: конфигурация хранится как код в общем репозитории, проходит проверку до применения, а схема пулов, сети и прав описана в документации. Тогда изменения перестают быть личной ответственностью одного человека.
Технические вопросы, которые задают перед стартом
Перед стартом обычно всплывает один и тот же набор сомнений: не утекут ли ключи, что будет с релизами в момент переезда и кто отвечает за машины после запуска. Ниже — прямые ответы на то, что чаще всего спрашивают до подписания плана работ.
Куда попадают ключи доступа во время сборки?
Секреты не хранятся в репозитории и не прописываются в конфигурации сборки открытым текстом. Они лежат в отдельном защищённом хранилище, а раннер получает короткоживущий токен только на время конкретной задачи — после её завершения доступ отзывается автоматически. Значения маскируются в выводе команд, поэтому утечка через логи исключена.
Изолирован контур сборки от остальной инфраструктуры?
Каждый запуск идёт в чистом окружении, которое удаляется после задачи, — код одного проекта не остаётся на машине и не попадает в чужую сборку. Раннер видит только те реестры образов и артефактов, что разрешены политикой, а во внутренние сервисы и базы доступа у него нет. Сетевые правила описываются отдельно и проверяются на тестовом конвейере до вывода в работу.
Что произойдёт с релизами при переезде?
Новый контур поднимаем параллельно — прежний продолжает собирать и выпускать. Несколько дней задачи идут на обоих, артефакты сверяются, затем проекты переключаются по одному. Окно простоя нулевое: если сборка на новом раннере ведёт себя иначе, проект возвращается на прежний адрес до разбора причины.
Кто обслуживает машины после запуска?
Регламент фиксируем письменно: обновления раннера и базовых образов, мониторинг очереди и свободных ресурсов, чистка старых артефактов, реакция на падение задачи. В том же документе граница: что остаётся на нашей стороне, а что требует участия вашей команды — доступы к внутренним системам, согласование сетевых правил, выпуск релизов. Так ответственность не размывается через месяц после передачи.
Обсудим задачу: сборка без очередей и утечек
Чтобы вернуться с оценкой и планом работ, а не общими соображениями, достаточно вводных по сборке — этого хватает, чтобы посчитать конфигурацию раннеров, оценить трудозатраты и предложить порядок старта.
- Число репозиториев и активных команд, типичная частота коммитов — по ним считаем параллелизм и запас по нагрузке.
- Где именно копится очередь: текущее время сборки и тестов, в какие часы пик ждать приходится дольше всего.
- Как сборки идут сейчас: облачные раннеры, локальные машины разработчиков или собственный сервер.
- Требования к изоляции: какие задачи получают доступ к секретам и артефактам, кто и что видит в логах.
- Куда планируете ставить раннеры — свой контур, выделенные машины или гибрид, — и какие сети им доступны.
- Кто на вашей стороне отвечает за доступы, и кто сопровождает конфигурацию после запуска.
В ответ присылаем оценку и план работ, схему размещения раннеров и порядок старта. Первым шагом предлагаем пилот на одном репозитории: переносим его сборку, замеряем время и поведение под нагрузкой и только после этого раскатываем на остальные. Опишите задачу — вернёмся с оценкой и планом.







