I like to deploy my applications as OCI images. Technically I'm using Podman these days rather than Docker, but everyone who knows what an OCI image is knows what I mean when I say "Docker image."
I also like to build these images for both linux/arm64
and linux/amd64
. I have one ARM64 server and my laptop is ARM64 but I also have a bunch of x86_64/x64/amd64 servers that I deploy to as well, and it's nice to have one image that works on both of them.
When doing a multi architecture build with Docker or Podman, it seems that they don't actually know anything about these other architectures or ensure that they can run. They rely on QEMU or more specifically qemu-user-static
with binfmt_misc
, so that when the Kernel sees and tries to run the executable for the wrong CPU architecture, QEMU kicks in and emulates it.
Unfortunately, .NET does not officially support running in QEMU and since around the .NET 6/7 timeframe has had problems with running the arm64
binaries on amd64
hosts.
If you're using GitHub Actions, the standard way to set this up is docker/setup-qemu-action
which if you check the code, loads QEMU binaries from the OCI image docker.io/tonystigii/binfmt:latest, and if you go check the repository for that, you'll discover that it is 2 years old and still uses QEMU v7.

This is particularly painful to learn after learning that the bug which causes .NET to fail on QEMU was fixed in version 9.1 in late 2024. Unfortunately that was too late to make the latest Ubuntu releases, which ship QEMU as new as 9.0.
Looking over GitHub Issues and Pull Requests, the binfmt image above has yet to update despite various attempts over the years due to it failing some compatibility test suites, since any change here has the potential to break so many CI/CD pipelines...
Meanwhile, I too have yet to actually manage to build 9.1 from source and get it working, so in the meantime I am stuck with the three-year-old workaround of adding the following magic to my Dockerfile
to continue running in QEMU v7:
ENV DOTNET_EnableWriteXorExecute=0
Sigh.