Creating multi-arch docker images

· 492 words · 3 minutes read docker cicd

Docker images are a great way to make your application deployment idempotent and generally platform independent, however that doesn’t cover multiple CPU architectures like i386, ARM, or PowerPC. In order to deploy docker containers to multiple architectures at the same time would normally require multiple tags, but with the Docker Manifest command you can make an image tag reference multiple underlying images for different architectures and operating systems. This could be useful for a multi architecture kubernetes cluster where you have a mix of ARM and x86_64 and don’t want to use a node selector to specify where your images are scheduled, or want to distribute a docker images and allow customers to use any architecture they want. In this post I’ll break down how to create these manifests and push them to a docker repository.

First experimental options need to be enabled in your config.json, if you don’t have a config.json already you can create it with the following content under ~/.docker/config.json assuming you’re on linux:

{
  "experimental": "enabled"
}
Otherwise add the "experimental": "enabled" to your already existing config file.

Once that’s been done your docker client has the ability to use experimental features like creating manifests. For this example I will be using a project I’ve been working on and using in my everyday life, a lightweight docker container that runs in a multi-arch kubernetes cluster to control the LIFX Z Strip in my kitchen. I will create a manifest that combines both the linux ARM image as well as the linux x86_64 image.

docker manifest create registry.gitlab.com/wwsean08/lifx-pastel:latest registry.gitlab.com/wwsean08/lifx-pastel/arm:latest registry.gitlab.com/wwsean08/lifx-pastel/amd64:latest
docker manifest inspect registry.gitlab.com/wwsean08/lifx-pastel:latest
The docker manifset inspect command will allow you to see the manifest it generates and understand the process a bit more. What you will see is that the manifest we created contains two manifests, one for linux amd64, and one for linux arm, these will be used when you try to pull an image, comparing your machines platform information against the manifest to pull the correct one.

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 3051,
         "digest": "sha256:1b9892dcd33cb77c47b52081a1e54165513e93b0c9e64a94dcc8bd37611b0676",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 3050,
         "digest": "sha256:e34aff5906b9eea5adbc649db1ad81534ddea6b4679bbd2988f3f32a1ba8be73",
         "platform": {
            "architecture": "arm",
            "os": "linux"
         }
      }
   ]
}

Now that you have a manifest it’s time to push it to the docker registry by simply running

docker manifest push registry.gitlab.com/wwsean08/lifx-pastel:latest

Once that’s done you are able to pull the same image on either linux/arm or linux/x86_64 with no problems, and are able to use them in your kubernetes configs ore give the docker repo/tag to your customers without having to ask what architecture they are on.

As a reminder this is an experimental feature so may change over time, however many of the “official” images on dockerhub are using them so I don’t think the feature itself will go away. Now go out there and experiment with this useful feature which will make your life much easier.