GitLab Container Registry: где ломается CI/CD
Реестр образов в GitLab почти никогда не ломается «сам по себе» — он ломается на стыках: между сборкой, тегированием и очисткой. Первый типовой сбой — раздувание хранилища. Каждый прогон публикует новый слой, старые теги остаются, и через несколько месяцев реестр растёт быстрее, чем продукт. Пока места хватает, проблему никто не видит; когда место кончается, падают уже не сборки, а весь сервер с реестром.
Второй источник — конфликты тегов. Если сборка перезаписывает latest или переиспользует неизменяемый тег, то откат на предыдущий релиз становится невозможен: под тем же именем лежит уже другой образ. Диагностировать это тяжело — сборка прошла, деплой прошёл, а на стенде крутится не то, что ожидали.
Отдельная категория — ошибки авторизации. Истёкший токен раннера, неверные права у сервисной учётной записи или несовпадение области видимости дают сбой не на этапе публикации, а на этапе вычитывания образа в другом окружении. Симптом при этом выглядит как «сборка прошла, а развернуть не можем».
Наконец, деградация сборок: чем больше в реестре мусора, тем дольше идут операции выгрузки и очистки, тем чаще прогоны упираются в таймауты. Разбираем, как это закрывается на уровне политик хранения, схемы тегирования и прав доступа.
Что даёт выстроенный реестр образов
Реестр — это не «склад образов», а точка, где сходятся скорость сборки, скорость отката и целостность того, что уезжает в прод. Когда он выстроен, эффект виден в измеримых величинах: сборка перестаёт каждый раз тянуть базовые слои из внешних источников, потому что они лежат локально и переиспользуются между задачами, а время восстановления после сбоя определяется не поиском нужной версии, а одной командой отката на конкретный тег.
Первый измеримый эффект — скорость. Кэш слоёв на стороне реестра и переиспользование базовых образов внутри сети снимают повторную загрузку одних и тех же зависимостей: типичный шаг сборки сокращается в разы, а не на проценты. Второй — время восстановления. Когда каждый релиз помечен неизменяемым тегом и связан с коммитом, откат перестаёт быть археологией: инженер возвращает предыдущий рабочий образ за минуты, а не собирает его заново из старой ветки.
Третий эффект — устранённые классы отказов. Уходит «собралось у меня, упало на стенде» из-за разных базовых слоёв, уходит ручная заливка образов мимо конвейера, уходит ситуация, когда в прод уехал тег, перезаписанный поверх старого. Целостность обеспечивается тем, что тег указывает на один и тот же дайджест, а прослеживаемость — связкой «образ → коммит → задача → автор».
Именно эту логику мы закладываем при настройке реестра GitLab Container Registry: политики хранения, разграничение доступов и автоматическая публикация из конвейера, чтобы реестр отражал реальное состояние кода, а не намерения.
Сравнение подходов к хранению образов
Выбор между встроенным реестром, внешним хранилищем и гибридной схемой определяется не удобством, а тем, где живут сборка, рантайм и политика доступа. Встроенный реестр в GitLab даёт минимум движущихся частей: аутентификация наследуется из проекта, права на чтение и запись совпадают с ролями, а очистка образов управляется теми же правилами жизненного цикла, что и остальные артефакты. Ограничение — реестр живёт на том же контуре, что и сам GitLab, и делит с ним дисковое пространство и пропускную способность.
Внешнее хранилище снимает нагрузку с основного контура и позволяет разнести сборку и выдачу образов по разным зонам доступности. Плата за это — отдельный слой аутентификации, синхронизация прав и свой механизм удаления устаревших тегов: забытая политика очистки превращает хранилище в свалку, которая растёт быстрее, чем приходят релизы. Гибридная схема берёт лучшее из обоих: сборка идёт во встроенный реестр, а выдача в рантайм — через внешнее зеркало с прогревом.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Встроенный реестр | Небольшая команда, единый контур, короткий путь от сборки до деплоя | Делит ресурсы с GitLab, ограничен масштабом одного контура |
| Внешнее хранилище | Несколько кластеров, разнесённые зоны, высокая частота выдачи образов | Отдельная аутентификация, ручная синхронизация прав и очистки |
| Гибридная схема | Сборка в одном месте, рантайм в нескольких, нужен прогрев кэша | Сложнее в настройке, требует согласованных политик тегирования |
На практике выбор сводится к двум вопросам: сколько контуров потребляют образы и кто отвечает за их удаление. Если ответ один — встроенного реестра достаточно. Если контуров несколько и между ними есть сетевые границы, гибридная схема окупается временем выдачи образа при деплое.
Этапы внедрения и настройки
Работу начинаем с аудита текущего конвейера: смотрим, где собираются образы, куда публикуются, как устроены права доступа и сколько времени занимает цикл от коммита до готового артефакта. На этом этапе фиксируем узкие места — дублирующиеся сборки, отсутствие кеша слоёв, ручные шаги при выпуске. По итогам аудита согласуем схему: какие репозитории и теги заводим, как разделяем доступ между командами и средами, где хранятся секреты для авторизации в реестре.
Настройка и проверка
- Аудит. Разбираем текущие сборки, публикацию образов, права и время прохождения конвейера — получаем карту узких мест.
- Схема. Проектируем структуру репозиториев и тегов, политику доступа по ролям, правила очистки старых образов.
- Настройка реестра. Поднимаем хранилище, подключаем аутентификацию, настраиваем лимиты и политики хранения.
- Интеграция с конвейером. Встраиваем сборку и публикацию образов в автоматический выпуск, добавляем кеш слоёв и проверки безопасности.
- Проверка. Прогоняем тестовый релиз: сборка, публикация, развёртывание, откат на предыдущий тег — убеждаемся, что всё воспроизводится.
- Передача. Отдаём команде документацию, доступы и регламент работы с реестром, обучаем инженеров.
После проверки фиксируем метрики: время сборки, долю автоматизированных шагов, скорость отката. Передача включает не только доступы, но и понятный регламент — как выпускать образы, как чистить реестр, что делать при сбое публикации. Опишите вашу задачу — вернёмся с оценкой и планом работ.
Что заказчик получает на руки
После сдачи проекта у вас остаётся не «доступ к серверу», а комплект, по которому инфраструктуру можно передать другой команде или поднять заново без нас. Всё, что мы настраиваем, фиксируется в репозитории и документации — никаких ручных действий «по памяти».
- Конфигурации хранилища и сборки: файлы настройки реестра, манифесты развёртывания, параметры хранения и очистки образов — в системе контроля версий, с историей изменений.
- Схема потока образов: от сборки в задании до публикации в реестре и выдачи в среду — с точками, где проверяются права и подписи.
- Политики доступа: роли и области видимости токенов, разделение прав на чтение и запись, правила для внешних потребителей и ботов сборки.
- Регламент очистки: сколько образов и тегов хранится, что удаляется автоматически, как сохраняется возможность отката на предыдущий релиз.
- Документация по эксплуатации: как выпустить образ, как отозвать доступ, как восстановить реестр из резервной копии, к кому идти при сбое.
- Схема резервного копирования и восстановления: периодичность, место хранения копий, проверенный сценарий подъёма после отказа.
- Чек-лист приёмки и передачи: перечень проверок, которые подтверждают, что конвейер и реестр работают штатно после смены ответственного.
Каждый пункт мы проговариваем с вашей командой на этапе передачи — чтобы документ не остался формальностью, а совпадал с реальным состоянием системы. Опишите задачу — вернёмся с оценкой и планом.
Кейс: как сократили время сборки втрое
Клиент — продуктовая команда из 14 разработчиков, монорепозиторий, 6 сервисов. Сборка образа занимала 19 минут: на каждый коммит пересобирались все слои, потому что кеш не переиспользовался между раннерами. Реестр рос бесконтрольно — теги накапливались без политики, объём хранилища перевалил за терабайт, а половина образов не собиралась вообще.
GitLab Container Registry подключили как основной реестр рядом с конвейером. Разделили сборку на базовый слой с зависимостями и прикладной — базовый пересобирается только при изменении манифеста, остальное берётся из кеша. Включили распределённый кеш между раннерами, чтобы параллельные задачи не собирали одно и то же дважды.
Что изменилось в цифрах
| Метрика | До | После |
|---|---|---|
| Время сборки образа | 19 мин | 6 мин |
| Доля упавших сборок | 11% | 2% |
| Объём хранилища | 1,1 ТБ | 340 ГБ |
Сбои почти ушли за счёт двух вещей: сборка перестала зависеть от внешних загрузок в момент запуска, а тег всегда указывает на неизменяемый образ — откат на предыдущий релиз занимает минуты, а не часы разбирательств.
Что сделали с хранилищем
Правило жизненного цикла держит последние 10 образов на тег и чистит остальное — реестр перестал расти, при этом откат на предыдущую версию остаётся возможным. Отдельно настроили удаление «висячих» слоёв, которые остаются после перезаписи тега: именно они давали треть объёма.
Сборка сократилась втрое, объём хранилища — втрое с лишним, доля сбоев упала в пять раз. Команда перестала ждать конвейер и чистить реестр вручную.
Чем отличается GitLab Container Registry от внешнего реестра?
Встроенный реестр — это часть самого GitLab: образы хранятся рядом с кодом, пайплайнами и задачами, а не в отдельном сервисе. Для сборки это означает, что после docker build образ уходит в тот же проект, где живёт исходник, и следующий шаг пайплайна забирает его без настройки внешних учётных данных и сетевых маршрутов. Внешний реестр требует отдельной интеграции: свои токены, свои правила доступа, отдельный контур для CI-раннеров, и всё это нужно синхронизировать с жизненным циклом проекта в GitLab.
Управление доступом в обоих случаях строится на токенах, но логика разная. Во встроенном реестре права наследуются от ролей проекта: разработчик пушит образы своей ветки, релизный инженер — теги, гость только читает. Отзывается доступ в одном месте — при удалении участника из проекта он теряет и доступ к образам, что закрывает типовую дыру, когда уволенный сотрудник сохраняет pull-токен внешнего реестра. Во внешнем решении роли приходится вести параллельно и сверять вручную, а рассинхрон между двумя системами — источник инцидентов с утечкой приватных образов.
Стоимость владения складывается не из тарифа, а из сопутствующей работы. Встроенный реестр не требует отдельного сервиса, его резервного копирования, мониторинга доступности и обновления — эти задачи уже закрыты эксплуатацией самого GitLab. Внешний реестр добавляет ещё один компонент в отказоустойчивый контур: сетевые политики между раннерами и реестром, отдельные ключи шифрования, свой график обновлений. Плюс политики хранения: lifecycle-правило чистит старые теги, но настраивать его нужно в каждой системе отдельно.
Практический выбор зависит от масштаба. Пока команда и число проектов умеренные, встроенный реестр даёт меньше движущихся частей и предсказуемое поведение при откате — образ предыдущего релиза лежит там же, где его собрали. Внешний реестр оправдан, когда образы потребляют кластеры за пределами GitLab, нужна единая точка для нескольких платформ или геораспределённая раздача. Тогда интеграция и синхронизация доступов становятся осознанной платой за независимость хранилища от системы сборки.
Технические сомнения и ответы
Разберём вопросы, которые чаще всего всплывают на этапе проектирования и после запуска: доступы, рост объёма, переезд между реестрами и совместимость с текущими сборками.
Как разграничить доступ к образам между командами и средами?
Права выдаём на уровне проекта и группы: разработчики пушат в свои ветки, сборщик — в промежуточные теги, продакшн-теги закрыты отдельной ролью. Для внешних потребителей используем токены с ограниченным сроком и областью видимости только на чтение. Секреты не хранятся в конфигурации сборки — передаются через защищённые переменные, доступные лишь на защищённых ветках.
Что будет с реестром, когда образов станут тысячи?
Рост объёма — вопрос политики, а не размера диска. Lifecycle-правила держат последние N образов на тег и удаляют остальное по расписанию, поэтому реестр не растёт бесконтрольно, а откат на предыдущий релиз остаётся возможным. Дополнительно кэш сборки выносим на отдельный том, чтобы он не конкурировал за место с рабочими образами.
Как переехать с другого реестра без простоя?
Миграцию делаем поэтапно: сначала настраиваем синхронизацию, затем переключаем сборки на новый адрес, а потребителей — по одному, с проверкой на каждом шаге. Старый реестр остаётся доступен только на чтение, пока не убедимся, что все разворачивания идут из нового. Обратный откат возможен на любом этапе, пока старый адрес не отключён.
Совместим ли он с нашими текущими сборками и разворачиванием?
Реестр работает по стандартному протоколу образов, поэтому существующие сборки и оркестратор подключаются сменой адреса и учётных данных — переписывать конвейеры не нужно. Отдельно проверяем сценарии с несколькими архитектурами и подписью образов, если они уже используются. Если в конвейере есть свои проверки безопасности, они продолжают работать поверх новых адресов.
Как понять, что реестр настроен правильно?
Критерий простой: сборка публикует образ, разворачивание забирает именно его, а старые версии удаляются по правилу, не задевая актуальные. Плюс журнал доступа показывает, кто и когда обращался к образам. Эту проверку прогоняем до передачи в работу, а не после первого сбоя.
Обсудим вашу задачу
Чтобы вернуться с оценкой и планом, а не с общими словами, нам нужен контекст вашей задачи. Опишите, как сейчас устроен выпуск образов: где собираются, куда публикуются, кто и как забирает их на стенды. Этого достаточно, чтобы понять объём работ и риски.
Дальше работа идёт по шагам:
- Разбираем текущий процесс сборки и публикации образов — где ручные операции, где узкие места, что ломается чаще всего.
- Уточняем требования: сколько окружений, какие политики хранения, нужны ли отдельные реестры под команды и проекты.
- Готовим план внедрения GitLab Container Registry с привязкой к вашим репозиториям и сборочным заданиям.
- Согласуем схему прав доступа и разграничение по ролям — кто публикует, кто только забирает образы.
- Настраиваем автоматическую очистку старых версий, чтобы реестр не разрастался бесконтрольно.
- Прогоняем сборку и доставку на одном сервисе как пилот, замеряем время и стабильность.
- Переводим остальные сервисы и передаём документацию вашей команде.
Что нам важно получить от вас на старте:
- список сервисов и окружений, которые нужно подключить;
- как сейчас хранятся и версионируются образы;
- требования к срокам хранения и откату на предыдущие версии;
- кто со стороны вашей команды будет принимать работу;
- ограничения по инфраструктуре, если они есть.
Опишите задачу в удобной форме — вернёмся с оценкой сроков, составом работ и планом по этапам.







