docker devops cloudnative buildkit

Core Idea

Cloud Native Buildpacks and BuildKit answer the same question — how source becomes an OCI image — from opposite ends: Buildpacks infer the build from your code with no Dockerfile, BuildKit executes the Dockerfile you write.

  • Buildpacks: detect → restore → analyze → build → export, with rebase to patch the base image in seconds.
  • BuildKit: LLB-based, cached, parallel, multi-platform builds driven by a Dockerfile and docker buildx.
  • Trade-off: opinionated automation versus explicit, versionable control.

Cloud Native Buildpacks

Abstract

Cloud Native Buildpacks (CNB) transform application source code into OCI-compliant container images without a Dockerfile. They automate dependency detection, layer caching, and image rebasing — designed for production-grade, opinionated builds.

What Are Cloud Native Buildpacks?

Cloud Native Buildpacks originated from Heroku’s buildpack concept and were later co-developed by Pivotal (now VMware) and Heroku, before becoming a cncf incubating project in 2018.

The core promise: give CNB your source code, and it figures out the rest — language runtime, dependencies, base image — and produces a reproducible OCI image.

[Source Code] → [CNB Lifecycle] → [OCI Image]

Key Concepts

Buildpack

A unit of detection + build logic for a specific language or framework (e.g., Node.js, Java, Python). Each buildpack consists of two scripts:

  • detect — determines if the buildpack applies
  • build — assembles the layer

Builder

A composite image that bundles:

  • A stack (run image + build image)
  • A set of buildpacks
  • The life cycle binary
    Popular builders:
  • paketobuildpacks/builder:base
  • heroku/buildpacks:20
  • gcr.io/buildpacks/builder:v1

Life Cycle

The orchestrator that runs each phase in order:

detect → restore → analyze → build → export

Stack

Two OCI images: one for building and one for running the app. Separating them keeps the final image lean.

How a Build Works

flowchart LR
    A[Source Code] --> B[Detect Phase]
    B --> C{Which buildpacks match?}
    C --> D[Build Phase]
    D --> E[Layer Assembly]
    E --> F[Export → OCI Image]
  1. Detect — each buildpack’s detect script runs; passing ones form an ordered group
  2. Restore — cached layers from previous builds are restored
  3. Analyze — metadata from previous image is analyzed for layer reuse
  4. Build — buildpacks run in order, contributing layers
  5. Export — layers are assembled into a final OCI image and pushed

Rebase

Rebasing works by exploiting the fact that OCI images are just a stack of content addressable layers with a manifest, Later when a patched base image is published pack rebase automatically rebase the base layer.

  • Pulls the new run image from the registry
  • Looks at the old manifest and finds where the base layers end and your app layers begin
  • Rewrites the manifest to reference the new base layers instead, keeping your app and dependencies layer digests identical
  • Pushes the new manifest

That’s it. No compilation, no npm install, no go build. The app and dependencies layers are not touched — they’re reused by their content digest. The operation takes a few seconds and produces a fully patched image.

At scale — say, 500 microservices — rebasing all of them in seconds versus triggering 500 CI pipelines is a meaningful operational difference.

Warning

Rebasing has a strict constraint: you can only swap the OS base layers, not arbitrary layers in the middle of the stack.

pack rebase doesn’t validate compatibility. It will happily swap a base with a different glibc version and hand you a broken image.

CLI Tools

pack (Local Builds)

# Build an image from source
pack build my-app --builder paketobuildpacks/builder:base
 
# Inspect a builder
pack builder inspect paketobuildpacks/builder:base
 
# Rebase (swap the run image without full rebuild)
pack rebase my-app

kpack (Kubernetes-native)

Runs CNB builds as Kubernetes resources, watching for source or stack updates and rebuilding automatically.

apiVersion: kpack.io/v1alpha2
kind: Image
metadata:
  name: my-app
spec:
  tag: registry.example.com/my-app
  builder:
    name: my-builder
  source:
    git:
      url: https://github.com/org/repo
      revision: main

Strengths

  • No Dockerfile required — zero container expertise needed by devs
  • Automatic OS-level patching via rebasing (swap base image, no full rebuild)
  • Built-in layer caching across builds
  • Reproducible, deterministic images
  • SBOM (Software Bill of Materials) generation out of the box
  • Strong separation of concerns (ops controls stack, devs control app)

Weaknesses

  • Less flexible than raw Dockerfiles for custom build steps
  • Slower cold builds (lifecycle overhead)
  • Debugging failures can be opaque
  • Builder ecosystem fragmented (Paketo vs Heroku vs Google)
  • Complex mental model for teams new to the concept

BuildKit

Abstract

BuildKit is the next-generation build engine for Docker/OCI images, replacing the legacy docker build backend. It uses a low-level intermediate representation (LLB) to enable parallel, cache-efficient, Dockerfile-driven builds with advanced features.

BuildKit ships as the default backend in Docker 23.0+ and is the engine behind docker buildx.

Key Concepts

LLB (Low-Level Build)

BuildKit’s internal DAG-based IR. Build steps are expressed as a graph of operations (exec, copy, mount), enabling automatic parallelism and fine-grained caching.

Frontend

The component that parses your build definition (e.g., a Dockerfile) and emits LLB. Custom frontends are possible — BuildKit isn’t married to Dockerfiles.

Solver / Cache

BuildKit’s solver walks the LLB graph and applies content-addressable caching. Cache can be exported/imported from remote registries.

How a Build Works

flowchart LR
    A[Dockerfile / Frontend] --> B[LLB Graph]
    B --> C[Solver]
    C --> D{Cache Hit?}
    D -- yes --> E[Restore Layer]
    D -- no --> F[Execute Step]
    F --> G[OCI Image]
    E --> G

Key Features

Parallel Stage Execution

Multi-stage Dockerfiles run independent stages concurrently.

FROM golang AS builder
RUN go build -o app .
 
FROM node AS frontend
RUN npm ci && npm run build
 
FROM alpine
COPY --from=builder /app .
COPY --from=frontend /dist ./static

Both builder and frontend stages run in parallel.

Cache Mounts

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

Persists package manager caches between builds without baking them into the image.

Secret Mounts

RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
    npm install

Secrets are never written to any layer.

Remote Cache

# Export cache to registry
docker buildx build \
  --cache-to type=registry,ref=myrepo/cache \
  --cache-from type=registry,ref=myrepo/cache \
  -t myrepo/app .

Multi-platform Builds

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t myrepo/app --push .

Strengths

  • Full Dockerfile flexibility — arbitrary shell, multi-stage, custom frontends
  • Parallel stage execution
  • Fine-grained cache control (cache mounts, inline cache, remote cache)
  • Secret & SSH mounts — no credential leakage into layers
  • Native multi-platform builds via QEMU or cross-compilation
  • Daemonless builds possible (buildkitd separate from Docker daemon)
  • First-class containerd integration
  • Widely supported in CI (GitHub Actions, GitLab, Tekton)

Weaknesses

  • Still requires authoring Dockerfiles (or equivalent)
  • No automatic OS rebasing — must re-run full build to patch base image
  • No built-in SBOM (needs separate tooling like Syft or --sbom flag in buildx)
  • Cache invalidation can be subtle/unexpected
  • Complexity spikes with advanced LLB or custom frontends

CNB vs BuildKit - Comparison

DimensionCloud Native BuildpacksBuildKit
Build definitionNone (auto-detect)Dockerfile (or custom frontend)
FlexibilityOpinionated, structuredFully flexible
ParallelismLimited (sequential buildpacks)Native (DAG-based)
Base image patching✅ Rebase (instant, no rebuild)❌ Full rebuild required
CachingLayer reuse across buildsCache mounts + remote cache
SBOM✅ Built-in⚠️ Opt-in (--sbom)
Multi-platform⚠️ Limited✅ Native with buildx
Secrets in build❌ Not native✅ --mount=type=secret
Kubernetes-native✅ kpack⚠️ Via Tekton/Kaniko wrappers
Dev experienceZero Docker knowledge neededRequires Dockerfile authoring
CI integrationâś… Good (Tekton, GitHub Actions)âś… Excellent
Governancecncf (incubating)Docker / Moby
Primary use casePaaS-style, enterprise app platformsGeneral-purpose image building

When to Use Which

Use Cloud Native Buildpacks when…

  • You’re building a platform for developers who shouldn’t need to manage containers
  • You need automatic OS-level security patching across many images (rebase)
  • You want opinionated, governed builds across a large app fleet (e.g., kpack on K8s)
  • You’re migrating from Heroku or a PaaS environment

Use BuildKit when…

  • You need full control over the build process
  • Your app has complex, non-standard build steps
  • You need multi-platform images (amd64 + arm64)
  • You’re already heavily invested in Dockerfiles and Docker tooling
  • You need secret injection during build without layer leakage

Warning

They’re not mutually exclusive CNB’s pack CLI uses BuildKit under the hood for some operations. In enterprise setups, CNB (via kpack) handles app images while BuildKit handles base image construction.

References