Skip to main content

Rob Pankow Rob Pankow

KubeVirt Persistent Storage: Architecture Guide for Production VM Workloads

Jun 15, 2026  |  10 min read

Last edited: Jul 13, 2026

KubeVirt Persistent Storage: Architecture Guide for Production VM Workloads

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:

  1. Re-sync the data to the destination node before migration can proceed. For large VM disks, this takes minutes to hours.
  2. 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.
  3. 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

Diagram showing KubeVirt VMs on Kubernetes nodes connecting to a disaggregated simplyblock NVMe/TCP storage pool, with live migration moving only memory state while disk remains on network storage
Figure 1: KubeVirt VMs backed by disaggregated NVMe/TCP storage. Live migration copies only memory state to the destination node; the VM disk remains on the storage pool and is instantly accessible from any node.

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/v1
kind: StorageClass
metadata:
name: simplyblock-nvme-vm
provisioner: csi.simplyblock.io
parameters:
pool: vm-tier
replication: "2"
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Retain

Setting 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/v1beta1
kind: DataVolume
metadata:
name: vm-disk-ubuntu-24
namespace: production-vms
spec:
source:
registry:
url: docker://quay.io/containerdisks/ubuntu:24.04
pvc:
accessModes:
- ReadWriteMany
storageClassName: simplyblock-nvme-vm
resources:
requests:
storage: 50Gi
volumeMode: Block

Using 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/v1
kind: VirtualMachine
metadata:
name: ubuntu-prod-1
namespace: production-vms
spec:
running: true
template:
spec:
domain:
devices:
disks:
- name: disk0
disk:
bus: virtio
volumes:
- name: disk0
dataVolume:
name: vm-disk-ubuntu-24

For 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 ModelLive MigrationBlock LatencyTopology ConstraintScale Model
Disaggregated NVMe/TCP (simplyblock)Instant, any node100-400µsNoneStorage and compute scale independently
Hyperconverged distributed storageRequires data sync or remote I/O1-5msData locality requiredStorage and compute scale together
NFS / shared filesystemImmediate (shared mount)2-10msNoneScale NFS servers independently
Cloud block storage (EBS, Azure Disk)AZ-bound, node reattach required1-5msAvailability zoneCloud-managed
Local NVMe (hostPath / local-path)Not supportedUnder 100µsNode-pinnedNo 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.

You may also like:

NVMe/TCP vs NVMe/RoCE for Kubernetes Storage: Choosing the Right Fabric
NVMe/TCP vs NVMe/RoCE for Kubernetes Storage: Choosing the Right Fabric

NVMe over Fabrics gives Kubernetes clusters low-latency block storage over the network. The transport you pick, TCP or RoCE, determines your latency floor, infrastructure cost, and operational complexity. Here is how to choose.

How to Benchmark Block Storage Performance: fio and Network Tuning Best Practices
How to Benchmark Block Storage Performance: fio and Network Tuning Best Practices

A practical methodology for benchmarking distributed block storage: how to configure fio, why warm-up matters, how to read mixed read/write results, and the network tuning that lets NVMe/TCP reach line rate.

We Break Our Storage So You Never Have To
We Break Our Storage So You Never Have To

Simplyblock runs 100+ hours of automated chaos engineering before every release: real NVMe hardware, real FIO workloads, four failure types injected under live load. This is what we test, why it is necessary, and what it means for your infrastructure.