kubevirt-vm-migration-platform

Virtualization fundamentals: ESXi, KVM, QEMU, libvirt, VirtIO

Stage 0 learning document. It covers request sections 1 (first principle), 2 (KVM / QEMU / libvirt) and 3 (nested virtualization).

Evidence markers used in this document:


1. First principle: three ways to run the same nginx

ESXi VM vs KubeVirt VM vs Pod

Take one concrete workload: a small Linux server that runs nginx and serves a static site from /var/www.

A. Traditional VM on ESXi

B. VM managed by Kubernetes through KubeVirt

C. Native Kubernetes application (Pods)

The key insight

A and B both run a full guest OS on virtual hardware. Only the manager changes. Moving from A to B is migration (rehosting). C removes the VM entirely. Moving from A or B to C is modernization (see modernization-model.md).

The chain from an ESXi VM to a running guest on KubeVirt

KubeVirt object chain

ESXi VM                         source: .vmx + .vmdk on VMFS; runs as a VMX process on VMkernel
  |  migration: translate metadata, convert + import disks
  v
KubeVirt VirtualMachine (VM)    persistent desired state (kubevirt.io/v1); survives stop/start
  |  virt-controller creates a VMI when spec.runStrategy says "run"
  v
VirtualMachineInstance (VMI)    one running instance; deleted when the VM stops
  |  virt-controller creates the launcher Pod; kube-scheduler places it
  v
virt-launcher Pod               normal Pod: cgroups, namespaces, pod IP, PVC mounts
  |  virt-handler (on the node) tells virt-launcher to define/start the libvirt domain
  v
QEMU process                    user-space process that emulates the machine and its devices
  |  ioctl() calls on /dev/kvm
  v
KVM                             Linux kernel module; runs guest code on the CPU using VT-x/EPT
  |
  v
guest OS                        the same Linux + nginx that ran on ESXi, now on virtio devices

Who owns which layer

Layer Owner (who creates / changes it) Comparable ESXi concept
ESXi VM (source) ESXi hostd / VMkernel; our migration platform only reads it -
VirtualMachine You (kubectl, GitOps) or our migration controller The VM object in inventory (.vmx)
VirtualMachineInstance virt-controller (owner reference to the VM) A powered-on VM
virt-launcher Pod virt-controller creates it; kube-scheduler places it; kubelet runs it The VMX “world” on a host
libvirt domain virt-handler asks virt-launcher to define it VMX configuration in memory
QEMU process libvirt inside virt-launcher VMX process + device emulation
KVM Node Linux kernel The VMM part of VMkernel
Guest OS + app Application / OS team Same

DOCUMENTED: KubeVirt architecture, KubeVirt components (kubevirt/kubevirt docs/components.md).


2. KVM, QEMU, libvirt and VirtIO

Four pieces, each solving one problem. Together they do what ESXi does as one product.

KVM (Kernel-based Virtual Machine)

QEMU

libvirt

VirtIO

How they interact (one VM on a KubeVirt node)

virt-launcher Pod
  libvirtd  --(domain XML)-->  QEMU process
                                 |- device emulation: virtio-net, virtio-blk, UEFI/BIOS, ...
                                 |- vCPU threads --(ioctl KVM_RUN)--> /dev/kvm
Node Linux kernel
  KVM module --(VT-x / EPT)--> physical CPU and RAM
  tap / bridge / nftables  <-- host side of the virtual NIC
  block device or file     <-- backing store of the virtual disk (from a PVC)

VMware to KVM/QEMU translation table

This is a conceptual mapping for learning. KVM and ESXi are not identical. ESXi is a purpose-built type-1 hypervisor OS where VMkernel does scheduling, memory management, storage and networking. KVM makes a general-purpose Linux kernel into a hypervisor, and many ESXi functions are split across Linux, QEMU, libvirt and (on Kubernetes) KubeVirt and CNI/CSI plugins.

VMware concept Closest KVM / QEMU / KubeVirt concept Important difference
ESXi (hypervisor product) Linux + KVM + QEMU + libvirt (+ KubeVirt on Kubernetes) ESXi is one integrated product. The KVM stack is assembled from parts.
VMkernel Linux kernel with the KVM module VMkernel is purpose-built. Linux is general-purpose and also runs containers.
VMM (inside VMkernel) KVM (CPU/memory virtualization in the kernel) Similar role.
VMX process (per VM) QEMU process (per VM) Both are per-VM user-space processes that emulate devices.
.vmx file libvirt domain XML; in KubeVirt the VM/VMI spec In KubeVirt the source of truth is a Kubernetes object, not a file.
VMDK Disk image: raw or qcow2 file, or a raw block device CDI converts imported disks to raw.
VMFS datastore Filesystem or block storage behind a PVC/StorageClass Kubernetes storage is per-volume (PVC), not a shared clustered filesystem.
Thin-provisioned VMDK Sparse raw file or qcow2 Sparseness can be lost if tools are used carelessly.
VM snapshot (delta VMDK chain) qcow2 backing chain; in KubeVirt VirtualMachineSnapshot via CSI snapshots Different mechanisms.
vNIC (VMXNET3, E1000) virtio-net (or e1000) exposed by QEMU Guest driver changes from vmxnet3 to virtio_net.
PVSCSI controller virtio-scsi or virtio-blk Guest driver changes.
vSwitch Linux bridge / OVS / CNI plugin inside the Pod network In KubeVirt, the VM NIC connects to the Pod’s network namespace first.
Port group Kubernetes Pod network, or a Multus NetworkAttachmentDefinition See networking-model.md.
VMware Tools QEMU guest agent (qemu-guest-agent) Reports IPs, allows graceful shutdown, freezes filesystems.
hostd / Host Client libvirtd per VM + KubeVirt virt-handler per node  
vCenter Kubernetes API + KubeVirt controllers Declarative desired state instead of imperative tasks.
vMotion KubeVirt live migration (VirtualMachineInstanceMigration) Needs shared RWX storage or storage migration, and a suitable network binding.
DRS placement kube-scheduler (requests, affinity, taints)  
HA restart runStrategy: Always / RerunOnFailure + Kubernetes rescheduling  

3. Nested virtualization in our lab and on AWS

Nested virtualization layers

L0 / L1 / L2 terminology

Our source lab (OBSERVED)

Physical laptop: Intel Core i7-14650HX, 32 GB RAM, VT-x + SLAT enabled in firmware
  |
Windows 11 Home (Windows hypervisor OFF: hypervisorlaunchtype Off)
  |
VMware Workstation Pro 17.6.4, monitor mode CPL0 (native), hv-vt.vmm + gphys-ept.vmm loaded   <- L0 hypervisor
  |
esxi-8-lab: ESXi 8.0.3 build 24677879, 8 vCPU, 16 GB, vhv.enable = TRUE, HV Support: 3       <- L1 hypervisor
  |
future legacy-source-vm (not created yet)                                                    <- L2 guest

Why the Windows hypervisor had to be off (OBSERVED in the handoff): with it running, Workstation ran on top of Hyper-V/WHP, which does not support “Virtualize Intel VT-x/EPT”. With it off, Workstation owns VT-x directly and can pass it to ESXi. The cost is that WSL2 and Docker Desktop cannot run.

Our eventual AWS target (PLANNED, nothing created)

AWS Nitro hypervisor on physical host                                    <- L0
  |
EC2 instance of a supported family, NestedVirtualization=enabled         <- L1: Linux + KVM
  |
Kubernetes node (kubelet, containerd) + KubeVirt virt-handler
  |
virt-launcher Pod -> QEMU -> /dev/kvm (KVM in the L1 kernel)
  |
target VM (the migrated legacy-source-vm)                                <- L2

DOCUMENTED (AWS: Use nested virtualization, AWS What’s New 2026-02-16):

VT-x and EPT

Why nested virtualization is required

Performance implications

Why this is a lab architecture