Ir para o conteúdo

BuildKit e buildx

BuildKit é o motor de build do Docker moderno (padrão desde o Docker 23). Ele substitui o builder legado e traz cache mais inteligente, execução paralela de estágios, montagens especiais no RUN (cache, secret, ssh, bind) e build multi-plataforma. buildx é a CLI que expõe esses recursos (docker buildx ...), hoje já embutida no Docker.

Ligando o BuildKit

Desde o Docker 23 já é o padrão. Para forçar em versões antigas:

export DOCKER_BUILDKIT=1
docker build -t app .

Todo Dockerfile que usa recursos do BuildKit deve começar com a diretiva de sintaxe, que também garante a versão mais recente do frontend:

# syntax=docker/dockerfile:1

RUN --mount: montagens durante o build

type=cache — cache persistente entre builds

Monta um diretório que sobrevive de um build para o outro sem entrar na imagem. Ideal para caches de gerenciadores de pacote:

# syntax=docker/dockerfile:1
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci
COPY . .

Outros exemplos de alvo:

# apt
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update && apt-get install -y --no-install-recommends curl

# pip
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt

# go
RUN --mount=type=cache,target=/root/.cache/go-build \
    --mount=type=cache,target=/go/pkg/mod \
    go build ./...

Para o cache de apt funcionar, remova a linha rm -rf /var/lib/apt/lists/* e apague o /etc/apt/apt.conf.d/docker-clean (RUN rm -f /etc/apt/apt.conf.d/docker-clean).

type=bind — montar o contexto sem COPY

Usa um arquivo do contexto de build só durante aquele RUN, sem criar camada:

RUN --mount=type=bind,source=go.sum,target=go.sum \
    --mount=type=bind,source=go.mod,target=go.mod \
    go mod download

type=secret — segredos que não vão para a imagem

# syntax=docker/dockerfile:1
FROM alpine
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
    npm ci
docker build --secret id=npmrc,src=$HOME/.npmrc -t app .

O arquivo existe só durante aquele RUN. Não aparece em docker history, não fica em camada, não fica no cache. É assim que se passa token de repositório privado, chave de licença, credencial de artefato.

type=ssh — usar o agente SSH do host

Para git clone de repositório privado por SSH:

RUN --mount=type=ssh git clone [email protected]:company/private-lib.git
docker build --ssh default -t app .

Cache externo: --cache-to / --cache-from

Em CI, cada job começa do zero. O BuildKit exporta e importa cache de um registry ou diretório:

docker buildx build \
  --cache-to   type=registry,ref=registry.example.com/app:buildcache,mode=max \
  --cache-from type=registry,ref=registry.example.com/app:buildcache \
  -t registry.example.com/app:1.2.3 --push .
  • mode=max exporta o cache de todas as camadas, inclusive as de estágios intermediários (multi-stage). mode=min (padrão) exporta só as da imagem final.
  • Alternativas de backend: type=local,dest=/path / type=gha (GitHub Actions) / type=inline (embute o cache na própria imagem, só mode=min).

Build multi-plataforma

Uma imagem que roda em amd64 e arm64 a partir de uma máquina só. Precisa de um builder com o driver docker-container:

docker buildx create --name multi --driver docker-container --use
docker buildx inspect --bootstrap

Build e push do manifesto multi-arch:

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t registry.example.com/app:1.2.3 \
  --push .

O --push é necessário aqui porque o armazenamento local de imagens do Docker tradicionalmente não guarda uma lista de manifestos multi-plataforma. Para carregar só a da sua máquina, use --load com um único --platform.

Emulação de outra arquitetura (quando não há runner nativo):

docker run --privileged --rm tonistiigi/binfmt --install all

No Dockerfile, use os argumentos automáticos para não emular a compilação:

# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:1.23 AS build
ARG TARGETOS TARGETARCH
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /out/app .

FROM alpine
COPY --from=build /out/app /usr/local/bin/app

$BUILDPLATFORM é a máquina que compila; $TARGETOS/$TARGETARCH são o destino — assim o Go faz cross-compile nativo, sem QEMU.

docker buildx bake

Descreve vários targets de build em um arquivo (docker-bake.hcl) e roda tudo com um comando — útil para monorepos:

group "default" {
  targets = ["api", "worker"]
}

target "api" {
  context    = "./api"
  tags       = ["registry.example.com/api:dev"]
  platforms  = ["linux/amd64", "linux/arm64"]
}

target "worker" {
  context = "./worker"
  tags    = ["registry.example.com/worker:dev"]
}
docker buildx bake --push

Inspecionar o que foi construído

docker buildx build --progress=plain .    # full log, without the compact UI
docker buildx history                      # recent builds (Docker Desktop / newer versions)
docker buildx du                           # space used by the builder cache
docker buildx prune                        # clears the builder cache

Gerar SBOM e proveniência

O BuildKit pode anexar um SBOM (lista de pacotes) e atestado de proveniência SLSA à imagem no push:

docker buildx build --sbom=true --provenance=true \
  -t registry.example.com/app:1.2.3 --push .

Isso alimenta ferramentas de auditoria e scanners de vulnerabilidade. Ver também Distribuindo imagens.