Mensen denken vaak dat je VMware, Hyper-V, of minstens Proxmox nodig hebt om een “echte” hypervisor te draaien. Iets met een web UI, enterprise features, het hele pakket.
Maar hier is het ding: KVM met libvirt kan vrijwel alles wat die commerciële hypervisors doen. Live migratie, memory ballooning, CPU pinning, GPU passthrough, SR-IOV, nested virtualization — het is er allemaal. De Linux kernel is al meer dan tien jaar een production-grade hypervisor.
Ik draai NixOS als mijn hypervisor. Geen Proxmox, geen web UI, alleen declaratieve Nix configs en virsh. Laat me je tonen wat er mogelijk is.
De Basis: KVM en QEMU
Voordat we induiken, even de stack verduidelijken:
- KVM (Kernel-based Virtual Machine): Een Linux kernel module die je kernel verandert in een type-1 hypervisor. Hardware-versneld, near-native performance.
- QEMU: De userspace emulator die virtuele hardware (disks, netwerkkaarten, etc.) levert aan VMs.
- libvirt: Een management laag die een consistente API biedt over verschillende virtualisatietechnologieën. Bevat de
virshCLI.
Samen drijft deze stack alles aan van de VMs op je laptop tot massieve cloud infrastructuur. AWS’s Nitro hypervisor? Gebouwd op KVM. Google Cloud? KVM. Het grootste deel van de cloud draait op deze technologie.
NixOS Configuratie
Zo stel ik NixOS in als hypervisor:
{ config, pkgs, ... }:
{
# Enable virtualization
virtualisation.libvirtd = {
enable = true;
qemu = {
package = pkgs.qemu_kvm;
runAsRoot = true;
swtpm.enable = true; # TPM emulatie
ovmf = {
enable = true; # UEFI support
packages = [ pkgs.OVMFFull.fd ];
};
};
};
# Voeg jezelf toe aan de libvirt groep
users.users.tom = {
extraGroups = [ "libvirtd" ];
};
# Handige tools
environment.systemPackages = with pkgs; [
virt-manager # GUI als je wilt
virt-viewer # Voor console access
libguestfs # VM image manipulatie
win-virtio # Windows VirtIO drivers
];
# Bridge networking (optioneel, voor bridged VMs)
networking.bridges.br0.interfaces = [ "enp1s0" ];
networking.interfaces.br0.useDHCP = true;
}
Pas deze config toe, en je hebt een volledig functionele hypervisor. Dat is het. Geen installer, geen setup wizard, alleen Nix.
VMs Maken met virsh
Laten we een VM maken. Eerst een disk alloceren:
# Maak een 50GB qcow2 disk
qemu-img create -f qcow2 /var/lib/libvirt/images/ubuntu-server.qcow2 50G
Definieer dan de VM met XML (of gebruik virt-install):
virt-install \
--name ubuntu-server \
--memory 4096 \
--vcpus 2 \
--disk /var/lib/libvirt/images/ubuntu-server.qcow2 \
--cdrom /var/lib/libvirt/images/ubuntu-24.04-server.iso \
--os-variant ubuntu24.04 \
--network bridge=br0 \
--graphics vnc
Nu heb je een draaiende VM. Beheer het met:
virsh list --all # Lijst alle VMs
virsh start ubuntu-server # Start VM
virsh shutdown ubuntu-server # Graceful shutdown
virsh destroy ubuntu-server # Force stop
virsh console ubuntu-server # Seriële console
Live Migratie
Hier denken mensen dat je enterprise software nodig hebt. Dat is niet zo.
Live migratie verplaatst een draaiende VM van de ene host naar de andere met minimale downtime. De VM blijft draaien terwijl het geheugen gekopieerd wordt, dan gebeurt de finale switchover in milliseconden.
Vereisten:
- Gedeelde storage (NFS, Ceph, GlusterFS) of zelfde disk pad op beide hosts
- Zelfde CPU architectuur (of gebruik CPU model compatibiliteit)
- libvirt draaiend op beide hosts
# Vanaf de bron host
virsh migrate --live ubuntu-server qemu+ssh://target-host/system
# Met opties voor betere performance
virsh migrate --live --persistent --undefinesource \
--copy-storage-all \
ubuntu-server qemu+ssh://target-host/system
Dat is het. Je VM draait nu op de andere host. De --copy-storage-all flag kopieert zelfs de disk als je geen gedeelde storage hebt.
Voor gescripte omgevingen kun je dit programmatisch doen:
#!/bin/bash
# Simpele load balancer - migreer VM naar minst belaste host
HOSTS=("host1" "host2" "host3")
VM="ubuntu-server"
# Vind host met laagste load
TARGET=$(for h in "${HOSTS[@]}"; do
echo "$(ssh $h 'cat /proc/loadavg | cut -d" " -f1') $h"
done | sort -n | head -1 | cut -d" " -f2)
virsh migrate --live $VM qemu+ssh://$TARGET/system
Memory Ballooning
Memory ballooning laat je VM-geheugen dynamisch aanpassen zonder herstarten. De balloon driver van de VM geeft geheugen terug aan de host of vraagt meer aan.
Zet het aan in je VM definitie:
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</memballoon>
Pas dan aan tijdens runtime:
# Zet huidig geheugen op 2GB (VM heeft 4GB max)
virsh setmem ubuntu-server 2G --live
# Geef weer 4GB terug
virsh setmem ubuntu-server 4G --live
Dit is ongelooflijk handig voor memory overcommitting. Je kunt 64GB toewijzen over VMs op een 32GB host, en de balloon driver balanceert het daadwerkelijke gebruik.
GPU Passthrough
Dit is de holy grail voor homelab enthousiastelingen: een fysieke GPU direct doorgeven aan een VM voor near-native graphics performance. Gaming VMs, machine learning workloads, transcoding — allemaal mogelijk.
Configureer eerst IOMMU in je NixOS config:
{
boot.kernelParams = [
"intel_iommu=on" # of amd_iommu=on voor AMD
"iommu=pt"
];
# Isoleer de GPU van de host
boot.extraModprobeConfig = ''
options vfio-pci ids=10de:2204,10de:1aef
'';
boot.initrd.kernelModules = [
"vfio_pci"
"vfio"
"vfio_iommu_type1"
];
}
Vind de PCI IDs van je GPU:
lspci -nn | grep -i nvidia
# 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation ... [10de:2204]
# 01:00.1 Audio device [0403]: NVIDIA Corporation ... [10de:1aef]
Voeg dan de GPU toe aan je VM:
<hostdev mode='subsystem' type='pci' managed='yes'>
<source>
<address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
</source>
</hostdev>
<hostdev mode='subsystem' type='pci' managed='yes'>
<source>
<address domain='0x0000' bus='0x01' slot='0x00' function='0x1'/>
</source>
</hostdev>
De VM heeft nu directe toegang tot de GPU. Installeer de native drivers in de guest, en je krijgt volledige hardware acceleratie.
Netwerkkaart Passthrough en SR-IOV
Hetzelfde principe werkt voor netwerkkaarten. Voor 10GbE of 25GbE kaarten wil je misschien directe passthrough:
# Vind de NIC
lspci -nn | grep -i ethernet
# Geef door zoals de GPU
Maar de echte kracht is SR-IOV (Single Root I/O Virtualization). Het splitst één fysieke NIC in meerdere virtual functions, elk toewijsbaar aan een andere VM:
# Enable 4 virtual functions op de NIC
echo 4 > /sys/class/net/enp5s0f0/device/sriov_numvfs
# Lijst ze
lspci | grep "Virtual Function"
Elke VF krijgt zijn eigen PCI adres en kan worden doorgegeven aan een VM. Hardware-versnelde networking zonder de overhead van virtio.
CPU Pinning
Voor latency-gevoelige workloads wil je dat VMs specifieke CPU cores gebruiken zonder gemigreerd te worden door de scheduler:
<vcpu placement='static'>4</vcpu>
<cputune>
<vcpupin vcpu='0' cpuset='4'/>
<vcpupin vcpu='1' cpuset='5'/>
<vcpupin vcpu='2' cpuset='6'/>
<vcpupin vcpu='3' cpuset='7'/>
<emulatorpin cpuset='0-1'/>
</cputune>
Dit pint de 4 vCPUs van de VM aan host cores 4-7, met emulator threads op cores 0-1. Gecombineerd met isolcpus in je kernel parameters krijg je near-bare-metal latency.
Declaratief VM Beheer op NixOS
Hier schittert NixOS. Je kunt VMs declaratief definiëren:
{
virtualisation.libvirtd.enable = true;
# Definieer VMs als Nix expressies
systemd.services."libvirt-guest-ubuntu" = {
after = [ "libvirtd.service" ];
requires = [ "libvirtd.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = "yes";
};
script = ''
${pkgs.libvirt}/bin/virsh define /etc/libvirt/qemu/ubuntu-server.xml || true
${pkgs.libvirt}/bin/virsh start ubuntu-server || true
'';
preStop = ''
${pkgs.libvirt}/bin/virsh shutdown ubuntu-server || true
sleep 10
${pkgs.libvirt}/bin/virsh destroy ubuntu-server || true
'';
};
}
Of gebruik NixVirt voor een meer geïntegreerde aanpak:
{
virtualisation.libvirt.connections."qemu:///system" = {
domains = [{
definition = ./vms/ubuntu-server.xml;
active = true;
}];
};
}
Je VMs zijn nu onderdeel van je NixOS configuratie. Version controlled, reproduceerbaar, declaratief.
De Limieten van CLI-Only
Ik draai deze setup al jaren, en het werkt goed. Maar ik ga niet doen alsof het allemaal rozengeur en maneschijn is.
Wat vervelend wordt:
- VMs maken:
virt-installheeft een miljoen flags. Ik heb wrapper scripts, maar mooi is het niet. - Monitoring: Je eindigt met scripts schrijven om VM status, resource gebruik en health te checken. Of grafana dashboards met libvirt exporters.
- Storage beheer: Pools maken, volumes, snapshots — allemaal mogelijk met
virsh, maar de commando’s zijn verbose. - Netwerk visualisatie: Welke VM zit op welke bridge? Welke heeft welk IP? Je hebt scripts of goede documentatie nodig.
Wat scripts niet makkelijk kunnen:
- Snel visueel overzicht: Hoe doen mijn VMs het? Wat is het resource gebruik? Een dashboard verslaat
virsh listplusvirsh domstatsplus parsen. - Console toegang:
virt-viewerwerkt, maar een web-based console is handiger voor remote beheer. - Delegatie: Wil je iemand anders specifieke VMs laten beheren zonder volledige host access? Dat is complex met raw libvirt.
Waarom Proxmox Bestaat
Dit brengt me bij Proxmox. Het is dezelfde onderliggende technologie — KVM, QEMU, libvirt — maar verpakt in een web UI die alles toegankelijker maakt.
Ik zeg niet dat je Proxmox nodig hebt. Voor een homelab waar jij de enige admin bent, is NixOS + virsh + scripts prima werkbaar. Ik heb het jaren zo gedraaid.
Maar er zit echte waarde in een goede UI:
- Onboarding: Nieuw teamlid begrijpt de infrastructuur direct
- Emergency response: Om 3 uur ’s nachts is klikken makkelijker dan
virshsyntax onthouden - Zichtbaarheid: Zie alle VMs, hun status, resource gebruik, netwerk topologie in één oogopslag
- Geïntegreerde features: Backup scheduling, HA clustering, firewall regels — geconfigureerd op één plek
Proxmox voegt ook clustering, Ceph integratie en backup beheer toe dat significante moeite zou kosten om te repliceren met scripts.
Mijn Aanbeveling
Als je virtualisatie diepgaand wilt leren, begin met NixOS + KVM + virsh. Je begrijpt precies wat er gebeurt. Geen magie, geen abstractie. Elke feature die de “enterprise” hypervisors adverteren, kun je zelf implementeren.
Als je virtualisatie in productie moet draaien of met een team, overweeg Proxmox. De UI is niet alleen gemak — het is operationele gezondheid.
En als je zoals ik bent — een homelab draait waar leren deel van de lol is — is NixOS als hypervisor een geweldige keuze. Declaratieve configs, volledige controle, en de voldoening van weten dat er geen vendor lock-in is. Gewoon Linux, doend wat Linux het beste doet.
De beste hypervisor is degene die je begrijpt. KVM geeft je dat begrip. Of je het verpakt in Proxmox, NixOS, of raw scripts is een kwestie van voorkeur en use case.
