Chapter 12Lesson 01~105 minutes

Multi-Platform Images, QEMU Emulation, Native Builders, Manifest Lists, and Cross-Architecture Delivery: Concepts, Architecture, and Mental Model

Multi-platform delivery is not “one binary that runs everywhere.” This lesson separates build platform, target platform, worker capability, emulation, cross-compilation, per-platform image manifests, and the higher-level OCI image index so every architecture-specific artifact can be identified and verified independently.

Multi-platformOCI image indexBuild vs targetQEMUDigest identity

Learning objectives

  • Distinguish host architecture, BuildKit worker platform, BUILDPLATFORM, TARGETPLATFORM, TARGETOS, TARGETARCH, and the platform declared on an image descriptor.
  • Explain how one image reference can resolve to an OCI image index that points to independent per-platform manifests, configs, and layer graphs.
  • Compare QEMU emulation, multiple native builder nodes, and cross-compilation without treating any strategy as universally best.
  • Explain why a successful multi-platform build does not prove every variant was executed, tested, loaded locally, or published to a registry.
  • Define the evidence required to bind a release index digest to its platform descriptors, builder strategy, and per-platform test results.
Chapter 12 evidence baseline — verified 2026-09-21. Mandatory exercises use only synthetic source, chapter-owned isolated Buildx builders, public base images, and local OCI output. At verification time Docker Engine 29.8.1, Buildx 0.37.1, BuildKit 0.33.0, and Dockerfile frontend 1.27.0 are the current course baselines, but every lab records actual versions, builder driver, worker platforms, and image-store behavior. Fresh Engine 29 installations and Docker Desktop use the containerd image store by default and support multi-platform images locally; upgraded Engine hosts can retain the classic store. The mandatory path uses cross-compilation-style BUILDPLATFORM/TARGET* separation and OCI export, so no public registry, cloud account, production daemon, host-wide emulator registration, or real credential is required.

1. The problem: “runs in a container” does not erase CPU architecture

Containers package user-space files and process configuration, but the process still executes machine instructions on a real CPU through the host kernel. An amd64 binary is not magically transformed into arm64 just because both are distributed as Docker images. Multi-platform delivery solves a distribution problem by placing multiple platform-specific images behind one reference; it does not abolish platform-specific artifacts.

The operational mistake is to treat myapp:1.0 as one opaque byte sequence. In a multi-platform release that reference commonly resolves to an image index. The index contains descriptors for platform-specific manifests. Each manifest then identifies its own config object and ordered layer descriptors. The index digest, per-platform manifest digest, config digest, and layer digests are different identities and answer different questions.

2. Mental model: request → strategy → per-platform results → index

Multi-platform build and pull path
flowchart TD
  A[Requested platforms\nlinux/amd64 + linux/arm64] --> B[Selected Buildx builder]
  B --> C{How will target work execute?}
  C -->|Emulation| D[QEMU/binfmt]
  C -->|Native nodes| E[Matching worker CPUs]
  C -->|Cross-compile| F[Build on BUILDPLATFORM\nproduce TARGETARCH artifact]
  D --> G[amd64 result]
  D --> H[arm64 result]
  E --> G
  E --> H
  F --> G
  F --> H
  G --> I[Per-platform manifest]
  H --> J[Per-platform manifest]
  I --> K[OCI image index digest]
  J --> K
  K --> L[Registry / OCI output / capable local store]
  L --> M[Pull selects matching platform descriptor]
            

BuildKit chooses workers and executes the build graph. The strategy determines how instructions that require target-platform execution are satisfied. QEMU translates foreign instructions. Native nodes execute on matching CPUs. Cross-compilation keeps compilation on the build platform and asks the toolchain to emit target-platform artifacts. A single build can also mix strategies by stage.

3. Five platform identities to keep separate

Identity Meaning Evidence
Host platform The machine/VM running the Docker daemon or BuildKit worker. uname -m, OS information, daemon info.
Worker platform A platform BuildKit reports a node can execute, natively or via registered emulation. docker buildx inspect --bootstrap.
BUILDPLATFORM The platform on which a particular build stage is intended to execute. Automatic platform ARG captured in build output.
TARGETPLATFORM The platform of the result requested by --platform. Automatic target ARG and output descriptor.
Runtime-selected platform The descriptor selected by an image consumer when pulling/running an index. Resolved manifest digest and runtime metadata.

These values can coincide, but coincidence is not identity. On an amd64 host building an arm64 image with cross-compilation, the build stage can run on amd64 while TARGETARCH=arm64. On a QEMU-enabled builder, BuildKit may execute an arm64 stage on an amd64 machine through emulation. On a native arm64 node, no translation is involved.

4. Automatic platform arguments are build intent, not magic runtime proof

BuildKit exposes BUILDPLATFORM, BUILDOS, BUILDARCH, BUILDVARIANT and the corresponding TARGET* values. To use an automatic ARG inside a build stage, redeclare the specific ARG in that stage. A common cross-compilation pattern pins the compiler stage with FROM --platform=$BUILDPLATFORM, then passes TARGETOS/TARGETARCH to the compiler.

# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM alpine:3.22 AS build
ARG BUILDPLATFORM
ARG TARGETPLATFORM
ARG TARGETOS
ARG TARGETARCH
RUN printf 'build=%s\ntarget=%s\nos=%s\narch=%s\n' \
    "$BUILDPLATFORM" "$TARGETPLATFORM" "$TARGETOS" "$TARGETARCH" \
    > /platform-evidence.txt

FROM scratch
COPY --from=build /platform-evidence.txt /platform-evidence.txt

This example proves what BuildKit requested and what artifact metadata was generated. It does not prove a target-platform process was executed. That distinction becomes essential when a release is built by cross-compilation.

5. OCI image index versus platform manifest

An OCI image index is a higher-level JSON object with descriptors in a manifests array. Each descriptor can include platform.os, platform.architecture, an optional variant, a media type, size, and digest. The descriptor digest identifies the referenced manifest bytes. That per-platform manifest then points to one config object and its layer descriptors.

Therefore “the image digest” is ambiguous unless you state which object you mean. For deployment/promotion of a multi-platform release, the index digest is typically the top-level immutable release identity. For debugging one platform, the selected platform manifest digest is the relevant object. If a vulnerability or runtime failure is platform-specific, two descriptors behind the same index can legitimately have different outcomes.

6. Three strategies, three kinds of evidence

QEMU emulation

BuildKit can use QEMU user-mode emulation when the builder exposes the foreign architecture. This is convenient because the Dockerfile often needs no special changes. It is also slower for compute-heavy compilation or compression and can hide whether a build step ran natively.

Multiple native nodes

A Buildx builder can contain multiple nodes backed by different Docker contexts or remote BuildKit daemons. Each target is scheduled to a matching native worker. Native execution improves fidelity and performance but adds node provisioning, patching, credentials, network, cache, and failure-domain concerns.

Cross-compilation

Languages such as Go and Rust can emit target binaries while the compiler itself runs natively on the build platform. This avoids emulation for the compile step, but the toolchain must correctly cross-compile dependencies, CGO/native libraries, generated code, and tests. Cross-compilation does not remove the need for target-platform runtime testing.

7. “Build succeeded” is only one state

  • The builder accepted two target platforms.
  • Both target graphs completed.
  • An OCI index was exported.
  • The index contains two platform descriptors.
  • Each referenced manifest/config/layer graph exists.
  • The artifacts inside each variant match their declared platform.
  • The release was loaded locally or pushed to a registry.
  • Each variant executed successfully on a representative runtime.

These are separate claims. A green BuildKit solve can produce an OCI archive without creating any local Docker tag. An index can be structurally valid while one variant contains a broken executable. A registry can accept the index while a target runtime later rejects one platform. Keep the evidence chain explicit.

8. Read-only preflight before requesting foreign platforms

docker version
docker info
docker context show
docker buildx version
docker buildx ls
docker buildx inspect --bootstrap

Record the selected builder, driver, BuildKit version, nodes, and listed platforms. On Engine 29, also inspect whether the daemon uses the containerd image store rather than assuming a fresh-install default applies to an upgraded system. If the lab uses OCI output through a docker-container builder, the learning path remains independent of local multi-platform image-store support.

9. DevOps connection: one release reference, several independently accountable artifacts

A production multi-platform release needs source revision, Dockerfile/frontend identity, builder/buildkit identity, requested platform set, per-platform tests, index digest, per-platform manifest digests, publication target, and promotion evidence. “arm64 is inside the tag” is not enough. You should be able to show exactly which descriptor, manifest, artifact, and test result correspond to arm64.

This is especially important during incident response. If only arm64 crashes, do not roll back or rebuild amd64 blindly. Resolve the index, identify the failing descriptor, inspect the exact target artifact, and compare platform-specific dependency/test evidence.

10. Small challenge: what can you actually claim?

A build on an amd64 workstation produces an OCI index with amd64 and arm64 descriptors. The Dockerfile compiler stage uses FROM --platform=$BUILDPLATFORM, and no arm64 process was executed. Which statements are justified? You can claim a two-platform index was built and the target metadata/artifacts can be inspected. You cannot claim the arm64 application was runtime-tested unless separate native or emulated execution evidence exists.

Next lesson

Next: Guided Hands-On Workflow and Core Operations

Build and inspect a two-platform OCI artifact without requiring privileged host changes or a public registry.

Knowledge check

Does a multi-platform image index contain one shared filesystem for every CPU architecture?

What does TARGETPLATFORM=linux/arm64 prove?

Why can QEMU be a poor choice for a compile-heavy build?

Which digest is the top-level immutable identity of a published multi-platform release?

Can build success substitute for per-platform runtime tests?

Official references and version notes

Version and compatibility note

Version-sensitive statements were rechecked against primary documentation on 2026-09-21. The course baseline is Docker Engine 29.8.1, Buildx 0.37.1, BuildKit 0.33.0, and Dockerfile frontend 1.27.0, but every executable lab records the versions and image-store/builder behavior actually present. Fresh Engine 29 installations and Docker Desktop use the containerd image store by default; upgraded Engine hosts may retain the classic store. Mandatory exercises therefore use an isolated docker-container builder and OCI export so learning does not depend on a registry or on local multi-platform load support.

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.