Building multi arch Docker images without using qemu
Tags: docker, buildx, raspberrypi
Published: 2020-09-23 12:09:01

---
title: Building multi arch Docker images without using qemu
published: true
description: Qemu is slow and crosscompiling is tricky but I have a raspberry pi...
tags: docker,buildx,raspberrypi
cover_image: https://images.unsplash.com/photo-1495508348712-216a17cfbbc4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80
---

Lately I've been doing lots of Rust with [MRML](https://github.com/jdrouet/mrml), [Catapulte](https://github.com/jdrouet/catapulte) and [Jolimail](https://github.com/jdrouet/jolimail), and one of the pain points of Rust is that the compiling process is pretty slow. When, on top of that, you want to build it for amd64, i386, arm64 and arm32v7 because your application is open source and supposed to work everywhere, it becomes a bit tricky to make it build.

Candidly, I initially tried to build it using docker and Qemu for multiple architectures but I finished [with some weird errors](https://github.com/jdrouet/docker-bug-value-too-long).

After a bit of chatting with my previous colleagues from Docker, I was encouraged to try to cross compile. Cross compiling is really great when you don't have a lib dependency on the system. But [Catapulte](https://github.com/jdrouet/catapulte) and [Jolimail](https://github.com/jdrouet/jolimail) are based on [actix](https://crates.io/crates/actix) which depends on OpenSSL, which is supposed to be compiled for the architecture. In short, to cross compile your rust code you first have to cross compile OpenSSL. If you have other libraries, well, cross compile them.

So I did it for [Jolimail](https://github.com/jdrouet/jolimail/blob/master/crosscompile.Dockerfile), it cross compiles, but deep down, I don't like this approach for several reason. First, I've to handle the build of OpenSSL. If there is a new version, I've to update everything and not only rebuild my image. Then, it adds an unwanted complexity to my Dockerfile. So I decided to find another way to do this.

After a bit of digging and a good hint from a nice user on the docker slack community (Billy), I finally did my first use of `docker buildx create --append`. If you're not familiar with `docker buildx` and multi arch images, I encourage you to take a look at [the article I wrote](https://www.docker.com/blog/multi-arch-build-and-images-the-simple-way/), back when I was at Docker.

When you are on an amd64 machine and you want to make a multi arch image, the initial `buildx` solution is to use Qemu to emulate the target environment. But you can also, when you create a `buildx` context, specify a context target for a specific platform.

Like lots of my peers, I bought every version of the raspberry pi, I even have several of each version, but I don't really have time to properly use them. So I started one (3b+ I guess) and installed [HypriotOS](https://blog.hypriot.com/) on it (take a look, install it, test it, it's great). I then created a [context](https://docs.docker.com/engine/context/working-with-contexts/) to be able to build on the raspberry pi from my local machine.

```bash
docker context create rpi --docker "host=ssh://pirate@black-pearl"
```

When this is done, I am able to target the raspberry pi by doing `DOCKER_CONTEXT=rpi docker pull jdrouet/kaamelott-quote`.

Then the trick is to tell `buildx` that, when it needs to build the image for `arm32v7`, it should use the context `rpi`.
First, I use `docker buildx ls` to get the name of the current builder. Then, I append the context to this builder with the following command.

```bash
docker buildx create --append --name you-builder-name --platform linux/arm/v7 rpi
```

And that's it! I can now build your multi arch image.

```bash
docker buildx build --tag jdrouet/catapulte:some-tag --platform linux/amd64,linux/i386,linux/arm/v7 .
```