DEV Community

Cover image for Multi-CPU architecture container images. How to build and push them on Docker Hub (or any other registry)
Petr Razumov for Tidal

Posted on • Updated on • Originally published at tidalmigrations.com

Multi-CPU architecture container images. How to build and push them on Docker Hub (or any other registry)

This is the second post in the series on how we prepared our application to run on M1 (Apple Silicon).

In the previous part we were talking about Go programming language and its ability to easily cross-compile applications for different operating systems and CPU architectures using just a developer's laptop.

With this post, I'm going to describe some other aspects of modern cross-platform applications development.

Our application

It's worth repeating that at Tidal Migrations we build our CLI application — Tidal Tools — to make it easier for our customers to deal with all sorts of data necessary on their way towards the clouds. Tidal Migrations' May 2021 Newsletter describes Tidal Tools as the

meat-and-potatoes of how you’ll start your cloud journey.

The CLI app could be run anywhere:

Locally

  • on Microsoft Windows
  • on Apple macOS (Intel or M1)
  • on GNU/Linux

Or preinstalled on a free cloud VM in:

Tidal Tools architecture in brief

Tidal Tools is a Go command-line interface (CLI) application. It mostly acts as a Tidal Migrations API client accompanying our web application. It also has some additional features like source code and database analysis.

Those two extra functionalities are implemented by our technological partners in other programming languages.

We build Docker container images for such 3rd-party solutions and our application (Tidal Tools) runs containers under the hood using the awesome Docker Go SDK.

Problems with container images

While preparing a new release of Tidal Tools for M1 Macs we discovered that our existing Docker container images won't work on the new Apple Silicon architecture. After some investigation we figured out that we build our container images for amd64 architecture, while M1 Macs expect images for arm64 CPU architecture.

Docker images can support multiple architectures, which means that a single image may contain variants for different architectures, and sometimes for different operating systems, such as Windows.

When running an image with multi-architecture support, docker automatically selects the image variant that matches your OS and architecture.

After some trial and error with our Docker images we are now finally confident in our happy path on how to build multi-CPU architecture Docker container images. In other words, we now know how to build container images for different architectures and push such images to container registries (e.g. Docker Hub) to be used on machines with different OSes and architectures. In short, build on (for example) Debian GNU/Linux — run on (for example) macOS for M1!

So, without further delay, let's jump straight to the topic!

How to build multi-arch container images with docker buildx

CAUTION! To build container images with multi-CPU architecture support, you need to use parent image which supports multiple CPU architectures. Most of the official images on Docker Hub provide a variety of architectures. For example, the openjdk image variants (which we're going to use later) support arm64v8 and amd64.

For this example, we're going to use “Hello world” application written in Java:

// HelloWorld.java

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello world!");
  }
}
Enter fullscreen mode Exit fullscreen mode

Let's start with a Dockerfile:

# Dockerfile

FROM openjdk:8-jdk-slim AS builder
COPY HelloWorld.java /app/
WORKDIR /app
RUN javac HelloWorld.java

FROM openjdk:8-jre-slim
COPY --from=builder /app/HelloWorld.class /app/
WORKDIR /app
CMD ["java", "HelloWorld"]
Enter fullscreen mode Exit fullscreen mode

To make it possible to build multi-CPU architecture container images we need to install Docker Buildx. Docker Buildx is a CLI plugin that extends the docker command with some additional features, and multi-arch builds is one of those. If you're using recent Docker Desktop or Docker for Linux packages chances are high that Buildx is already available for you. If not, check the installation instructions.

Create and switch to using a new builder which gives access to the new multi-architecture features:

docker buildx create --name mybuilder --use
Enter fullscreen mode Exit fullscreen mode

Log in to a Docker registry:

docker login
Enter fullscreen mode Exit fullscreen mode

Build and push multi-arch container image for x86-64 (amd64) and AArch64 (arm64) CPU platforms (replace your-username with the actual Docker registry user name):

docker buildx build . \
  --platform linux/arm64,linux/amd64 \
  --tag your-username/hello-world:latest \
  --push
Enter fullscreen mode Exit fullscreen mode

Running the above commands would build and push multi-arch container images to your Docker Hub profile:

alt text

When running such image with multi-architecture support, docker automatically selects the image variant that matches the running OS and architecture.

That's it! With this simple trick you can build Docker container images for different operating systems and architectures and host such images on Docker Hub.

I hope you enjoyed this post! Stay tuned to learn more about how we prepared our application to run on M1 (Apple Silicon)!

Top comments (1)

Collapse
 
santosh profile image
Santosh Kumar

I am having trouble running built image. Both arm64 & amd64 images are built. arm64 runs on arm64, but amd64 does not runs on amd64.
More info: reddit.com/r/docker/comments/t1yz4...
Help is highly appreciated.