Back to Blog
Lesson 50 of the Docker: Containers & Your First Image course
DevOpsSeptember 22, 20266 min read

Multi-Architecture Builds: Master Cross-Platform Docker

Learn how to create multi-architecture container images for x86 and ARM hardware using Docker buildx and test cross-platform compatibility.

architecturebuildxmulti-archcross-platformdockerdevops
Shipping containers and cranes at Hamburg port showcasing global trade.

Previously in this course, we looked at supply chain security in Image Signing and Notary. This lesson adds a crucial modern capability: building container images that execute seamlessly across different CPU architectures like AMD64 and ARM64 using buildx.

Modern infrastructure is heterogenous. Your local development machine might run an Apple Silicon Mac (ARM64), your teammate uses an Intel laptop (AMD64), and your cloud production servers might run on AWS Graviton processors (ARM64) or traditional x86_64 nodes. When you build a container image locally, standard Docker commands build an image tied strictly to your host's CPU architecture. If you push that image to a registry, users on a different processor architecture will hit frustrating exec format error failures.

To solve this, Docker introduced buildx, a CLI plugin powered by the Moby BuildKit engine. It enables true multi-architecture (multi-arch) builds, letting you compile a single manifest list containing images for multiple CPU platforms at once.

Understanding CPU Architectures and BuildKit

Before writing code, it helps to understand what happens under the hood during a cross-platform build. When you run docker build, Docker normally talks directly to the local daemon, targeting whatever CPU your machine currently runs.

When you switch to buildx, Docker provisions an isolated BuildKit builder environment. If you need to build an ARM64 image from an x86_64 machine, BuildKit leverages binfmt_misc kernel emulation to execute binaries compiled for foreign architectures transparently.

+-------------------------------------------------------+
|                    Docker Buildx                      |
|                  (BuildKit Engine)                    |
+---------------------------+---------------------------+
                            |
         +------------------+------------------+
         |                                     |
         v                                     v
+------------------+                  +------------------+
|  linux/amd64     |                  |  linux/arm64     |
|  (Intel / AMD)   |                  |  (Apple Silicon) |
+------------------+                  +------------------+
         \                                     /
          +-----------------+-----------------+
                            |
                            v
            +-------------------------------+
            |  Multi-Arch Manifest List     |
            |     (Pushed to Registry)      |
            +-------------------------------+

This architecture allows you to create a unified image manifest that points to architecture-specific image layers. When a production node pulls your image, the container runtime automatically fetches the correct binary slice for its processor.

Using Buildx for Cross-Platform Compilation

Detailed view of code and file structure in a software development environment.

Let's build a cross-platform container image for our running course project. We will create a custom builder instance, target multiple platforms, and push or export the multi-arch result.

First, check your available builder instances:

Bash
docker buildx ls

By default, you might see a default builder that does not support multi-node or multi-platform container exports. Let's create and switch to a new builder named multiarch-builder using the docker-container driver:

Bash
docker buildx create --name multiarch-builder --use
docker buildx inspect --bootstrap

The --bootstrap flag starts the BuildKit container pod immediately and verifies that emulation capabilities are active on your engine.

Writing a Multi-Arch Ready Dockerfile

For a multi-architecture build to succeed, your application code and base images must be compatible with all target platforms. Let's use a lightweight Go binary or a simple Python script. For this example, we will use a basic multi-stage setup similar to what we explored in Optimizing Image Size: Multi-Stage Builds and Alpine Linux.

Create a simple Dockerfile in your project directory:

Dockerfile
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:1.22-alpine AS builder
ARG TARGETOS
ARG TARGETARCH

WORKDIR /app
COPY main.go .
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /app/server main.go

FROM alpine:3.20
WORKDIR /app
COPY --from=builder /app/server /app/server
EXPOSE 8080
CMD ["/app/server"]

Notice the use of automatic build arguments provided by BuildKit:

  • $BUILDPLATFORM: The architecture of the machine executing the build.
  • $TARGETOS and $TARGETARCH: The desired operating system and CPU architecture for the output image.

Building and Testing Cross-Platform Compatibility

To build the image for both linux/amd64 and linux/arm64, invoke docker buildx build with the --platform flag.

If you are just testing locally without pushing to a remote registry yet, you can use --load (though --load only supports a single architecture at a time) or push directly to a local registry or Docker Hub. Let's build and push a multi-arch tag to a registry (replace yourusername with your actual Docker Hub handle):

Bash
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t yourusername/course-app:latest \
  --push .

If you prefer to inspect the multi-arch images locally without pushing to a public registry, you can output them to a local OCI layout directory:

Bash
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t course-app:local-multi \
  --output type=oci,dest=./oci-image-tar

Verifying Architecture with Inspect

Once your image is built or pushed, you can inspect the manifest list to confirm multiple architectures are present:

Bash
docker buildx imagetools inspect yourusername/course-app:latest

You will see output detailing the manifest list, showing separate entries for linux/amd64 and linux/arm64, complete with distinct digest hashes for each platform's filesystem layers.

Hands-on Exercise

To practice multi-architecture builds:

  1. Initialize a new buildx builder instance and bootstrap it.
  2. Create a simple Dockerfile that uses TARGETOS and TARGETARCH build arguments.
  3. Build the image targeting both linux/amd64 and linux/arm64.
  4. Run docker buildx imagetools inspect on your built artifact to verify that both platform manifests exist.

Common Pitfalls

Close-up of a triangular warning sign indicating a slippery surface, fixed to a wooden post.

  • Using --load with multiple platforms: BuildKit cannot load a multi-architecture manifest directly into the standard docker images daemon store in one command. Use --push to send multi-arch images to a registry, or output to an OCI tarball using --output.
  • Foreign architecture binaries: If your application relies on native compiled C-extensions (like certain Python packages or database drivers), cross-compiling without proper cross-compilers or static linking will cause runtime exec format error or segmentation faults.
  • Emulation performance overhead: Emulating foreign architectures (e.g., building ARM64 on an x86 host via QEMU) is significantly slower than native builds. Keep heavy compilation steps optimized.

FAQ

Can I build ARM64 images on an Intel machine?

Yes. Docker buildx uses QEMU via binfmt_misc kernel emulation to execute binaries of foreign architectures transparently during the build process.

Why does docker images not show all architectures after a multi-arch build?

The standard Docker image store only holds single-architecture images native to your current daemon. Multi-architecture manifest lists reside inside the BuildKit builder storage or a remote registry.

What is the difference between --load and --push in buildx?

--load imports a single-platform image back into your local Docker engine so you can run docker run immediately. --push sends the completed multi-architecture manifest list to a remote container registry.

Recap

Team members presenting a project in a modern office setting with a focus on collaboration.

Multi-architecture builds ensure your containers run seamlessly across diverse hardware environments without modification. By leveraging Docker buildx and BuildKit, you can compile, package, and verify cross-platform applications for both x86 and ARM infrastructure in a single unified workflow.

Up next, we will explore advanced volume backups to protect and manage persistent container state.

Similar Posts