Multi-arch All the Things

By Sebastian Barrenechea on Sep 6, 2021
Two chips, one labeled "x86" and the other labeled "ARM".

When we began laying our initial foundations at Finalis, I remember having the idea to test AWS’s Graviton. It wasn’t feasible in 2018 without building things yourself. Fast forward, it’s 2022, and we (as a community) still struggle to find ARMv8 support in Dockerhub images.

But in 2020, something big happened: Apple announced the transition of Macs to Apple Silicon with a 2-year timeline.

At Finalis, we stick with Apple hardware for software development. You get a Unix-like Operating System and fantastic screen and audio quality for watching movies or whatever 🍿.

In 2020, a countdown began. If we wanted to continue acquiring new Apple devices in the future, Finalis needed to become multi-architecture.

Docker

When Apple released the M1, and we got one, Docker was starting to “get along” with it, but Docker on ARM had some issues in earlier versions simply because the engine was being tested (by us, the pioneering developers).

Later it seemed like everything was fine: third-party tools - most of the required images were already available for ARM64, but not all. browserless was the one I started tackling to get it built on ARM64, and so I sent a pull request with the minimum changes needed to make it work.

With third-party tools covered, it was a matter of making sure Docker built our own images for ARM64. “Hey, you use TypeScript; it should just work!”… Well, as long as your dependencies don’t require downloading binaries while running npm install.

The main problem? No binaries are provided for ARM64, forcing a binary build while you run npm install with make (post-installation scripts?). From a configuration perspective, a little love in some of our Dockerfile files was all we needed and it solved everything.

Pipelines

Working with GitHub Actions and dealing with multi-architecture, you have two options: run two parallel runners (one building for x86/64 and the other for arm64), or run one runner for both architectures.

I chose the second option to experiment, through docker buildx. Following the setup instructions for build-push-action you can quickly get an operational pipeline.

Letting buildx handle the multi-architecture build allows you to push to Dockerhub without having to deal with different tags for different architectures. All your tags WILL be multi-architecture compatible.

The downside is the build time: having two parallel runners on their appropriate architectures would be much faster, but the pipeline would require managing the merging of the results into a single tag. Only if you care about making it easier for consumers to find the right image.

Content translated by gpt-4-1106-preview

©2022-2024 Sebastian Barrenechea. All rights reserved.

Built with Astro v4.15.9.