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.
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.
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
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.
Knowledge check
Does a multi-platform image index contain one shared filesystem for every CPU architecture?
No. It points to platform-specific manifests, each with its own config and layer descriptors.
What does
TARGETPLATFORM=linux/arm64 prove?
It proves BuildKit requested an arm64 target for that result. It does not by itself prove an arm64 process executed successfully.
Why can QEMU be a poor choice for a compile-heavy build?
Instruction emulation can be much slower than native execution or cross-compilation.
Which digest is the top-level immutable identity of a published multi-platform release?
The digest of the image index/manifest list; each child platform manifest also has its own digest.
Can build success substitute for per-platform runtime tests?
No. Structural/build evidence and runtime behavior are distinct states.
Official references and version notes
- Docker multi-platform builds — current prerequisites, QEMU, multiple native nodes, cross-compilation, automatic platform arguments, and local image-store guidance.
- containerd image store with Docker Engine — Engine 29 fresh-install default, multi-platform local storage, snapshotters, upgrade caveats, and userns-remap limitation.
- Docker Desktop containerd image store — Desktop image-store behavior and multi-platform/attestation support.
-
docker buildx build—--platform, exporters, metadata, progress, builder selection, and output semantics. -
docker buildx inspect— builder driver, BuildKit nodes, status, and platform capability evidence. -
Automatic platform ARGs
—
BUILDPLATFORM,TARGETPLATFORM,TARGETOS,TARGETARCH, and stage-scope behavior. - OCI Image Index Specification — higher-level descriptors and platform selection.
- OCI Image Manifest Specification — per-platform config and layer descriptors.
- OCI Descriptor Specification — digest, size, media type, and platform metadata.
- Docker Engine 29 release notes — current Engine baseline and multi-platform image load/save updates.
- Buildx releases — current Buildx release history.
- BuildKit releases — current BuildKit and Dockerfile frontend history.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.