error: a 'x86_64-linux' with features {kvm} is required to build '/nix/store/zf5rifg7gyszd9cxx8xmxmzfcg4ia772-docker-layer-delme.drv', but I am a 'x86_64-linux' with features {benchmark, big-parallel, nixos-test}
The error only occurs if the runAsRoot attribute is provided, otherwise the Docker image builds correctly. Hoping someone can advise as to what the error means, and how I might be able to fix it. Thanks!
The runAsRoot setting uses kvm (kernel VM implementation) to run the commands, rather than doing it through containers.
I don’t really understand why either, to be honest, would be much better to use something like bubblewrap.
This requires enabling your CPU’s virtualization features in BIOS if you’re on bare metal. If you’re building on cloud infra you might be out of luck, or at the very least need to look into virtualization options…
An alternative might be to use Entrypoint and manage your directory setup/switching to the target user there.
I’m sorry to ask this, but are you sure you really need to do something as root? I observed users often rely on runAsRoot while it would actually not be required.
If you really need runAsRoot, i would be interested in your use case!
With a big of digging, I found this post, which suggested adding:
system-features = kvm
to /etc/nix/nix.conf. That enabled the build to work without an error (although I got the following logs - it looks like it’s using QEMU TCG emulation to run something?)
Regarding the user, maybe defining the uid:gid as image configuration(Config.User=...) could be enough.
Regarding /tmp permissions, i don’t remember if it is possible with dockerTools (without runAsRoot) but nix2container provides a way to set permissions on files.
I typically just do passwd and group really, I’ve not looked into the benefit of including shadow
add a root:x:0:0....etc to that too if you want
*(UID is determined at container creation so it doesn’t really matter if the container FS has that user listed, it will just say it’s unknown. The main thing you want to watch out for is host collisions if you’re not using user namespacing)
λ docker run -u 12345 -it nixos/nix
bash-5.1$ id -u
12345
bash-5.1$ whoami
whoami: cannot find name for user ID 12345
bash-5.1$ cat /etc/passwd | grep "12345"
bash-5.1$
Hm, I wonder what the effect of using qemu-tcg is. I’d dig into that before recommending/using it. If it’s still properly virtualized, sure, but I suspect it’s just running things on the host, and might sneak in nonreproducible state.
Or just go with any of the recommendations here, it’ll significantly speed up your builds to skip runAsRoot.
This example is pretty complicated but it’s complete:
Thanks - I have to admit I’m very new to Nix, and this is the first use case I’m really trying it out with, so I apologise in advance that I don’t really know what I’m doing! In particular, I don’t know how to transplant that example to my use case - I don’t suppose you could indicate how I could change my example from above to e.g. write a line to /etc/passwd without using runAsRoot? Would be much appreciated!
I get an error unfortunately, not sure what it’s indicating:
$ nix-build delme.nix
trace: warning: in docker image delme: The contents parameter is deprecated. Change to copyToRoot if the contents are designed to be copied to the root filesystem, such as when you use `buildEnv` or similar between contents and your packages. Use copyToRoot = buildEnv { ... }; or similar if you intend to add packages to /bin.
error: cannot coerce a function to a string
at /nix/store/37nl1pnk837xd0033qw7jrq7i18q36vn-nixpkgs/nixpkgs/pkgs/build-support/docker/default.nix:350:9:
349| inherit baseJson extraCommands;
350| contents = copyToRoot;
| ^
351| nativeBuildInputs = [ jshon rsync tarsum ];
(use '--show-trace' to show detailed location information)
Thanks - unfortunately I still get an error with that recipe:
$ nix-build delme.nix
trace: warning: in docker image delme: The contents parameter is deprecated. Change to copyToRoot if the contents are designed to be copied to the root filesystem, such as when you use `buildEnv` or similar between contents and your packages. Use copyToRoot = buildEnv { ... }; or similar if you intend to add packages to /bin.
error: cannot convert a function to JSON
at /nix/store/37nl1pnk837xd0033qw7jrq7i18q36vn-nixpkgs/nixpkgs/pkgs/build-support/trivial-builders.nix:78:8:
77| # TODO(@Artturin): enable strictDeps always
78| }: buildCommand:
| ^
79| stdenv.mkDerivation ({
(use '--show-trace' to show detailed location information)
I think I’ll need to go off and read up a bit to understand exactly what’s going on in this recipe, but I had one conceptual question - what’s the difference between making changes to a Docker image using pkgs.runCommand and runAsRoot? They ostensibly would seem similar - both making changes to the image through a series of commands that need root privileges. One wants to use KVM and the other doesn’t?
anything that goes in copyToRoot is going to be built in nix world as normal. runAsRoot builds a VM, then runs that VM in order to safely run these commands as “root” even if you’re not “root” on the host & then exports the output.
We could try replace some of that with a rootless container but that would likely then depend on user namespaces being enabled for your kernel, whereas with nix we can enforce having KVM as a required feature.