Що таке BuildKit і які переваги він надає?
BuildKit це сучасний Docker build engine. Legacy-builder це той, що Docker шиппив з 2014; BuildKit замінив його як дефолт у Docker 23 (2023). Різниці видно одразу: швидші білди, кращий cache, нові Dockerfile-фічі, без leak secret.
Теорія
TL;DR
- Дефолт з Docker 23 (2023). Старіші версії Docker мали його opt-in через
DOCKER_BUILDKIT=1. - Побудовано на іншій архітектурі: паралельне виконання стейджів, content-addressable граф операцій, pluggable frontend.
- П'ять killer-фіч над legacy:
- Паралельний multi-stage — незалежні стейджі білдять конкурентно.
- Cache mounts —
RUN --mount=type=cacheтримає cache між білдами без запікання у image. - Secret mounts —
RUN --mount=type=secretдля build-time secret, ніколи у image. - Розумніший cache key —
COPYінвалідує лише на реальні зміни файлів, не на mtime директорії. - Директива
# syntax=— пін frontend-версії Dockerfile, нові інструкції без апгрейду daemon.
- Доступ через
docker buildx(BuildKit-aware CLI-розширення).
Архітектура vs legacy-builder
Legacy-builder: BuildKit:
Лінійно, послідовно Граф-based, паралельно
Вбудовано у dockerd Окремий engine (може бути remote)
Без cache-mount First-class cache-mount
ARG-значення leak у history Secret-mount (без leak)
Один Dockerfile-парсер Pluggable frontend (#syntax=)
Повільні rebuild Розумна cache-інвалідаціяBuildKit по суті це новий build-daemon з іншою mental-model, операції утворюють DAG, BuildKit їх планує.
Killer-фіча 1: паралельні стейджі
FROM golang:1.23 AS go-builder
RUN go build -o /out/server ./cmd/server
FROM rust:1.81 AS rust-builder
RUN cargo build --release --bin tool
FROM ubuntu:24.04
COPY /out/server /usr/local/bin/
COPY /target/release/tool /usr/local/bin/Legacy-builder: будує Go-стейдж, потім Rust-стейдж, потім runtime. Послідовно. BuildKit: Go і Rust-стейджі білдять паралельно. Wall-clock час = max обох, не сума.
Killer-фіча 2: cache-mount
# syntax=docker/dockerfile:1.7
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN \
pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]Pip wheel-cache живе у Docker-managed cache-директорії поза image. Наступні білди з тим же requirements.txt перевикористовують кешовані wheels. Image лишається малим (без pip-cache, запеченого); білд лишається швидким.
Поширені targets:
- pip:
/root/.cache/pip - npm:
/root/.npm - apt:
/var/cache/aptі/var/lib/apt/lists(зsharing=locked) - Go:
/go/pkg/mod - Cargo:
/usr/local/cargo/registry
Killer-фіча 3: secret-mount
# syntax=docker/dockerfile:1.7
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN \
npm ci
COPY . .docker buildx build --secret id=npmrc,src=$HOME/.npmrc -t myapp ..npmrc змонтовано у білд, але ніколи не приземляється у жоден image-шар. docker history не показує сліду; pulled-image його не містять.
Порівняй з поганим патерном:
# НЕПРАВИЛЬНО: ARG з'являється у image-history
ARG NPM_TOKEN
RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc && npm cidocker history --no-trunc показує RUN-рядок, включно з токеном.
Killer-фіча 4: розумніший cache key
Legacy-builder інвалідував COPY за file-timestamps (mtime). Touch файлу без редагування тригерив cache-miss.
BuildKit: cache-key для COPY це content-hash файлів. mtime-зміни не інвалідують. Лише реальні content-зміни.
Killer-фіча 5: директива # syntax=
# syntax=docker/dockerfile:1.7
# Тепер маєш доступ до:
# --mount=type=cache
# --mount=type=secret
# --mount=type=ssh
# --mount=type=tmpfs
# here-doc синтаксис (RUN <<EOF ... EOF)
# Anonymous build stages з named outputДиректива пінить Dockerfile-frontend image. Нові фічі шиппяться без апгрейду daemon, просто бамп syntax-версію.
Увімкнення BuildKit (коли не дефолт)
# Per-shell
export DOCKER_BUILDKIT=1
docker build -t myapp .
# Per-build
DOCKER_BUILDKIT=1 docker build -t myapp .
# Daemon-wide (старіший Docker)
# /etc/docker/daemon.json
{ "features": { "buildkit": true } }Docker 23+ має BuildKit увімкненим за замовчуванням; старіші версії потребують явного opt-in. Підтверди:
docker buildx version
# github.com/docker/buildx v0.17.0 ...Якщо buildx встановлено і працює, BuildKit доступний.
docker buildx — BuildKit-aware CLI
docker buildx build -t myapp . # як docker build, але з BuildKit-фічами
docker buildx build --platform linux/amd64,linux/arm64 # multi-arch в одному заході
docker buildx build --cache-to type=registry,ref=cache # registry cache export
docker buildx build --cache-from type=registry,ref=cache # registry cache import
docker buildx build --provenance=true --sbom=true # SLSA provenance + SBOMbuildx це те, що ти реально викликаєш для повних BuildKit-фіч. Звичайний docker build теж працює на Docker 23+ (використовує BuildKit під капотом).
Типові помилки
Забути директиву # syntax= при використанні нових фіч
# Не працюватиме, потребує syntax-директиви
RUN pip install ...Додай # syntax=docker/dockerfile:1.7 (або вище) нагорі Dockerfile.
Білд без buildx-builder для multi-arch
$ docker buildx build --platform linux/amd64,linux/arm64 -t myapp .
ERROR: Multi-platform builds require a builder instance.Фікс: docker buildx create --use --name multi-builder спочатку. Дефолтний builder може бути single-platform Docker-driver.
Плутати docker build і docker buildx build
У Docker 23+ обидва викликають BuildKit. Але деякі флаги (--platform, --cache-from type=registry) працюють краще на buildx. Для складного CI бери buildx.
Сприймати BuildKit cache-mount як image-content
RUN \
make && cp -r /build-output/* /app/
# Після цього RUN /build-output зник (це був mount, не частина image).Cache-mount зникають після RUN. Щоб дістати content у image, копіюй у звичайний шлях у тому самому RUN.
Реальний impact
- CI build-час: типовий Node/Python проект з 5 хвилин (legacy) → 90 секунд (BuildKit + cache-mount).
- Image-розмір: менший, бо cache-директорії більше не запікаються.
- Secret-гігієна: secret-leak через ARG-history переважно ліквідовано.
- Multi-arch: один CI-крок будує для amd64 + arm64. Критично для кластерів, що міксують CPU.
- Supply chain:
--provenance=true --sbom=trueдає SLSA-attested білди для верифікації admission-controller.
Питання для поглиблення
Q: Чи потрібен мені BuildKit, якщо мій Dockerfile простий?
A: Це дефолт у сучасному Docker, ти використовуєш BuildKit, якщо спеціально не вимикав. Навіть прості Dockerfile виграють від швидшого cache.
Q: Що таке buildx vs BuildKit?
A: BuildKit це engine. buildx це CLI-plugin, що говорить з BuildKit (і підтримує multi-platform, multi-cache тощо). docker buildx ... це як ти користуєшся повними BuildKit-фічами.
Q: Як мігрувати існуючі Dockerfile на BuildKit?
A: Вони працюють as-is на BuildKit (backward-compatible). Щоб отримати нові фічі, додай # syntax=docker/dockerfile:1.7 нагорі, тоді починай використовувати --mount=type=cache і --mount=type=secret, де допомагає.
Q: Чи може BuildKit крутитися віддалено?
A: Так. docker buildx create --driver kubernetes ... або --driver remote дозволяє крутити білди на remote-кластері. Корисно для великих білдів, що не хочеш на лептопі.
Q: (Senior) Як BuildKit DAG-архітектура відрізняється від лінійного підходу legacy-builder?
A: Legacy: кожна Dockerfile-інструкція створювала шар послідовно; cache-перевірка per-instruction. BuildKit: білд це DAG операцій LLB (low-level builder); BuildKit їх планує на основі залежностей. Незалежні операції крутяться паралельно; cache-lookup на operation-рівні (часто більш гранулярно, ніж інструкції). DAG також відкриває нові фічі (mount-points, що існують лише під час конкретної операції, frontend-свопи для різних Dockerfile-варіантів синтаксису, розподілені білди).
Приклади
Максимально сучасний Dockerfile
# syntax=docker/dockerfile:1.7
FROM node:22-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN \
npm ci
FROM deps AS build
COPY . .
RUN npm run build
FROM node:22-alpine AS runtime
WORKDIR /app
COPY /app/dist /app/dist
COPY /app/node_modules /app/node_modules
USER node
CMD ["node", "dist/server.js"]Npm cache переживає між білдами; npmrc ніколи не у image; deps + build стейджі ділять роботу; runtime-стейдж тонкий.
CI registry-cache патерн
docker buildx build \
--cache-to type=registry,ref=ghcr.io/myorg/myapp:cache,mode=max \
--cache-from type=registry,ref=ghcr.io/myorg/myapp:cache \
--platform linux/amd64,linux/arm64 \
--provenance=true \
--sbom=true \
--push \
-t ghcr.io/myorg/myapp:1.0 .Multi-arch + registry-cache + provenance + SBOM в одній команді. CI-runner на різних машинах перевикористовують той самий cache.
Білд віддалено
$ docker buildx create --name remote --driver remote tcp://buildkit:1234 --use
$ docker buildx build -t myapp .
# Білд крутиться на remote BuildKit-daemon, не на лептопі.Корисно для shared-builder, GPU-accelerated білдів або просто щоб тримати лептоп вільним.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.
Коментарі
Ще немає коментарів