Building Multi‑Platform Docker Images with Docker Buildx
This tutorial explains how to install Docker Buildx, create and manage builders, and use QEMU emulation or Go cross‑compilation to produce multi‑platform Docker images, covering command syntax, driver options, global BuildKit variables, and how to push or load the resulting images.
Introduction
Docker supports multi‑platform images that can run on different CPU architectures. While the older docker manifest command can create such images, the preferred method today is the docker buildx plugin, which automates the process and improves efficiency.
Installation
buildx is a CLI plugin that extends Docker with BuildKit capabilities. It requires Docker Engine 19.03 or newer. Docker Desktop includes buildx by default; you can verify the version with docker buildx version . For manual installation, download the binary from the GitHub releases page, rename it to docker-buildx , place it in the CLI‑plugins directory ( $HOME/.docker/cli-plugins on Linux/macOS or %USERPROFILE%\.docker\cli-plugins on Windows), and make it executable:
$ chmod +x ~/.docker/cli-plugins/docker-buildxMore details are available in the official documentation.
Building Multi‑Platform Images
Docker calls them Multi‑platform images . When you pull or run such an image, Docker automatically selects the appropriate architecture without exposing the underlying manifest list.
Build Strategies
Use QEMU emulation via BuildKit’s binfmt_misc support (default on Docker Desktop).
Run the same builder on multiple physical nodes (requires hardware for each target platform).
Use multi‑stage Dockerfiles with cross‑compilation (e.g., Go’s GOOS and GOARCH ).
Creating a Builder
List existing builders:
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
default * docker
default default running 20.10.21 linux/arm64, linux/amd64, ...
desktop-linux docker
desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, ...Create a new builder named mybuilder :
$ docker buildx create --name mybuilder
mybuilderInspect and bootstrap the builder:
$ docker buildx inspect --bootstrap mybuilder
[+] Building 16.8s (1/1) FINISHED
... (output omitted) ...
Name: mybuilder
Driver: docker-container
Nodes:
Name: mybuilder0
Endpoint: unix:///var/run/docker.sock
Status: running
Buildkit: v0.9.3
Platforms: linux/arm64, linux/amd64, ...Activate the builder with docker buildx use mybuilder .
Using the Builder
Example Go program ( hello.go ) and module ( go.mod ) are placed in a directory with a multi‑stage Dockerfile :
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Printf("Hello, %s/%s!\n", runtime.GOOS, runtime.GOARCH)
} module hello
go 1.20 FROM golang:1.20-alpine AS builder
WORKDIR /app
ADD . .
RUN go build -o hello .
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/hello .
CMD ["./hello"]Build for both arm64 and amd64 in one command:
$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go .If you omit --push or --load , the result stays in the build cache, producing a warning. Use --push to upload to a registry (after docker login ) or --load to load a single‑platform image locally.
Cross‑Compilation
Modify the Dockerfile to use BuildKit’s automatic platform arguments:
FROM --platform=$BUILDPLATFORM golang:1.20-alpine AS builder
ARG TARGETOS
ARG TARGETARCH
WORKDIR /app
ADD . .
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o hello .
FROM --platform=$TARGETPLATFORM alpine:latest
WORKDIR /app
COPY --from=builder /app/hello .
CMD ["./hello"]Build with the same command; BuildKit substitutes $BUILDPLATFORM , $TARGETOS , $TARGETARCH , and $TARGETPLATFORM automatically.
Platform‑Related Global Variables
BuildKit defines eight global ARG variables:
Variable
Description
TARGETPLATFORM
Target platform (e.g., linux/amd64)
TARGETOS
OS part of the target platform
TARGETARCH
Architecture part of the target platform
TARGETVARIANT
Variant of the target platform (e.g., v7)
BUILDPLATFORM
Platform where the build is executed
BUILDOS
OS of the build platform
BUILDARCH
Architecture of the build platform
BUILDVARIANT
Variant of the build platform
Example usage:
# Use TARGETPLATFORM directly in FROM
FROM --platform=$TARGETPLATFORM alpine
# Declare ARG before using it in RUN
ARG TARGETPLATFORM
RUN echo "Building for $TARGETPLATFORM"Deleting a Builder
Remove the builder and its BuildKit container:
$ docker buildx rm mybuilder
mybuilder removedAfter removal, docker buildx ls shows only the default builders again.
Feature List
Run docker buildx --help to see all commands, such as bake , prune , stop , etc., for managing builds and cache.
Conclusion
The article demonstrated installing buildx , creating and managing builders, three build strategies (QEMU emulation, multi‑node builds, and cross‑compilation), and how to push or load the resulting multi‑platform images. It also covered BuildKit’s global variables and provided references for further learning.
References
buildx repository: https://github.com/docker/buildx
Installation guide: https://docs.docker.com/build/install-buildx/
Command reference: https://docs.docker.com/engine/reference/commandline/buildx/
Driver documentation: https://docs.docker.com/build/drivers/
Multi‑platform images: https://docs.docker.com/build/building/multi-platform/
Multi‑stage builds: https://docs.docker.com/build/building/multi-stage/
BuildKit docs: https://docs.docker.com/build/buildkit/
Automatic platform args: https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
Go Programming World
Mobile version of tech blog https://jianghushinian.cn/, covering Golang, Docker, Kubernetes and beyond.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.