Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке BuildKit і які переваги він надає?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**BuildKit** це сучасний Docker build engine, дефолт з Docker 23. Значно швидший за legacy-builder завдяки паралельному виконанню стейджів, розумнішому кешу, cache-mount, secret-mount і pluggable frontend. ```dockerfile # syntax=docker/dockerfile:1.7 FROM python:3.13-slim RUN --mount=type=cache,target=/root/.cache/pip pip install -r req.txt RUN --mount=type=secret,id=npmrc cp /run/secrets/npmrc ~/.npmrc ``` **Головне:** BuildKit відкриває п'ять речей, що legacy-builder не може: паралельні multi-stage білди, персистентні cache-mount (pip/npm/apt), secret-mount (без leak у image), краща cache-інвалідація і директива `# syntax=` для нових Dockerfile-фіч.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**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: 1. **Паралельний multi-stage** — незалежні стейджі білдять конкурентно. 2. **Cache mounts** — `RUN --mount=type=cache` тримає cache між білдами без запікання у image. 3. **Secret mounts** — `RUN --mount=type=secret` для build-time secret, ніколи у image. 4. **Розумніший cache key** — `COPY` інвалідує лише на реальні зміни файлів, не на mtime директорії. 5. **Директива `# 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: паралельні стейджі ```dockerfile 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 --from=go-builder /out/server /usr/local/bin/ COPY --from=rust-builder /target/release/tool /usr/local/bin/ ``` Legacy-builder: будує Go-стейдж, потім Rust-стейдж, потім runtime. Послідовно. **BuildKit: Go і Rust-стейджі білдять паралельно.** Wall-clock час = max обох, не сума. ### Killer-фіча 2: cache-mount ```dockerfile # syntax=docker/dockerfile:1.7 FROM python:3.13-slim WORKDIR /app COPY requirements.txt . RUN --mount=type=cache,target=/root/.cache/pip \ 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 ```dockerfile # syntax=docker/dockerfile:1.7 FROM node:22-alpine WORKDIR /app COPY package*.json ./ RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \ npm ci COPY . . ``` ```bash docker buildx build --secret id=npmrc,src=$HOME/.npmrc -t myapp . ``` `.npmrc` змонтовано у білд, але **ніколи не приземляється у жоден image-шар**. `docker history` не показує сліду; pulled-image його не містять. Порівняй з поганим патерном: ```dockerfile # НЕПРАВИЛЬНО: ARG з'являється у image-history ARG NPM_TOKEN RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc && npm ci ``` `docker 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=` ```dockerfile # 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 (коли не дефолт) ```bash # 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. Підтверди: ```bash docker buildx version # github.com/docker/buildx v0.17.0 ... ``` Якщо `buildx` встановлено і працює, BuildKit доступний. ### `docker buildx` — BuildKit-aware CLI ```bash 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 + SBOM ``` `buildx` це те, що ти реально викликаєш для повних BuildKit-фіч. Звичайний `docker build` теж працює на Docker 23+ (використовує BuildKit під капотом). ### Типові помилки **Забути директиву `# syntax=` при використанні нових фіч** ```dockerfile # Не працюватиме, потребує syntax-директиви RUN --mount=type=cache,target=/root/.cache/pip pip install ... ``` Додай `# syntax=docker/dockerfile:1.7` (або вище) нагорі Dockerfile. **Білд без buildx-builder для multi-arch** ```bash $ 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** ```dockerfile RUN --mount=type=cache,target=/build-output \ 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 ```dockerfile # syntax=docker/dockerfile:1.7 FROM node:22-alpine AS deps WORKDIR /app COPY package*.json ./ RUN --mount=type=cache,target=/root/.npm \ --mount=type=secret,id=npmrc,target=/root/.npmrc \ npm ci FROM deps AS build COPY . . RUN npm run build FROM node:22-alpine AS runtime WORKDIR /app COPY --from=build /app/dist /app/dist COPY --from=build /app/node_modules /app/node_modules USER node CMD ["node", "dist/server.js"] ``` Npm cache переживає між білдами; npmrc ніколи не у image; deps + build стейджі ділять роботу; runtime-стейдж тонкий. ### CI registry-cache патерн ```bash 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. ### Білд віддалено ```bash $ docker buildx create --name remote --driver remote tcp://buildkit:1234 --use $ docker buildx build -t myapp . # Білд крутиться на remote BuildKit-daemon, не на лептопі. ``` Корисно для shared-builder, GPU-accelerated білдів або просто щоб тримати лептоп вільним.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.