# ADR-0005 — VM workloads: KubeVirt + CDI - Status: Accepted - Date: 2026-08-15 - Serves: R-PLAT-03, R-PLAT-04, R-STATE-01 - Supersedes: — ## Context Not everything fits in a container. The platform must run VMs, but the operator must manage them through the **same** Kubernetes API/CLI/YAML/GitOps as containers, with the same network isolation, egress classes, storage durability, and observability — no separate hypervisor management plane for application workloads. ## Decision Use **KubeVirt** to run application VMs as Kubernetes custom resources (`VirtualMachine` / `VirtualMachineInstance`), with **CDI (Containerized Data Importer)** to provision VM disks onto **Longhorn** PVCs. VMs run on the same Cilium network (inheriting default-deny + egress classes) and are managed by Flux like any other workload. `virtctl` provides console/lifecycle helpers alongside `kubectl`. ## Alternatives considered - **Proxmox / standalone hypervisor + separate IaC** — a second management plane and tooling; breaks the "same Kubernetes surface" requirement (R-PLAT-03). (The operator's prior environment used Proxmox; this platform deliberately unifies on Kubernetes instead.) - **Harvester (SUSE)** — HCI built on KubeVirt; heavier and opinionated about the whole node OS; k3s + KubeVirt keeps one lightweight cluster for both containers and VMs. - **Containers only** — rejected: the requirement explicitly needs a VM escape hatch. ## Consequences - One control plane, one GitOps flow, one network/storage/observability model for containers *and* VMs. - Nodes must expose virtualization extensions (nested virt in dev KVMs; native on prod) — a node baseline prerequisite ([02](../docs/02-environments-and-provisioning.md)). - VMs are heavier than pods; capacity planning on the 3-node cluster must account for them. - At least one representative VM workload must be proven in dev/test so the IaaS path is real ([06](../docs/06-vm-workloads-kubevirt.md)). - VM guest updates use in-guest automation (R-UPD-*), distinct from container image tag bumps.