KubeVirt turns Kubernetes into a unified platform for virtual machines and containers. Each VM runs as a VirtualMachineInstance (VMI) with its persistent disk backed by a DataVolume, which is itself a standard persistent volume claim provisioned by a CSI driver. The Kubernetes control plane manages the VM lifecycle the same way it manages pods: using the same scheduler, networking, and storage primitives.
This architecture has a critical implication. The storage model you choose determines whether live migration works, whether VMs can reschedule freely across nodes, and whether you are pinned to specific hosts for fault tolerance. Getting KubeVirt storage right from the start avoids a class of operational constraints that are expensive to fix after VMs are running in production.
Why KubeVirt Storage Is Different from Container Storage
Container volumes are typically short-lived and stateless-adjacent. A database pod holds its data in a PVC, but the pod restarts frequently and the storage model assumes that any cluster node can serve the volume on demand. Kubernetes tolerates short interruptions for most containerized workloads.
KubeVirt VMs have fundamentally different requirements:
- Long-running block devices: VMs stay attached to their disk for days or weeks. The disk has block-device semantics: guest operating systems issue raw block I/O directly through the QEMU device layer, not through a filesystem mounted over a PVC.
- Live migration requires instant disk access from the destination node: When a VM live-migrates, the guest memory state copies to the destination node. The disk must remain accessible from that destination node immediately, without any data copy or re-sync step.
- Node drain tolerance: When a Kubernetes node drains for maintenance, VMs on it must either live-migrate or terminate cleanly. If the disk is local to the draining node, live migration cannot proceed without first moving all disk data.
These requirements mean that local-disk storage, which works acceptably for containerized workloads, creates hard scheduling constraints for production VM operations on Kubernetes.
How Hyperconverged Storage Limits VM Live Migration
Hyperconverged storage systems run storage software on the same nodes as compute workloads, distributing data across the cluster using replication. The appeal is reduced infrastructure: no separate storage nodes, no additional network hardware.
The problem for KubeVirt is that hyperconverged storage is topology-aware by design. A volume’s data lives on a subset of cluster nodes, typically two or three, depending on the replication factor. When a VM needs to live-migrate to a node that is not among the replica holders, the storage system must take one of three paths:
- Re-sync the data to the destination node before migration can proceed. For large VM disks, this takes minutes to hours.
- Serve I/O remotely from the replica nodes to the destination node, adding extra network hops to every disk operation the VM issues after migration.
- Block the migration until data locality is established at the destination, which defeats the purpose of live migration for routine maintenance.
Platform teams running hyperconverged storage with KubeVirt typically discover this constraint during the first planned node drain. The drain waits for VM disks to replicate to an eligible destination before migration can proceed, or it times out and terminates the VM instead. For VM disk images in the range of hundreds of gigabytes to several terabytes, the wait is measured in minutes at best.
Running KubeVirt VMs in production and hitting live migration constraints? simplyblock’s disaggregated NVMe/TCP storage gives every node instant access to any VM disk, removing topology constraints from live migration entirely. Talk to a storage architect
NVMe/TCP as the Storage Fabric for KubeVirt
Disaggregated storage separates storage nodes from compute nodes. Storage runs on dedicated hosts with NVMe drives. Compute nodes access storage over the network. The VM disk is never local to any compute node: it is always network-attached and accessible from any node that can reach the storage network.
NVMe over TCP carries native NVMe commands over standard Ethernet without specialized hardware or RDMA-capable NICs. The Linux kernel NVMe/TCP driver has been upstream since kernel 5.0. For VM workloads, NVMe/TCP delivers:
- 100 to 400 microseconds of latency round-trip on a 25 GbE link, adequate for VM guest I/O
- Up to 65,535 queue pairs per namespace, supporting the high I/O parallelism that modern guest operating systems issue
- Any-node access: any compute node can attach any NVMe/TCP volume without data movement
Simplyblock provides a disaggregated NVMe/TCP block storage pool for Kubernetes, integrated via a standard CSI driver. Each KubeVirt VM’s DataVolume is backed by a simplyblock volume. Because the volume is network-attached:
- Live migration from any source node to any destination completes without moving disk data
- Simplyblock handles multi-replica durability at the storage layer, so a lost compute node does not mean lost VM data
- Storage capacity scales independently from compute: add VM capacity (compute nodes) and storage capacity (NVMe nodes) on separate schedules
Configuring Kubernetes Storage for KubeVirt VMs
KubeVirt storage configuration has three components: the StorageClass, the DataVolume, and the VirtualMachine spec referencing that volume.
A StorageClass for KubeVirt VM disks using simplyblock:
apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: simplyblock-nvme-vmprovisioner: csi.simplyblock.ioparameters: pool: vm-tier replication: "2"volumeBindingMode: WaitForFirstConsumerallowVolumeExpansion: truereclaimPolicy: RetainSetting reclaimPolicy: Retain is important for VM disks. If a VirtualMachine object is deleted by mistake, Retain prevents the underlying volume from being automatically removed, giving operators time to recover the data.
A DataVolume that imports a VM disk image from a container registry:
apiVersion: cdi.kubevirt.io/v1beta1kind: DataVolumemetadata: name: vm-disk-ubuntu-24 namespace: production-vmsspec: source: registry: url: docker://quay.io/containerdisks/ubuntu:24.04 pvc: accessModes: - ReadWriteMany storageClassName: simplyblock-nvme-vm resources: requests: storage: 50Gi volumeMode: BlockUsing volumeMode: Block keeps the disk as a raw block device end-to-end. There is no filesystem layer between the guest OS and the NVMe/TCP volume, which minimizes I/O overhead and avoids double-caching between the guest page cache and a host filesystem cache. KubeVirt live migration with block-mode volumes requires the CSI driver to support the ReadWriteMany access mode so both source and destination nodes can access the volume concurrently during the migration window. The simplyblock CSI driver supports ReadWriteMany for block volumes.
A VirtualMachine spec referencing the DataVolume:
apiVersion: kubevirt.io/v1kind: VirtualMachinemetadata: name: ubuntu-prod-1 namespace: production-vmsspec: running: true template: spec: domain: devices: disks: - name: disk0 disk: bus: virtio volumes: - name: disk0 dataVolume: name: vm-disk-ubuntu-24For clusters running mixed workloads, use separate StorageClasses for VMs and containers. VM disk volumes benefit from higher replication factors and Retain reclaim policy. Container workload PVCs can use a separate StorageClass with Delete reclaim policy and lower overhead.
Choosing a Storage Model for KubeVirt
| Storage Model | Live Migration | Block Latency | Topology Constraint | Scale Model |
|---|---|---|---|---|
| Disaggregated NVMe/TCP (simplyblock) | Instant, any node | 100-400µs | None | Storage and compute scale independently |
| Hyperconverged distributed storage | Requires data sync or remote I/O | 1-5ms | Data locality required | Storage and compute scale together |
| NFS / shared filesystem | Immediate (shared mount) | 2-10ms | None | Scale NFS servers independently |
| Cloud block storage (EBS, Azure Disk) | AZ-bound, node reattach required | 1-5ms | Availability zone | Cloud-managed |
| Local NVMe (hostPath / local-path) | Not supported | Under 100µs | Node-pinned | No independent scaling |
Table 1: Storage model comparison for KubeVirt production deployments.
For production KubeVirt deployments, the critical decision point is whether live migration speed and storage latency justify the infrastructure overhead of dedicated storage nodes. For clusters running business-critical VMs, databases inside VMs, or VMs that must survive node drains without downtime, disaggregated NVMe/TCP resolves the topology constraint that hyperconverged storage cannot address.
For background on how simplyblock compares to other VM approaches on Kubernetes, see the KubeVirt vs VMware and KubeVirt vs Proxmox posts. For backup and restore workflows once your storage layer is in place, see backup and restore for KubeVirt VM workloads on Kubernetes.
Questions and Answers
What persistent storage does KubeVirt use for VM disks?
KubeVirt backs each VM disk with a DataVolume, provisioned as a standard Kubernetes persistent volume claim (PVC). The Containerized Data Importer (CDI) manages importing disk images into those volumes from container registries, URLs, or existing PVCs. Any CSI driver referenced by the StorageClass can provision the underlying volume: cloud block storage, a distributed storage system, or a disaggregated NVMe/TCP pool such as simplyblock.
Why does live migration fail or become slow with some storage backends?
VM live migration in KubeVirt copies the guest memory state from the source node to the destination node. With disaggregated storage, the VM disk is already accessible from any node via the network, so the migration only needs to copy memory. With hyperconverged storage, the disk’s data only exists on a subset of cluster nodes. If the destination is not one of those replica holders, the migration must either wait for data to sync to the destination or serve all block I/O remotely across additional network hops after migration completes. Disaggregated storage removes this constraint entirely.
Does KubeVirt live migration require ReadWriteMany storage?
For block-mode VM disks, yes. Live migration of block-mode KubeVirt VMs requires the CSI driver to support ReadWriteMany so that both the source and destination nodes can access the block volume simultaneously during the migration window. File-mode volumes also require ReadWriteMany for the same reason. The simplyblock CSI driver supports ReadWriteMany for block volumes, so live migration works without additional configuration.
How does simplyblock handle storage HA for KubeVirt VMs?
Simplyblock provides multi-replica durability at the storage layer. Each NVMe/TCP volume has configurable replication across dedicated storage nodes. If a storage node fails, the volume remains accessible from the surviving replicas with no I/O interruption to the running VM. If a compute node fails, the VM can restart on another node and immediately reattach the same volume over NVMe/TCP without any recovery step at the storage layer. This differs from hyperconverged storage, where losing a compute node also loses one replica of the data stored on that node.
What IOPS and throughput should I expect for KubeVirt VMs on NVMe/TCP?
For general-purpose VM workloads (OS boot, application reads and writes, database I/O), NVMe/TCP delivers 100 to 400 microsecond block-level latency on a 25 GbE link. For I/O-intensive workloads such as databases running inside VMs, simplyblock volumes support high queue depths and deliver NVMe-class throughput over the network, well above what cloud block storage provides at the same cost tier. For specific throughput and IOPS numbers relevant to your workload profile, use the comparison table above as a starting point and validate with fio benchmarks against your actual VM workload mix before production sizing.