Docker Buildx is the tool that lets you build container images for multiple architectures (like amd64 and arm64) simultaneously, often from a single command.
Here’s a Dockerfile for a simple Go application:
FROM golang:1.20-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp .
FROM alpine:latest
COPY --from=builder /app/myapp /myapp
CMD ["/myapp"]
Now, let’s build this for both linux/amd64 and linux/arm64 using Buildx. First, make sure you have Buildx installed and a builder instance created. If you don’t, run:
docker buildx create --use
This command sets up a new builder instance and makes it the default for subsequent buildx commands.
To build for multiple platforms, you’ll use the --platform flag:
docker buildx build --platform linux/amd64,linux/arm64 -t your-dockerhub-username/my-go-app:latest . --push
Let’s break this down:
docker buildx build: Invokes the Buildx build command.--platform linux/amd64,linux/arm64: Specifies the target architectures. You can list as many as you need, separated by commas.-t your-dockerhub-username/my-go-app:latest: Tags the resulting image. This tag will point to a manifest list, which is a special image that references other images for different platforms..: The build context (your current directory).--push: This is crucial. Since you’re building for multiple platforms, the output isn’t a single image on your local machine. Instead, Buildx creates a manifest list that points to the individual images for each platform. The--pushflag uploads these images and the manifest list to your container registry (like Docker Hub). Without--push, the images would be built in a temporary builder instance and lost when that instance is pruned.
After running the command, you can check your Docker Hub repository. You’ll see a single tag (your-dockerhub-username/my-go-app:latest), but when you pull it on a machine with a different architecture, Docker will automatically select the correct image.
The magic behind this is that Buildx uses QEMU (Quick EMUlator) to emulate different CPU architectures during the build process. When you specify --platform linux/arm64, Buildx starts an arm64 QEMU instance and runs your build steps within it. This allows you to create an arm64 image even if you’re building on an amd64 machine. The final output is a manifest list, which is a JSON file that contains pointers to the actual image layers for each architecture. When docker pull is executed, it inspects the manifest list and downloads the image layers appropriate for the host’s architecture.
What most people don’t realize is that the --platform flag isn’t just for CPU architectures. You can also specify different operating systems. For example, --platform windows/amd64 would allow you to build a Windows container image, provided your Buildx environment is configured to support it (which typically requires a separate builder instance running on a Windows machine or using advanced Docker Desktop settings). This makes Buildx incredibly versatile for creating cross-OS and cross-architecture deployable artifacts.
The next step is often to integrate this into your CI/CD pipeline, automating the multi-platform build and push process whenever you commit code.