BuildKit давно перестал быть просто «ускорителем сборок». Сейчас это инструмент, который помогает одновременно решать три задачи: быстрее собирать образы, не светить секреты в слоях и повышать доверие к результату сборки за счёт метаданных (SBOM и provenance). Ниже — практичные паттерны, которые удобно использовать на VDS или в CI.
Что такое Docker BuildKit и чем он отличается от «старого» билдера
Docker BuildKit — современный движок сборки: умеет параллелить шаги, лучше кешировать, подключать внешние источники (SSH, secrets, cache mounts) и выпускать дополнительные артефакты: SBOM (состав компонентов) и provenance (происхождение сборки).
Терминология, чтобы не путаться:
- BuildKit — движок сборки.
- buildx — CLI-плагин, который управляет BuildKit, билдерами, multi-arch и расширенными «выходами» (outputs), включая аттестации.
- docker cache — не один кеш, а набор механик: layer cache, inline cache, registry cache, local cache и cache mounts.
Если вы видите флаги вроде --secret, --ssh, --cache-to, --provenance, --sbom, — вы уже в мире BuildKit/buildx.
Как включить BuildKit и проверить, что он реально используется
В современных версиях Docker BuildKit часто включён по умолчанию, но в инфраструктуре встречаются разные Docker Engine/раннеры. Поэтому полезно уметь быстро диагностировать, чем именно вы собираете образ.
Временное включение через переменную окружения
DOCKER_BUILDKIT=1 docker build -t demo:buildkit .
Обычно вы сразу заметите «красивый» прогресс-вывод с параллельностью — это почти всегда BuildKit.
Проверка buildx и создание отдельного билдера
docker buildx version
docker buildx ls
Для CI и повторяемости лучше явно создать отдельный билдер и использовать его в пайплайне:
docker buildx create --name fastfox-builder --use
docker buildx inspect --bootstrap
Практика: в CI удобнее поднимать билдера перед сборкой и удалять после. Так меньше сюрпризов от «залипшей» конфигурации и неожиданного кеша между пайплайнами.
Если вы хотите углубиться именно в практику кеша, пригодится отдельный материал: cache mounts в Docker BuildKit: где реально ускоряют сборку.
BuildKit особенно хорошо раскрывается на выделенном окружении, где можно стабильно настроить билдера, кеш и права доступа: для этого удобен VDS под CI-раннер или сборочный хост.

Build secrets: как передавать секреты в сборку и не оставить их в образе
Частая ошибка — прокидывать токены через ARG/ENV или копировать ключи в контекст сборки. Так секреты легко попадут в историю слоёв, кеш или логи. BuildKit решает это через build secrets: секрет монтируется только на время выполнения команды и не сохраняется в итоговых слоях.
Секрет из файла: --secret id=...,src=...
Сценарий: нужно скачать приватные зависимости (npm/pip/composer) с токеном.
docker buildx build --secret id=npm_token,src=.npm_token -t app:secrets .
Dockerfile (важно: включаем синтаксис BuildKit):
# syntax=docker/dockerfile:1.7
FROM node:22-alpine AS build
WORKDIR /src
COPY package.json package-lock.json ./
RUN --mount=type=secret,id=npm_token sh -c 'TOKEN=$(cat /run/secrets/npm_token) && npm config set //registry.npmjs.org/:_authToken=${TOKEN} && npm ci'
COPY . .
RUN npm run build
- Секрет доступен как файл в
/run/secrets/<id>. - Не печатайте секреты в stdout/stderr: избегайте
set -x, verbose-режимов и команд, которые выводят конфиг целиком.
Секрет из переменной окружения (удобно в CI)
Если CI хранит секрет как env var, его можно передать без промежуточного файла:
docker buildx build --secret id=repo_token,env=REPO_TOKEN -t app:ci .
В Dockerfile используется тот же --mount=type=secret.
Когда нужен --ssh, а когда --secret
--secret — для токенов/конфигов/ключей API. --ssh — для доступа к Git по SSH (например, приватные submodules или приватные репозитории зависимостей).
docker buildx build --ssh default -t app:ssh .
И в Dockerfile:
# syntax=docker/dockerfile:1.7
RUN --mount=type=ssh git clone git@your-git.example:team/private-repo.git
Правило: секреты не должны попадать в final-стейдж. Если что-то приватное нужно только для сборки, делайте это в build-стейдже и копируйте в runtime-образ только результат (артефакты), а не исходники/конфиги с доступами.
Docker cache в BuildKit: как ускорить сборки и не сломать воспроизводимость
В BuildKit кеш — это не только слои. На практике чаще всего дают эффект: правильная структура Dockerfile, cache mounts для пакетных менеджеров и вынос кеша в registry/локальное хранилище для CI.
1) Структура Dockerfile: максимум стабильных слоёв в начале
Паттерн для большинства языков: сначала lock-файлы и установка зависимостей, и только потом исходники.
FROM node:22-alpine AS build
WORKDIR /src
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
При изменении исходников зависимости останутся закешированными.
2) Cache mounts: кешировать каталоги пакетов
Это ключевой приём, когда установка зависимостей «тяжёлая», а layer cache часто инвалидируется. Пример для npm:
# syntax=docker/dockerfile:1.7
RUN --mount=type=cache,target=/root/.npm npm ci
Пример для apt (важно: не забывайте чистить lists):
# syntax=docker/dockerfile:1.7
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt sh -c 'apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*'
Пример для Go:
# syntax=docker/dockerfile:1.7
RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build go build ./...
3) Inline cache: кеш «внутри» образа
Подходит, когда вы пушите образ в registry и хотите, чтобы следующий билд подтянул кеш из ранее опубликованного артефакта:
docker buildx build --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from type=registry,ref=repo/app:buildcache -t repo/app:latest --push .
Но в CI чаще удобнее отдельный артефакт кеша через --cache-to/--cache-from.
4) Registry cache: отдельный кеш-артефакт
Часто лучший баланс для CI: кеш живёт в registry отдельно и не засоряет продовые теги.
docker buildx build --cache-from type=registry,ref=repo/app:cache --cache-to type=registry,ref=repo/app:cache,mode=max -t repo/app:latest --push .
Параметр mode=max сохраняет больше промежуточных слоёв и повышает шанс попадания в кеш.
5) Local cache: кеш на диске раннера
Если у вас self-hosted раннер на постоянной машине, локальный кеш может быть очень быстрым:
docker buildx build --cache-from type=local,src=/tmp/.buildx-cache --cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max -t app:local .
После сборки обычно делают атомарную замену каталога кеша:
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
Кеш и воспроизводимость: где грань
Кеш ускоряет сборку, но не делает её «правильной». Чтобы получить предсказуемые результаты:
- фиксируйте версии базовых образов (часто лучше digest, если это вписывается в вашу политику),
- используйте lock-файлы,
- не полагайтесь на «плавающие» репозитории без pinning версий,
- разделяйте кеши по веткам/окружениям, если зависимости могут существенно отличаться.

SBOM: что это, зачем и как получать в BuildKit
SBOM (Software Bill of Materials) — «ведомость материалов» ПО: какие пакеты и библиотеки попали в артефакт, какие версии и какие зависимости. На практике SBOM помогает быстрее оценивать влияние уязвимостей, упрощает аудит и делает состав образа прозрачным для эксплуатации.
Генерация SBOM при сборке (buildx)
BuildKit/buildx умеет выпускать SBOM как часть сборки:
docker buildx build --sbom=true -t repo/app:latest .
Если вы пушите образ, SBOM обычно прикрепляется как аттестация рядом с образом (поведение зависит от версии Docker/buildx и настроек registry).
Практический совет: SBOM как артефакт CI
Подход «SBOM создаётся в процессе сборки» удобен тем, что состав фиксируется в момент выпуска артефакта. Так меньше шанс, что вы собрали одно, а просканировали потом другое.
Как правило, модель «образ + SBOM + provenance публикуются вместе в одном пайплайне» быстрее закрывает вопросы безопасности и заказчиков.
Provenance: как добавить происхождение сборки и укрепить supply chain
Provenance — метаданные о том, как получился артефакт: откуда исходники, какая ревизия, какой билдер и параметры. Это важная часть supply chain security: вы можете формально доказать, что образ собран вашим CI из конкретного исходного кода, а не подменён по пути.
Включение provenance при сборке
docker buildx build --provenance=true -t repo/app:latest .
Иногда нужно управлять детализацией, чтобы не раскрывать лишние сведения о сборочном окружении. Конкретные опции зависят от версии buildx, но принцип один: для публичных образов часто выбирают более «сдержанный» provenance, а во внутреннем registry можно хранить расширенный.
Если вы публикуете образы наружу или отдаёте их клиентам, добавьте транспортный уровень защиты: SSL-сертификаты пригодятся для фронтендов и внутренних панелей, которые обслуживают ваш реестр, артефакты и CI-интерфейсы.
Сборка “по-взрослому”: пример Dockerfile с secrets, cache mounts и multi-stage
Ниже — шаблон, который легко адаптировать под Node/Python/Go. Идея: секреты доступны только в build-стейдже, зависимости кешируются, а финальный образ минимален.
# syntax=docker/dockerfile:1.7
FROM node:22-alpine AS build
WORKDIR /src
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm --mount=type=secret,id=npm_token sh -c 'TOKEN=$(cat /run/secrets/npm_token) && npm config set //registry.npmjs.org/:_authToken=${TOKEN} && npm ci'
COPY . .
RUN npm run build
FROM nginx:1.27-alpine AS runtime
COPY --from=build /src/dist /usr/share/nginx/html
EXPOSE 80
Команда сборки (включаем и аттестации, и секрет):
docker buildx build --secret id=npm_token,src=.npm_token --sbom=true --provenance=true -t repo/app:latest .
Типичные ошибки и как их избегать
Секреты попали в слой
Если вы делаете RUN echo $TOKEN > .npmrc и файл остаётся в слое, секрет утечёт. Решение: build secrets и работа с временными файлами строго в рамках одного RUN (или вообще без записи на диск, если инструмент позволяет).
Секреты всплыли в логах
BuildKit не «прячет» всё автоматически. Если команда печатает токен в stdout/stderr, CI его увидит. Проверяйте скрипты на set -x, на вывод конфигов и на verbose-режимы.
Кеш “ломает” ожидаемые обновления
Например, вы ожидаете, что apt-get update всегда обновит индексы, но кешируете слой слишком агрессивно. Решение: аккуратно разделяйте кеш каталога (cache mount) и кеш слоя, и осознанно управляйте инвалидированием (файлы, аргументы, версии).
SBOM/provenance включили, но нигде не хранится
Если вы собираете локально без --push, артефакты могут не оказаться там, где их ждёт команда. Для рабочего процесса обычно нужен registry и политика хранения аттестаций рядом с образами.
Чек-лист: минимальный набор для безопасной и быстрой сборки
- BuildKit включён, сборка идёт через buildx-билдер.
- Секреты только через
--secret/--ssh, не черезARG/ENV. - Dockerfile построен так, чтобы зависимости кешировались стабильно (lock-файлы отдельно).
- Используются cache mounts для пакетных менеджеров.
- В CI настроен registry cache или local cache (в зависимости от типа раннера).
- Для релизных сборок включены
--sbomи--provenance.
Итог
Docker BuildKit закрывает сразу несколько болей: ускоряет сборки за счёт продвинутого кеша, даёт безопасные build secrets без утечек в слои и добавляет прозрачность supply chain через SBOM и provenance. Если вы поддерживаете несколько проектов и хотите предсказуемые релизы, эти фичи обычно окупаются за пару итераций CI.
Следующий логичный шаг — стандартизировать шаблоны Dockerfile и правила кеширования на уровне команды и CI, чтобы все сервисы собирались одинаково безопасно и повторяемо.


