Skip to content

Cross-compilation: Docker Buildx ​

Date: 2020/03/18

Context ​

Cross-compilation of Docker images already saw three previous attempts at implementation (original, revisited, base images).

At that point, cross-compilation worked, and every build generated amd64 and arm32 images. The latter had tags prefixed with rpi-.

Multi-architecture images are made possible by using manifests.

When evaluated, manifests were an early-stage experimental feature. The decision was to wait with implementation until the API became sufficiently stable.

What's new ​

Docker 19.03 added the buildx tool as experimental feature.

Buildx allows building the same image for multiple architectures.

How to ​

Buildx comes included with Docker CE, but is hidden behind the experimental features flag.

To build an image under Docker CE:

sh
# Buildx is an experimental feature
export DOCKER_CLI_EXPERIMENTAL=enabled

# Enable the QEMU emulator, required for cross compiling
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

# Remove previous builders
docker buildx rm bricklayer || true

# Create and use a new builder
docker buildx create --use --name bricklayer

# Bootstrap the newly created builder
docker buildx inspect --bootstrap

# Build the image for amd and arm
# Give the image a tag
# Push the image to the docker registry
docker buildx build \
    --push \
    --platform linux/amd64,linux/arm/v7 \
    --tag "$REPO":"$TAG" \
    .

Azure Pipelines (and likely many other CI services) don't use Docker CE, but Docker EE, which does not come with a pre-installed version of buildx. You can still download and install it.

To download and install buildx:

sh
curl \
    --output ~/.docker/cli-plugins/docker-buildx \
    --create-dirs \
    --location \
    https://github.com/docker/buildx/releases/download/v0.3.1/buildx-v0.3.1.linux-amd64
chmod a+x ~/.docker/cli-plugins/docker-buildx

After this, you can use the same build script. The experimental CLI flag is not required.

Proposed changes to deployment pipelines ​

  • Stop building emulation-ready base images for node and python
  • Stop publishing PyPi packages for user-facing repositories
  • Re-evaluate use of brewblox-dev when building
    • pro: one-click pipeline updates
    • con: black box for build commands. Custom behavior like the service_args flags is obscured.
  • Tag multi-platform images as both "tag", and "rpi-tag" for a deprecation period. This allows for a more graceful transition to prefix-less images.

Migrating user images ​

Adding multiple tags to the same image has negligible overhead. We can keep on building both "tag", and "rpi-tag" images. The only difference is that now they're just different names for the same image, and it will be perfectly ok to run rpi- prefixed images on an amd host.

Migrating user configuration ​

The AMD and ARM versions of docker-compose.shared.yml can be merged: they are functionally the same already. Every update overwrites this file. Migrating it is a straightforward operation.

To spread the impact, we can postpose rewriting tags in docker-compose.yml. Tagging the same image with and without rpi- prefix ensures backwards compatibility for both AMD and ARM setups.