From a4609501c48e8cfec53259c3defd3055c72065cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ryan4yin=20=7C=20=E4=BA=8C=E8=8A=B1?= Date: Mon, 21 Sep 2026 11:21:33 +0800 Subject: [PATCH] feat(kubevirt-youko): serve VM golden images from a shared NFS store (#282) * feat(kubevirt-youko): export a shared golden-image store over NFS * feat(vm-images): upload golden images into the cluster Replace the rsync-to-orangepi5 step with a CDI upload into the golden-image PVCs (vms/golden-images in k8s-gitops), so VM images no longer depend on the single-board file server. --- hosts/k8s/kubevirt-youko/nfs-golden.nix | 31 +++++++++++++++++++++++++ utils.nu | 12 ++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 hosts/k8s/kubevirt-youko/nfs-golden.nix diff --git a/hosts/k8s/kubevirt-youko/nfs-golden.nix b/hosts/k8s/kubevirt-youko/nfs-golden.nix new file mode 100644 index 00000000..05b415b7 --- /dev/null +++ b/hosts/k8s/kubevirt-youko/nfs-golden.nix @@ -0,0 +1,31 @@ +{ + ... +}: +let + # Shared golden-image store for the KubeVirt cluster. It is exported over + # NFSv4 so the cluster's NFS CSI driver can hand out RWX volumes to every + # node, and VM disks are cloned from it into local-path. + # + # It lives on the encrypted btrfs pool (/persistent), which has plenty of + # free space on this host. + goldenDir = "/persistent/nfs/golden"; + + # Only the homelab LAN may mount the export. The KubeVirt nodes are the + # clients (the CSI node plugin mounts from the node, not from the pod). + clientCidr = "192.168.5.0/24"; +in +{ + # Make sure the export directory exists before the NFS server starts. + systemd.tmpfiles.rules = [ + "d ${goldenDir} 0755 root root -" + ]; + + services.nfs.server.enable = true; + services.nfs.server.exports = '' + ${goldenDir} ${clientCidr}(rw,sync,no_subtree_check,fsid=0,no_root_squash) + ''; + + # NFSv4 only needs 2049/tcp (no rpcbind/mountd/statd), so the firewall stays + # minimal. The export itself is already restricted to the LAN CIDR above. + networking.firewall.allowedTCPPorts = [ 2049 ]; +} diff --git a/utils.nu b/utils.nu index b7352ac3..52cfe932 100644 --- a/utils.nu +++ b/utils.nu @@ -89,6 +89,14 @@ export def upload-vm [ nix build $target } - let remote = $"root@192.168.5.178:/data/caddy/fileserver/vms/kubevirt-($name).qcow2" - rsync -avz --progress --copy-links --checksum result/nixos-image-*.qcow2 $remote + # Push the freshly built image into its golden-image PVC. The PVC is + # declared in k8s-gitops (vms/golden-images) and lives on the shared NFS + # store exported by kubevirt-youko, so every node can clone it when a VM + # is (re)created. + # + # Requires the CDI upload proxy to be reachable from here; it is exposed + # as a NodePort by the cluster (see infra/configs/base/kubevirt). + let uploadProxyUrl = "https://192.168.5.181:30443" + let image = (glob result/nixos-image-*.qcow2 | first) + virtctl image-upload pvc $"golden-($name)" -n vms --image-path $image --uploadproxy-url $uploadProxyUrl --insecure }