Chapter 09Lesson 02~125 minutes

BuildKit and buildx Architecture, Builders, Frontends, Progress, Outputs, and Modern Build Workflows: Guided Hands-On Workflow and Core Operations

Create a disposable docker-container builder, bootstrap and inspect its BuildKit worker, run the same tiny build with plain progress, compare cache behavior, load one result into the local image store, export another as an OCI archive, and preserve build-record evidence before removing only the chapter-owned builder.

Hands-ondocker-container driverPlain progressOCI outputBuild history

Learning objectives

  • Inspect the current Buildx/BuildKit environment before creating or selecting any builder.
  • Create, bootstrap, and inspect a chapter-owned docker-container builder without replacing shared builders or mutating daemon configuration.
  • Run a tiny deterministic build with plain progress and record builder, worker, frontend, cache, and build-record evidence.
  • Compare an explicitly loaded image with an OCI archive export and verify the resulting states independently.
  • Remove only the disposable builder and chapter-owned image/archive while preserving the evidence packet.
Chapter 09 evidence baseline — verified 2026-09-21. Mandatory exercises use a synthetic local source tree and a uniquely named disposable docker-container builder; they do not require a registry, paid cloud builder, Kubernetes cluster, production daemon, or privileged shared CI runner. At verification time Docker Buildx 0.37.1 and BuildKit 0.33.0 are the current upstream releases; BuildKit 0.33.0 includes the built-in Dockerfile frontend 1.27.0, while Docker Engine 29.8.1 remains the current Engine 29 course baseline. Docker documents the docker driver as Engine-integrated with automatic local image loading, while docker-container/remote/Kubernetes-style drivers keep an unspecified-output result in BuildKit cache unless an exporter such as --load, --push, or --output is selected. Every lab therefore records the actual local Buildx/BuildKit/frontend/worker state and verifies output destination independently.

1. Lab scope: one disposable builder, one tiny source tree

This workflow uses a chapter-owned docker-container builder and a synthetic text-producing image. It does not publish to a registry, does not mount the Docker socket into untrusted workloads, and does not modify daemon configuration. The only persistent artifacts are a small local image, an OCI archive, build records/cache inside the disposable builder, and an evidence directory.

2. Preflight: capture current state before creating anything

mkdir -p ch09-lab/evidence
cd ch09-lab

BUILDER="devops-academy-ch09"
IMAGE="devops-academy-ch09:loaded"

printf 'context=%s\n' "$(docker context show)" | tee evidence/00-context.txt
docker version | tee evidence/01-docker-version.txt
docker buildx version | tee evidence/02-buildx-version.txt
docker buildx ls | tee evidence/03-builders-before.txt

docker buildx inspect 2>&1 | tee evidence/04-current-builder-before.txt || true

Do not delete or reconfigure an existing shared builder. If the requested builder name already exists and is not clearly chapter-owned, choose another unique chapter label.

3. Create deterministic synthetic inputs

# syntax=docker/dockerfile:1
FROM busybox:1.37.0
ARG MESSAGE="buildkit-evidence"
RUN printf '%s\n' "$MESSAGE" > /message.txt
CMD ["cat", "/message.txt"]
sha256sum Dockerfile | tee evidence/05-dockerfile-sha256.txt

The ARG value is non-secret synthetic input. Chapter 07 already established that ARG and ENV are not secret channels.

4. Create and bootstrap an isolated BuildKit builder

docker buildx create \
  --name "$BUILDER" \
  --driver docker-container

docker buildx inspect --bootstrap "$BUILDER" \
  | tee evidence/06-builder-inspect.txt

docker buildx ls | tee evidence/07-builders-after.txt

Inspect the Driver, node endpoint, status, BuildKit version, and platforms. A BuildKit container may be started as part of bootstrap; that container is builder infrastructure owned by the chapter lab.

5. First build: deliberately request no output

docker buildx build \
  --builder "$BUILDER" \
  --progress=plain \
  --build-arg MESSAGE=cache-only \
  -t devops-academy-ch09:cache-only \
  . 2>&1 | tee evidence/08-cache-only-build.txt

# Expected with docker-container default behavior: this may fail because no
# local image was loaded. Preserve the result rather than treating it as a build failure.
docker image inspect devops-academy-ch09:cache-only \
  > evidence/09-local-inspect-cache-only.json 2> evidence/09-local-inspect-cache-only.err || true
Interpret the warning, do not erase it. Current Docker documentation states that non-auto-load drivers retain an unspecified-output result in build cache. The local image absence is therefore output-state evidence.

6. Second build: request a local Docker image explicitly

docker buildx build \
  --builder "$BUILDER" \
  --progress=plain \
  --load \
  --build-arg MESSAGE=loaded-output \
  --label devops-academy.lab=ch09 \
  -t "$IMAGE" \
  . 2>&1 | tee evidence/10-load-build.txt

docker image inspect "$IMAGE" \
  --format 'ID={{.Id}} RepoDigests={{json .RepoDigests}}' \
  | tee evidence/11-loaded-image.txt

docker run --rm "$IMAGE" | tee evidence/12-runtime.txt

Compare the first and second plain logs. The graph may reuse cached operations, but only the second command asks Buildx to import the result into the Docker image store.

7. Third build: export an OCI image-layout archive

docker buildx build \
  --builder "$BUILDER" \
  --progress=plain \
  --build-arg MESSAGE=oci-output \
  --output type=oci,dest=./ch09-result.oci.tar \
  . 2>&1 | tee evidence/13-oci-build.txt

sha256sum ch09-result.oci.tar | tee evidence/14-oci-archive-sha256.txt
tar -tf ch09-result.oci.tar | sed -n '1,40p' \
  | tee evidence/15-oci-archive-list.txt

The archive is an output artifact. Its SHA-256 identifies the exact tar file, while the OCI manifest/config/layer digests inside identify OCI content. Do not call the archive checksum the image manifest digest.

8. Capture build records and logs

docker buildx --builder "$BUILDER" history ls --no-trunc \
  | tee evidence/16-history.txt

docker buildx --builder "$BUILDER" history logs \
  | tee evidence/17-last-build-logs.txt

If the installed Buildx does not expose history commands, record that compatibility limitation instead of inventing records. The plain build logs remain valid evidence.

9. Verify the output states independently

Build Solve completed? Local image expected? OCI file expected?
Cache-only Yes, if BuildKit completed No by default No
--load Yes Yes No
type=oci Yes No unless separately requested Yes

10. Small challenge: choose the exporter from the requirement

For each requirement—run the image locally, publish it to a registry, hand an OCI archive to an offline verifier, and export generated static files—choose an exporter/output and name the evidence you would collect after the build. Do not use “green build” as the verification for all four.

11. Exact cleanup

docker image rm "$IMAGE" 2>&1 | tee evidence/18-image-cleanup.txt || true
rm -f ch09-result.oci.tar

docker buildx rm "$BUILDER" \
  | tee evidence/19-builder-cleanup.txt

docker buildx ls | tee evidence/20-builders-final.txt

docker buildx rm removes the named builder and its associated builder state according to the driver. Because this builder is chapter-owned, that cleanup is bounded. Do not run broad build-cache or system prune against unrelated builders.

Next lesson

Next: Configuration, Design Choices, and Tradeoffs

Choose builder drivers, frontend strategy, exporter destination, and progress format intentionally.

Knowledge check

Why is the first cache-only build useful even though no local image is expected?

What does --load change?

Why record both Buildx version and buildx inspect output?

Does deleting builder cache prove why a build failed?

What should remain after exact cleanup?

Official references and version notes

Version and compatibility note

Version-sensitive statements were rechecked against primary sources on 2026-09-21. Buildx 0.37.1 is the current upstream Buildx release (2026-09-11), BuildKit 0.33.0 is the current upstream BuildKit release (2026-09-02), and that BuildKit release updates the built-in Dockerfile frontend to 1.27.0. Docker Engine 29.8.1 remains the current Engine 29 patch baseline used by this course at verification time. Tooling is independently versioned, so every lab captures the learner's actual Engine/CLI/Buildx/BuildKit/frontend/worker state instead of assuming these versions.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.