Requirements#
kdevops-ng targets a Linux distribution with two things installed: systemd and
Nix. The host’s systemd runs the Windmill stack and the guest VMs as
systemd --user services, and Nix builds and runs everything else: the
Windmill server, the kernels and QEMU under test, and the developer tooling. So
the host stays minimal: it needs no distro QEMU or build packages, only Nix and
a little kernel-level access for the guests.
kdevops-ng needs systemd as the init system. systemctl is-system-running
reports the manager state (running, or degraded if a unit has failed),
and is absent or errors where systemd is not PID 1. The underlying check, the
one sd_booted performs, is whether /run/systemd/system exists. Modern
distributions satisfy this by default.
Nix#
Install Nix with the recommended multi-user (daemon) installation:
$ curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install \
| sh -s -- --daemon
See the Nix install guide for other installers and platform notes.
The flake uses the unified nix CLI, which needs the experimental features
enabled once:
$ mkdir --parents ~/.config/nix
$ echo 'experimental-features = nix-command flakes' \
| tee --append ~/.config/nix/nix.conf
Host access for guests#
Running the guest VMs (the f/qsu flows) needs kernel-level access granted
once. Add yourself to the kvm group for /dev/kvm (QEMU’s -accel kvm)
and systemd-journal to read service logs without sudo:
$ sudo usermod --append --groups kvm,systemd-journal "$(whoami)"
Log out and back in for the group change to take effect.
PCI passthrough (VFIO)#
Letting a guest take a host PCI device (an NVMe drive, say) needs VFIO. This is
a one-time sudo setup that grants the kvm group access to the devices you
may want to hand to guests; after it, a flow binds and passes a device in user
mode, with no sudo at VM time. Do it only for devices you intend to make
available; skip the section otherwise.
First list the host PCI devices and note the address of each candidate. The
first column is the address, with the 0000: domain shown by -D:
$ lspci -nn -D
0000:2d:00.0 Non-Volatile memory controller [0108]: Samsung ... [144d:a80a]
Record the addresses in a small YAML file, say passthrough.yaml:
pci_passthrough:
- addr: "0000:2d:00.0"
- addr: "0000:03:00.0"
opts: "rombar=0"
opts is an optional string of extra QEMU -device vfio-pci properties
(rombar=0 drops the option-ROM BAR). List the available ones with
qemu-system-x86_64 -device vfio-pci,help; see the QEMU device emulation
guide for the syntax and the kernel VFIO docs for the framework.
Load the vfio-pci driver:
$ sudo cp vendor/qemu-system-units/files/vfio-pci.conf \
/etc/modules-load.d/vfio-pci.conf
$ sudo modprobe vfio-pci
Render the udev rule from your file and install it (minijinja-cli comes from
the development shell). It sets SUBSYSTEM=="vfio", GROUP="kvm", MODE="0660"
so the
kvm group can open /dev/vfio, with a per-device block for each address:
$ nix develop --command minijinja-cli --trim-blocks \
vendor/qemu-system-units/templates/vfio-udev.rules.j2 passthrough.yaml \
| sudo tee /etc/udev/rules.d/10-vfio-kvm.rules
Reload udev so the rule takes effect:
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger --subsystem-match=pci