Multi-Arch Container Images with Podman
Docker is a great introductory tool for the container landscape, but Podman, the cool kid on the block, really caught my attention with its rootless containers and fast startup times. This made me want to try it out. I was quite satisfied with the workflow so far, but when it came to building containers for multiple architectures, I found myself a bit confused. The biggest issue was figuring out 'how' to do it.
The Docker way
Install Docker, go to your project and run
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag docker.io/my/project \
.
Simple as it gets, right? Using Podman unfortunately makes things just a little harder.
The toolchain
Assuming you've already installed podman
from your package repositories, we'll skip straight ahead to the important parts. If not, the ArchWiki has a good explanation of everything you need to install Podman.
Qemu is used to emulate foreign CPU architectures and since we want to build ARM64 images on a AMD64 CPU we also need the qemu-aarch64
package. If you are on a M1 Mac or similar you will need the according qemu-amd64
package to compile the images for your coworkers ;)
Depending on your distro, the package names will be different. On Archlinux you will need these packages:
qemu-user-static
qemu-user-static-binfmt
qemu-system-aarch64
To test if everything works as expected, run
podman run --arch arm64 docker.io/hello-world
You should get something like this as output:
~ ❯ podman run --arch arm64 docker.io/hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(arm64v8)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
If it works, Great!
Building images
Now, to build the images, go to your project and just run the Podman build command with some extra parameters.
podman build \
--platform linux/amd64,linux/arm64 \
--manifest docker.io/peek1e/my-image:v0.0.1 \
--file Dockerfile \
.
--platform
tells podman which architectures to build for--manifest
writes all the built images into a single manifest
the rest are the typical docker style arguments for building images.
Once that is done, you can push the image onto the registry of your choice (here docker.io) with
podman manifest push docker.io/peek1e/my-image:v0.0.1
Et Voilà. Your multi arch image is ready to be used.
Concluding
In my last blog post, we did some digging into setting up an ARM64-based Kubernetes cluster. Building atop that, I had to recompile some of my images for the right CPU architecture. In fashionable GitOps style, I wanted to automate the process using Kaniko (also leveraging rootless container builds), but you need multiple physical machines with the proper architecture to create those. If you are up for that, it has a guide on how to create multi-arch manifests.
With this article, you should at least be able to build the images locally for all the architectures you need and push them onto a registry.
Oh, and just in case. Yes, you can use podman with docker-compose if you are wondering.