Билдеры и драйверы:
По умолчанию buildx работает через драйвер docker, встроенный в демон. Он быстрый, но с классическим image store не умеет ни multi-platform, ни экспорт кэша в registry. Для серьёзных задач создаём билдер на драйвере docker-container, он крутится в отдельном контейнере с полноценным BuildKit:
Код: Выделить всё
docker buildx create --name ci --driver docker-container --use
docker buildx inspect --bootstrap
docker buildx lsТипичная картина 2026 года: разработчики на Apple Silicon (arm64), прод на amd64, плюс пара дешёвых ARM-виртуалок под фоновые задачи. Один тег обязан работать везде. Это решает OCI image index: под одним тегом лежат манифесты для каждой платформы, и docker pull сам выбирает нужный.
Код: Выделить всё
docker run --privileged --rm tonistiigi/binfmt --install arm64
docker buildx build --platform linux/amd64,linux/arm64 \
-t cr.yandex/crp1abc/app:1.4.0 --push .Код: Выделить всё
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS build
ARG TARGETOS TARGETARCH
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH \
go build -o /out/app ./cmd/app
FROM gcr.io/distroless/static-debian12
COPY --from=build /out/app /app
USER nonroot
ENTRYPOINT ["/app"]ARG для токенов не годится: значения остаются в docker history и в метаданных образа. BuildKit монтирует секрет в RUN на время одной инструкции, в слои он не попадает:
Код: Выделить всё
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
npm ci --omit=devКод: Выделить всё
docker buildx build --secret id=npmrc,src=$HOME/.npmrc -t app:dev .
docker buildx build --secret id=token,env=NPM_TOKEN -t app:dev .Экспорт кэша:
На ноутбуке кэш слоёв живёт сам по себе. В CI раннеры обычно эфемерные, и каждая сборка стартует с нуля. Лечится экспортом кэша во внешнее хранилище, чаще всего в тот же registry:
Код: Выделить всё
docker buildx build \
--cache-from type=registry,ref=cr.yandex/crp1abc/app:buildcache \
--cache-to type=registry,ref=cr.yandex/crp1abc/app:buildcache,mode=max \
--platform linux/amd64,linux/arm64 \
-t cr.yandex/crp1abc/app:1.4.1 --push .Типичные грабли:
Секрет через ARG. Прогоните по старым образам docker history --no-trunc, токены там лежат открытым текстом. Такие токены надо перевыпускать, чистка Dockerfile не поможет, образ уже скачали.
--load с несколькими платформами падает на классическом image store: локальный Docker не умеет хранить image index. Либо --push сразу в registry, либо включайте containerd image store (галка в настройках Docker Desktop, в Engine опция containerd-snapshotter в daemon.json).
RUN --mount=type=cache не выгружается через --cache-to. Кэш-маунты живут только внутри конкретного билдера, на эфемерном раннере от них толку нет.
QEMU-эмуляция замедляет сборку в 5-10 раз, а отдельные рантаймы под ней просто зависают. Если arm64-сборка стала узким местом, берите нативный ARM-раннер вместо эмуляции.
Итог:
buildx это не экзотика, а нормальный режим работы docker build. Multi-platform через image index, секреты через mount вместо ARG, кэш в registry с mode=max. В следующей главе соберём из этих кусков конвейер CI/CD: автосборка по коммиту, сканирование Trivy и публикация по тегу.