РАЗРАБОТКА

Почему GitLab CI тормозит: шесть частых ошибок в Runner

1423 пакета и 1 минута 48 секунд на пустую установку: как ошибки в GitLab CI и Runner незаметно раздувают время сборки и очереди.

✍️ Редакция iTech News | 14.07.2026 | ⏱ 4 мин | Источник: Habr / Карьера

Один неработающий кэш в GitLab CI может стоить команде почти двух минут на каждом прогоне: в примере из разбора зависимости ставились с нуля 1 минуту 48 секунд, хотя в конфиге кэш формально был включён. Для русскоязычных команд это история не про «красивый YAML», а про скорость Merge Request, выпуск хотфиксов и привычку жить с медленным пайплайном, пока он тихо съедает часы разработки.

Об этом сообщает Habr / Карьера в разборе Сергея Прощаева, Tech Lead и руководителя направления Java | Kotlin разработки в FinTech и e-commerce, который преподаёт в OTUS. Материал посвящён не дефициту CPU и не советам в духе «добавьте ещё один сервер», а шести типичным ошибкам в настройке GitLab Runner и .gitlab-ci.yml. Базовый сценарий статьи — self-hosted runner с Docker executor, то есть ровно та конфигурация, которая часто встречается в средних продуктовых командах.

Главный тезис автора звучит неприятно знакомо: пайплайн редко ломается одной большой проблемой. Обычно он медленно деградирует из-за набора мелочей, которые по отдельности выглядят безобидно. Кэш вроде бы описан, но не работает между раннерами. Лёгкие задачи стоят в одной очереди с тяжёлыми сборками. Контейнерные образы тянут лишние пакеты и стартуют дольше, чем нужно. Джобы связаны друг с другом так, будто каждая следующая обязана ждать предыдущую, хотя технической необходимости нет. В итоге команда получает не один громкий сбой, а ежедневный налог на ожидание.

Самый показательный кейс в статье связан с кэшем. В логах GitLab CI можно увидеть формально успешное извлечение локального кэша, а потом почти двухминутную установку зависимостей с нуля: речь шла о 1423 пакетах. Причина оказалась прозаичнее, чем любят думать в командах: статический ключ кэша плюс несколько раннеров без общего хранилища. По умолчанию Docker executor опирается на локальный кэш конкретного раннера, а значит, соседняя машина его просто не видит. Если инфраструктура распределена или раннеры эфемерные, как в Kubernetes, такой кэш превращается в декорацию. Рецепт тоже без магии: ключ привязывают к lock-файлу, а backend кэша выносят в общее объектное хранилище — S3, GCS, Azure Blob или MinIO. В описанном примере это сократило стадию с зависимостями примерно до 15–20 секунд.

Вторая типовая ошибка выглядит организационной, но бьёт по скорости не хуже битого кэша. Один shared-runner без тегов превращает CI в супермаркет с одной кассой: тяжёлая интеграционная сборка занимает слот на десять минут, а за ней стоят несколько Merge Request, которым нужен только линтер на 15 секунд. Сервер при этом может быть не загружен под завязку, проблема именно в маршрутизации задач. GitLab решает это тегами раннеров и разделением пулов по типу нагрузки, но на практике многие команды откладывают это как «потом разберём». Потом обычно наступает тогда, когда хотфикс ждёт в очереди вместе с ночными тестами.

Отдельный пласт проблем связан не с железом, а с культурой сборки. Чем старше проект, тем чаще в нём копятся тяжёлые базовые образы, лишние утилиты и зависимости, которые когда-то были нужны одной джобе, а затем поселились во всём пайплайне. Автор статьи прямо подводит к мысли, что медленный GitLab CI часто начинается не с GitLab, а с неопрятной инженерной гигиены. Если образ весит больше, чем требуется конкретной задаче, раннер тратит время на лишнюю загрузку. Если стадии и зависимости описаны «на всякий случай», задачи выстраиваются в цепочку вместо параллельного выполнения. Если артефакты и кэши не разделены по назначению, команда сначала ждёт упаковку того, что потом всё равно не будет переиспользовано.

Для бизнеса и продуктовых команд в этом разборе важен не только DevOps-слой. Медленный GitLab CI бьёт по тем метрикам, которые понимают не только инженеры: cycle time, скорость ревью, время до выката критичных правок, стоимость облачных ресурсов и психологическая инерция команды. Когда сборка регулярно идёт 20 минут, разработчики начинают подстраивать под это день: реже пушат, позже замечают регрессии, реже дробят изменения на небольшие коммиты. Это уже не проблема одного runner, а изменение поведения всей команды. И именно поэтому статья Прощаева полезна не только администраторам GitLab, но и тимлидам, которые пытаются объяснить, почему «ещё пять минут ожидания» в конце месяца превращаются в потерянные рабочие дни.

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

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

Поделиться: Telegram X LinkedIn