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 appliesbuild— 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:baseheroku/buildpacks:20gcr.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]
- Detect — each buildpack’s
detectscript runs; passing ones form an ordered group - Restore — cached layers from previous builds are restored
- Analyze — metadata from previous image is analyzed for layer reuse
- Build — buildpacks run in order, contributing layers
- 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 rebasedoesn’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-appkpack (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: mainStrengths
- 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 buildbackend. 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 ./staticBoth 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 installSecrets 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 (
buildkitdseparate 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
--sbomflag inbuildx) - Cache invalidation can be subtle/unexpected
- Complexity spikes with advanced LLB or custom frontends
CNB vs BuildKit - Comparison
| Dimension | Cloud Native Buildpacks | BuildKit |
|---|---|---|
| Build definition | None (auto-detect) | Dockerfile (or custom frontend) |
| Flexibility | Opinionated, structured | Fully flexible |
| Parallelism | Limited (sequential buildpacks) | Native (DAG-based) |
| Base image patching | ✅ Rebase (instant, no rebuild) | ❌ Full rebuild required |
| Caching | Layer reuse across builds | Cache 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 experience | Zero Docker knowledge needed | Requires Dockerfile authoring |
| CI integration | âś… Good (Tekton, GitHub Actions) | âś… Excellent |
| Governance | cncf (incubating) | Docker / Moby |
| Primary use case | PaaS-style, enterprise app platforms | General-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.,
kpackon 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
packCLI uses BuildKit under the hood for some operations. In enterprise setups, CNB (viakpack) handles app images while BuildKit handles base image construction.