Hello,
I have recently started tinkering with NixOS and I faced the same issue. For me the problem was that the qemu-{platform}
given by NixOS are dynamically linked which Docker does not like.
As a workaround (still ugly but at least declarative), I stole the qemu-user-static
binaries from the debian repos:
This looks like this:
{ pkgs, ... }:
let
qemu-static-derivation = {
stdenv,
fetchurl,
dpkg,
...
}:
stdenv.mkDerivation {
name = "qemu-static";
pname = "qemu-static";
dontPatchELF = true;
dontConfigure = true;
dontPatch = true;
src = fetchurl {
url = "http://ftp.fr.debian.org/debian/pool/main/q/qemu/qemu-user-static_9.0.0~rc2+ds-1_amd64.deb";
sha256 = "sha256-JrYf2oKUCIptqllolzPhOopVuSEfATPo+fi2bjDlQl4=";
};
unpackPhase = ''
mkdir -p $out
${dpkg}/bin/dpkg-deb -x $src $out
'';
};
qemu-static = pkgs.callPackage qemu-static-derivation {};
in
{
environment.systemPackages = [
qemu-static
];
boot.binfmt.registrations."arm64-linux" = {
interpreter = "${qemu-static}/usr/bin/qemu-aarch64-static";
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
fixBinary = true;
matchCredentials = true;
wrapInterpreterInShell = false;
};
}
In my case I am doing linux/arm64
emulation from an amd64
laptop, but it would be possible to do the other way around by grabbing the qemu-user-static binaries in the debian arm repos instead and setting up the binfmt registration for amd64
by changing the interpreter path, magic and mask.
Additionally, as you can see in the above config, I had to add the fixBinary
flag and disable the wrapInterpreterInShell
. By the way I am curious to know why NixOS default behavior is to wrap the interpreter in a shell script, what does it accomplish?
Hope this helps. And if someone thinks of a way to improve on that solution, please share it. Maybe some version of qemu static binaries should be present in nixpkgs to simplify this use case, what do you think?