Skip to main content

Building Multi-Architecture Docker Images with Buildx

· 3 min read
Aaron Cooper
Founder, Software Engineer @ ASOS.com (Ex. Redgate Software)

In this post, we'll explore how to use Docker Buildx to compile multi-architecture images for .NET, Rust, and Golang. This allows you to build images that can run on both x64 and ARM64 architectures.

Here at cloudcat.dev, we cross-compile all our Docker images. This gives freedom to the end user, ensuring compatibility across a wide range of devices and platforms, and providing a seamless experience regardless of the underlying hardware.

Prerequisites

Before we start, ensure you have the following:

  • Docker
  • Docker Buildx
  • Dockerfile

Setting Up Dockerfile for Buildx

We’ll create a Dockerfile that can build images for both x64 and ARM64 architectures. Here’s an example Dockerfile for .NET, Rust, and Golang.

# .Net
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0 AS build-dotnet
COPY . .
RUN dotnet publish -c Release -o out

# Rust
FROM --platform=$BUILDPLATFORM rust:latest AS build-rust
COPY . .
RUN cargo build --release

# Go
FROM --platform=$BUILDPLATFORM golang:latest AS build-golang
COPY . .
RUN go build -o main .

# Final stage
FROM --platform=$BUILDPLATFORM debian:latest

Have you noticed a pattern? --platform=$BUILDPLATFORM must be included after FROM to ensure the correct image architecture is used when buildx uses the file.

Building the Multi-Architecture Image

Now, let’s build the image for both x64 and ARM64 architectures using Docker Buildx.

1. Create a Buildx Builder Instance

docker buildx create --use --name ${serviceName}_build --bootstrap

This command creates a new Buildx builder instance named ${serviceName}_build, sets it as the default builder, and bootstraps it to ensure it is ready to use.

2. Build and Push the Image

docker buildx build --platform linux/amd64,linux/arm64 -f ${filePath} -t ${imageName}:latest -t ${imageName}:linux-amd64 -t ${imageName}:linux-arm64 --push .

This command builds the Docker image for both linux/amd64 and linux/arm64 platforms. It uses the Dockerfile located at ${filePath}, tags the image with multiple tags (latest, linux-amd64, and linux-arm64), and pushes the built images to the Docker repository.

* Ignore the 0 B, this is a visual bug with Gitlab.

Dimage

You can now pull using the latest tag and run the image without warnings about the image being compiled for a different architecture.

3. Remember to Cleanup

docker buildx rm ${serviceName}_build

This command removes the Buildx builder instance named ${serviceName}_build, cleaning up resources and allowing you to create a new builder instance if needed.

Conclusion

Using Docker Buildx, you can easily create multi-architecture Docker images for .NET, Rust, and Golang. This ensures your applications can run on a variety of devices, from servers to edge devices. Happy coding!