How to use docker manifest create command to build multi-architecture images

DockerBeginner
Practice Now

Introduction

In this lab, you will learn how to build and manage multi-architecture Docker images using the docker manifest create command. Multi-architecture images are essential for deploying applications across diverse environments with different CPU architectures, such as amd64 and arm64.

The lab will guide you through the process of preparing multi-architecture images by enabling experimental features and creating a multi-architecture builder instance. You will then create a manifest list that bundles these images, inspect the created manifest list to verify its contents, and finally push the manifest list to a registry, making your multi-architecture image available for deployment on various platforms.

Prepare multi-architecture images

In this step, we will prepare multi-architecture images. Multi-architecture images allow you to build and push images that can run on different architectures, such as amd64 and arm64. This is useful for deploying applications to various environments, including cloud servers, edge devices, and local machines.

First, we need to enable the experimental features in Docker. This allows us to use the buildx command, which is required for building multi-architecture images. We can do this by creating or modifying the Docker configuration file.

Open the Docker configuration file using nano:

nano ~/.docker/config.json

If the file does not exist, nano will create it. Add the following content to the file. If the file already exists, add the "experimental": "enabled" line within the main JSON object.

{
  "experimental": "enabled"
}

Save the file by pressing Ctrl + X, then Y, and Enter.

Next, we need to create a new builder instance that supports multiple architectures. A builder instance is a Docker component that manages the build process.

Create a new builder instance named mybuilder:

docker buildx create --name mybuilder --use

This command creates a new builder instance named mybuilder and sets it as the default builder for subsequent build operations. The output should indicate that the builder has been created and is being used.

Now, let's build a simple multi-architecture image. We will use a basic Dockerfile that creates an image based on Alpine Linux.

Create a directory for our project and navigate into it:

mkdir ~/project/multiarch-demo
cd ~/project/multiarch-demo

Create a Dockerfile in this directory:

nano Dockerfile

Add the following content to the Dockerfile:

FROM alpine:latest
CMD ["echo", "Hello from multi-architecture image!"]

Save the Dockerfile by pressing Ctrl + X, then Y, and Enter.

Now, build the image for both linux/amd64 and linux/arm64 architectures and push it to a dummy registry. We will use localhost:5000 as a placeholder for the registry. In a real scenario, you would replace this with your actual registry address.

Build and push the multi-architecture image:

docker buildx build --platform linux/amd64,linux/arm64 -t localhost:5000/multiarch-demo:latest --push .

This command builds the image for the specified platforms (linux/amd64 and linux/arm64), tags it as localhost:5000/multiarch-demo:latest, and pushes it to the localhost:5000 registry. The output will show the build process for each architecture and the push operation.

Create a manifest list for the images

In this step, we will create a manifest list for the multi-architecture images we built in the previous step. A manifest list is a list of image manifests, each for a different architecture. When you pull an image using a manifest list, Docker automatically selects the correct image for your architecture.

We will use the docker manifest create command to create the manifest list. This command takes the name of the manifest list you want to create, followed by the names of the images you want to include in the list.

Create a manifest list named localhost:5000/multiarch-demo:latest:

docker manifest create localhost:5000/multiarch-demo:latest \
  localhost:5000/multiarch-demo:latest@sha256:$(docker buildx imagetools inspect localhost:5000/multiarch-demo:latest | grep 'Digest:' | awk '{print $2}' | head -n 1) \
  localhost:5000/multiarch-demo:latest@sha256:$(docker buildx imagetools inspect localhost:5000/multiarch-demo:latest | grep 'Digest:' | awk '{print $2}' | tail -n 1)

Let's break down this command:

  • docker manifest create localhost:5000/multiarch-demo:latest: This specifies the name of the manifest list we are creating.
  • localhost:5000/multiarch-demo:latest@sha256:...: These are the images we are adding to the manifest list. We are using the image name followed by @sha256: and the digest of the image. The digest uniquely identifies a specific image layer.
  • $(docker buildx imagetools inspect localhost:5000/multiarch-demo:latest | grep 'Digest:' | awk '{print $2}' | head -n 1): This command chain retrieves the digest of the first image listed by docker buildx imagetools inspect.
  • $(docker buildx imagetools inspect localhost:5000/multiarch-demo:latest | grep 'Digest:' | awk '{print $2}' | tail -n 1): This command chain retrieves the digest of the second image listed by docker buildx imagetools inspect.

The output of the docker manifest create command will be the digest of the newly created manifest list.

Inspect the created manifest list

In this step, we will inspect the manifest list we created in the previous step. Inspecting the manifest list allows us to see which images are included in the list and their details, such as architecture and operating system.

We will use the docker manifest inspect command to view the details of the manifest list.

Inspect the manifest list localhost:5000/multiarch-demo:latest:

docker manifest inspect localhost:5000/multiarch-demo:latest

The output of this command will be a JSON document that describes the manifest list. You should see an array of "manifests", each representing an image for a different architecture. Look for the "platform" field within each manifest entry to see the architecture and operating system. You should see entries for both linux/amd64 and linux/arm64.

This inspection confirms that our manifest list correctly includes the images for the different architectures we built.

Push the manifest list to a registry

In this step, we will push the manifest list we created to a registry. Pushing the manifest list makes it available for others to pull the multi-architecture image. When someone pulls the image using the manifest list tag, Docker will automatically download the correct image for their system's architecture.

We will use the docker manifest push command to push the manifest list.

Push the manifest list localhost:5000/multiarch-demo:latest to the registry:

docker manifest push localhost:5000/multiarch-demo:latest

This command pushes the manifest list and all the images it references to the specified registry (localhost:5000). Since we already pushed the individual images in the first step using docker buildx build --push, this command primarily pushes the manifest list itself.

The output will show the push progress for the manifest list.

After pushing the manifest list, you can verify that it is available in the registry. Although we don't have a running registry in this lab environment to directly query, the successful execution of the docker manifest push command indicates that the manifest list has been prepared for pushing.

To simulate pulling the multi-architecture image and verify that Docker selects the correct architecture, you could try pulling the image on a system with a different architecture (if available). However, within this lab environment, we can rely on the successful push command and the previous inspection step to confirm the manifest list is ready.

Summary

In this lab, we learned how to prepare multi-architecture images using Docker. This involves enabling experimental features in Docker to utilize the buildx command, which is essential for building images compatible with different architectures like amd64 and arm64. We configured the Docker client by modifying the config.json file to enable experimental features. Subsequently, we created a new builder instance named mybuilder using docker buildx create --name mybuilder --use, which is capable of managing multi-architecture builds. Finally, we set up a basic project directory and created a simple Dockerfile based on Alpine Linux as a foundation for building our multi-architecture image.