Настройка Docker Layer Caching для ускорения сборки

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

Почему Docker layer caching перестаёт работать: где теряются слои

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

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

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

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

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

Время сборки и частота отказов

Слои образа Docker кэшируются по содержимому инструкций: пока не менялся файл зависимостей, шаг установки пакетов берётся готовым. На типичном проекте сборка сокращается с 8–12 минут до 2–3, а доля попаданий в кэш держится на уровне 80–90% при правках в коде приложения. Частота отказов сборки падает отдельно: сетевой сбой при скачивании пакетов больше не роняет прогон целиком, повтор не начинается с нуля.

Объём хранилища и предсказуемость выката

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

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

Способы кэширования: локальный кэш, реестр образов, общий том

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

Режим под одну команду

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

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

Когда узлов несколько

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

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

Как мы настраиваем кэш сборки Docker: этапы работ

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

Подготовка и проверка

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

Выкат и передача

  • Выкатываем на рабочие ветки постепенно: сначала основная, затем остальные, следим за временем сборки и ростом хранилища кэша.
  • Передаём регламенты сборки: правила правки описания образа, что нельзя менять без согласования, памятка для разработчиков и порядок полного сброса кэша.

Что остаётся в репозитории: конфигурации, схемы и регламенты

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

Код и инфраструктура

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

Документация и доступы

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

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

Кейс: сборка монорепозитория ускорилась, доля отказов упала

Что было до работ

Монорепозиторий на сорок сервисов собирался в одном конвейере Docker: общий реестр образов, общий исполнитель, одна ветка на все команды. Слои с зависимостями пересобирались при любом изменении в дереве — правка в одном сервисе тянула переустановку пакетов по всему репозиторию, полный проход занимал 22–26 минут.

Очередь росла: пока собирается один сервис, остальные ждут освобождения исполнителя. Инженеры перестали ждать результат и стали проверять локально, часть ошибок доходила до основной ветки. Доля отказов держалась на 18%, и класс сбоев «собрано на устаревших зависимостях» воспроизводился регулярно.

Что изменилось после

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

Полный проход сократился с 22–26 до 6–8 минут, повторная сборка неизменённого сервиса укладывается в минуту. Доля отказов упала с 18% до 4%: тот самый класс ошибок закрыт конструкцией кэша, а не регламентом. Реестр перестал расти — политика жизненного цикла держит последние десять образов на тег и чистит остальное, откат на предыдущую сборку остаётся возможным.

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

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

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

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

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

Частые технические сомнения по кэшированию сборок

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

Две сборки идут одновременно — не перемешают ли они кэш?

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

Обновился базовый образ — кэш останется валидным?

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

Перенесётся ли кэш на другой узел или сборочный агент?

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

Кэш безопасен? Не останутся ли в нём секреты?

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

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

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

Что отдаём в ответ:

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

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

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

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

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