Настройка автоматической сборки Docker-образов в CI/CD

Выкладки вручную тормозят команду и зависят от того, кто именно собирает образ. Мы настраиваем автоматическую сборку Docker-образов в конвейере под ключ: от подготовки репозитория до передачи готового процесса вашей команде. Время на выпуск новой версии сокращается в разы, а человеческие ошибки при сборке уходят из процесса.
Часто задаваемые вопросы

Автоматическая сборка Docker-образов: где ломается процесс

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

Дальше расхождение окружений перестаёт быть теоретическим. Тестовая среда и рабочая расходятся по версиям библиотек и настройкам настолько, что дефект не воспроизводится ни там, ни там, а поиск причины идёт вслепую. Ручная выкладка релиза добавляет к этому человеческий фактор: образ собирается вручную перед выкаткой, тег ставится «на глаз», и по записи в реестре уже не понять, какой именно код в этом образе лежит.

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

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

Что меняется после перевода сборки на конвейер

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

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

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

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

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

Где запускать конвейер: агенты, контейнеры, свои серверы

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

Вариант Когда подходит Ограничения
Управляемые агенты провайдера Небольшая команда, своей инфраструктуры нет, нужен быстрый старт Лимит одновременных задач, таймаут на шаг, кэш слоёв не переживает смену машины
Свой сервер сборки Крупные образы, приватные зависимости, тяжёлые проверки Обслуживание, обновления и мониторинг на нас; при отказе очередь встаёт целиком
Конвейер в контейнере Нужна изолированная среда сборки на общем хосте Вложенная сборка требует отдельного демона или расширенных прав, сложнее считать диск
Сборка на том же хосте, что и рабочий сервис Внутренние утилиты, быстрая проверка гипотез Ресурсы конкурируют с продуктивом, риск уронить сервис вместе со сборкой

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

Этапы внедрения конвейера: от аудита до передачи

Собирать образы руками на рабочей машине можно, пока релиз один в неделю. Как только сервисов и веток становится больше, сборка уезжает в конвейер — и вопрос уже не «нужна ли автоматизация», а в каком порядке её внедрять, чтобы не сломать текущие релизы. Ниже — последовательность, по которой мы ведём проект: каждый этап заканчивается проверяемым результатом, а не отчётом.

  1. Аудит репозитория. Разбираем структуру веток, зависимости между сервисами, кто и как собирает Docker-образы сейчас. Фиксируем узкие места: ручные шаги, отсутствие кеша, разные базовые образы у разных команд.
  2. Схема конвейера. Согласуем, что запускается при коммите в ветку, что — при релизном теге, где сборка останавливается при падении тестов. Схему фиксируем до настройки, чтобы не переделывать шаги по ходу.
  3. Настройка шагов сборки. Включаем кеш слоёв, задаём правила тегирования, разделяем сборку и публикацию в реестр. На выходе — одинаковый образ из одного и того же коммита у любого инженера.
  4. Проверка на предпродуктивной среде. Прогоняем реальный релиз по новому конвейеру, сверяем результат с ручной сборкой, проверяем откат на предыдущий тег. Дефекты ловим здесь, а не на продуктивной среде.
  5. Регламенты. Описываем триггеры, переменные окружения, порядок откатa и доступы к секретам — чтобы правила не жили только в голове одного инженера.
  6. Передача документации. Отдаём схему конвейера, файлы конфигурации и инструкцию по типовым сбоям, вместе проходим один релиз от коммита до публикации.

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

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

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

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

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

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

Что ломалось до

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

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

Что изменили и что получили

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

  • Доля выкладок без переделок: с половины до 9 из 10.
  • Время от слияния до готового образа: с 25–40 минут до 6–8.
  • Откат: одной командой на предыдущий тег, около двух минут вместо ручного разбора.
  • Размер образа: сократился втрое за счёт многостадийной сборки и чистки кэша пакетов.

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

Чем отличается кеш слоёв от кеша зависимостей

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

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

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

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

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

Технические сомнения перед переводом на конвейер

Возражения перед переводом автоматической сборки docker-образов на конвейер касаются не самого инструмента, а того, что вокруг: доступов, секретов и поведения при сбое. Ниже — короткие ответы на то, что инженеры спрашивают чаще всего.

Что при недоступности реестра образов?

Конвейер различает «сборка упала» и «артефакт некуда положить»: во втором случае тег не публикуется, задача приостанавливается, а выкладка живёт на предыдущей версии. Реестр дублируем зеркалом.

Как разделяются права выпуска?

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

Где хранятся секреты сборки?

Значения подставляются в шаг сборки из хранилища секретов, в слои образа не попадают и маскируются в логах. Доступ к хранилищу есть у конвейера, а не у каждого разработчика.

Не остановится ли выкладка на время перехода?

Идём ветка за веткой: сначала конвейер собирает ровно то, что собирали руками, результат сверяем по контрольной сумме. Пока идёт сверка, ручной выпуск остаётся рабочим — окна простоя нет.

Почему конвейер часто падал у нас раньше?

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

Сомнение, которого нет в списке, разберём на вашей конфигурации.

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

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

Чтобы вернуться с оценкой и планом внедрения, обычно нужно от заказчика:

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

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

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

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

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1369
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    816
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1141