Kubermatic branding element

What Is KubeVirt, and How Does It Fit Into Kubermatic Virtualization?

KubeVirt and Kubermatic Virtualization

Kubernetes and the VM problem

Cloud-native teams spent the last decade getting good at containers. Kubernetes became the default place to run containerized workloads, and almost every new service now ships as a container image.

The catch is that most organizations still run a lot of virtual machines. Some of those VMs host applications that cannot be containerized without a rewrite. Others host databases, appliances, or operating-system-coupled workloads that are perfectly fine as VMs and would gain nothing from a container migration. For years, that split meant running two infrastructure stacks. A hypervisor platform such as VMware vSphere, OpenStack, or Proxmox for the VMs, and Kubernetes for the containers. Two control planes, two backup strategies, two skill sets, and two upgrade cycles.

For teams running on their own bare-metal hardware, the split is even worse. They end up installing a hypervisor on bare metal, then creating VMs on the hypervisor, then running Kubernetes inside those VMs. That’s a lot of layers to manage a container.

What KubeVirt is

KubeVirt is a Kubernetes add-on that lets you run full virtual machines as native Kubernetes objects. A VM becomes a resource you can kubectl apply, watch, scale, label, and govern with the same tools you already use for Pods and Deployments.

The project was started by Red Hat, with its first tagged release v0.1.0 in December 2017. It joined the CNCF as a Sandbox project in September 2019 and was promoted to Incubating in April 2022. It is one of the most active projects in the CNCF landscape today.

Under the hood, KubeVirt runs each VM inside a special Pod called the virt-launcher. The virt-launcher runs qemu-kvm and uses libvirt to manage the guest. Because the VM is wrapped in a Pod, it inherits almost everything Kubernetes gives Pods for free. It is scheduled by the Kubernetes scheduler, its lifecycle is reconciled by a controller, it has a Service and a label selector story, and NetworkPolicies that target its labels apply directly to the guest’s traffic.

KubeVirt’s core resources are VirtualMachine (the long-lived, declarative VM), VirtualMachineInstance (the running instance, analogous to a Pod), and VirtualMachineInstanceMigration (a one-shot live migration request). The upstream architecture guide describes a VirtualMachine as behaving “similarly to a StatefulSet with spec.replica set to 1”, which is the right mental model.

Why Kubermatic built on KubeVirt

At Kubermatic we have been working with KubeVirt for years. The first product of that work was a KubeVirt cloud provider inside Kubermatic Kubernetes Platform, shipped in KKP 2.22. That integration let operators provision user clusters on top of VMs that KKP created through KubeVirt on a shared infrastructure cluster. It proved the model.

The more interesting question was what happens when you lean into KubeVirt all the way. Instead of using it as one cloud provider among many inside a Kubernetes management platform, what if the entire private cloud is built from Kubernetes primitives?

That’s what Kubermatic Virtualization is. It hit GA on November 27, 2025, after three years of engineering, and reached 1.1 in April 2026 with a self-service web UI, a declarative installer, and built-in authentication. The design goal was to remove the hypervisor middle layer from the bare-metal-to-container path. Install Kubernetes directly on bare metal, treat VMs as native Kubernetes objects, and run your tenant Kubernetes clusters inside those VMs, all from a single control plane.

How Kubermatic Virtualization fits together

Kubermatic Virtualization is not a single binary. It is a stack of well-known open-source components coordinated by a small set of Kubermatic-built controllers, a production-ready web UI, and a dedicated installer.

The pieces that do the heavy lifting:

  • KubeOne provisions and upgrades the bare-metal Kubernetes cluster that hosts everything else. This is the Infrastructure Cluster.
  • Upstream KubeVirt runs the VM workloads on that Infrastructure Cluster.
  • Kube-OVN provides the software-defined network. It is a CNCF Sandbox project that brings OVN and OVS to Kubernetes, with VPCs, subnets, NAT gateways, Elastic IPs, and routing tables expressed as CRDs.
  • KubeOne again provisions tenant Kubernetes clusters inside the KubeVirt VMs when teams ask for them.
  • Kubermatic’s Virtualization control plane wraps everything in a tenant/workspace model. The 1.1 release adds a production-ready web UI for end-to-end VM, networking, and storage management, and a kubermatic-virtualization apply installer that supports both an interactive wizard and declarative GitOps-style YAML, with self-healing on subsequent runs.

The whole stack is also air-gap ready: every component ships as an OCI artifact, and the installer handles offline image mirroring out of the box. Everything below is standard Kubernetes, so if you already know how to operate a Kubernetes cluster, you already know most of how to operate this one.

VirtualMachines and DataVolumes

A VirtualMachine in KubeVirt is the declarative spec for a long-running VM. You set the desired CPU, memory, disks, network interfaces, and cloud-init data, and KubeVirt makes sure a matching VirtualMachineInstance exists.

Disks are the interesting part. Instead of manually importing an image into your storage, you point at an image source and let the Containerized Data Importer (CDI) handle the download, format conversion, and PVC provisioning. CDI accepts HTTP/HTTPS URLs, container registries, upload via virtctl, existing PVC clones, VolumeSnapshot objects, and a few others.

Here is a minimal VirtualMachine that boots an Ubuntu Jammy cloud image and installs nginx through cloud-init:

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: ubuntu-web-server
  labels:
    app: web
    env: production
spec:
  runStrategy: Always
  dataVolumeTemplates:
  - metadata:
      name: ubuntu-web-server-rootdisk
    spec:
      source:
        http:
          url: https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
      storage:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 20Gi
  template:
    metadata:
      labels:
        app: web
        kubevirt.io/vm: ubuntu-web-server
    spec:
      domain:
        cpu:
          cores: 2
        resources:
          requests:
            memory: 4Gi
        devices:
          disks:
          - name: rootdisk
            disk:
              bus: virtio
            bootOrder: 1
          - name: cloudinitdisk
            disk:
              bus: virtio
          interfaces:
          - name: default
            masquerade: {}
      terminationGracePeriodSeconds: 180
      networks:
      - name: default
        pod: {}
      volumes:
      - name: rootdisk
        dataVolume:
          name: ubuntu-web-server-rootdisk
      - name: cloudinitdisk
        cloudInitNoCloud:
          userData: |
            #cloud-config
            hostname: ubuntu-web-server
            ssh_authorized_keys:
            - ssh-rsa AAAA...your-public-key
            packages:
            - nginx
            - qemu-guest-agent
            runcmd:
            - systemctl enable --now nginx
            - systemctl enable --now qemu-guest-agent

The root disk is ReadWriteOnce because this VM is a single instance. If you want the VM to be live-migratable, you will need the root disk on a StorageClass that supports ReadWriteMany. More on that in the next section.

Applying it and watching it come up

Save the YAML above as ubuntu-web-server.yaml, substitute a real SSH public key under ssh_authorized_keys, and apply it into any namespace:

kubectl create namespace kubevirt-demo
kubectl -n kubevirt-demo apply -f ubuntu-web-server.yaml
kubectl -n kubevirt-demo get vm,vmi,dv,pvc -w

The first time you run this, CDI pulls and converts the Ubuntu cloud image (~600 MB), so you will see the resources transition through a sequence of states:

datavolume.cdi.kubevirt.io/ubuntu-web-server-rootdisk   WaitForFirstConsumer    N/A
datavolume.cdi.kubevirt.io/ubuntu-web-server-rootdisk   ImportInProgress        48.20%
datavolume.cdi.kubevirt.io/ubuntu-web-server-rootdisk   Succeeded               100.0%

virtualmachineinstance.kubevirt.io/ubuntu-web-server   Running   10.244.5.233   node-07
virtualmachine.kubevirt.io/ubuntu-web-server           Running   True

On a small lab cluster this typically completes in two to three minutes. The PVC is named ubuntu-web-server-rootdisk — taken literally from dataVolumeTemplates[].metadata.name with no VM-name prefix, which matters when you write RBAC or admission policies that match PVCs by pattern.

Once the VMI is Running, virtctl gives you an SSH entry point without exposing a Service:

virtctl -n kubevirt-demo ssh ubuntu@vm/ubuntu-web-server -i ~/.ssh/id_rsa

From inside the VM, nginx is serving and the qemu-guest-agent is reporting back to KubeVirt:

$ systemctl is-active nginx qemu-guest-agent
active
active

$ curl -sI http://127.0.0.1/ | head -2
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)

One cloud-init gotcha worth flagging: on Ubuntu cloud images, a group named admin already exists, so a #cloud-config that uses the top-level shortcut user: admin fails at useradd with “group admin exists” and then silently skips the ssh_authorized_keys step. Stick with the built-in ubuntu default user (as above), or declare a full users: list with primary_group and groups set explicitly.

High availability, live migration, and maintenance

Kubermatic Virtualization uses two different mechanisms for two different failure modes.

Unplanned node loss is handled by reconciliation. If a bare-metal host dies, its VirtualMachineInstance becomes unavailable. The VM controller notices and creates a fresh VirtualMachineInstance on another suitable node, reattaching the existing PersistentVolumeClaims. The VM is restarted, not migrated, but recovery is automatic and uses only standard Kubernetes scheduling and storage primitives. This is infrastructure-level high availability without bolting on a separate clustering stack.

Planned maintenance is handled by live migration. KubeVirt supports three migration strategies:

  • Pre-copy is the default. Memory pages are copied to the target while the VM keeps running on the source, then execution switches over when state converges. Guests see no downtime.
  • Post-copy flips the model. The VM starts immediately on the target and pulls memory pages on demand. It’s useful for memory-heavy workloads where pre-copy struggles to converge, but you opt in with allowPostCopy: true.
  • Auto-converge throttles the guest CPU to help pre-copy finish. Also opt-in, via allowAutoConverge: true.

All migration traffic is TLS-encrypted by default. Live migration requires shared storage with ReadWriteMany access mode on the VM’s PersistentVolumeClaims.

When a bare-metal host is cordoned for maintenance, the Virtualization controllers evaluate each VM on that host. If the VM has compatible storage and a target node with enough capacity, live migration runs before the node is drained. If it can’t, the system falls back to a safe restart on another node. Tenant Kubernetes clusters running inside those VMs stay available through the whole operation.

Scale with VirtualMachinePools

For workloads that need identical VMs in bulk, such as a fleet of web servers or build agents, KubeVirt offers VirtualMachinePool. It plays the same role for VMs that a Deployment plays for Pods: you declare a template and a replica count, and the pool keeps that many VirtualMachine objects running. Each VM gets its own PVC through the DataVolumeTemplates mechanism, with the pool’s sequential suffix appended to the template name, so there is no shared-disk collision.

Networking with Kube-OVN

Kubermatic Virtualization uses Kube-OVN as its SDN. Kube-OVN integrates OVN (Open Virtual Network) and OVS (Open vSwitch) with Kubernetes, and it’s a CNCF Sandbox project that matches the feature surface of commercial SDNs like NSX, entirely in open source.

Tenancy at the network layer is expressed through Kube-OVN’s VPC resource. Each tenant workspace can be assigned its own VPC with isolated subnets, routing tables, NAT gateways, and Elastic IPs, all declared as CRDs. Inside a VPC, VMs behave like any other workload. They can talk to each other, to Services, and to the outside world according to the routing you define.

Because KubeVirt VMs run inside Pods, standard Kubernetes NetworkPolicies apply to them directly. KubeVirt propagates the VirtualMachineInstance’s labels down to its virt-launcher Pod, and that label propagation is what makes a podSelector-based policy match a VM exactly the way it would match a Pod. Teams reuse the same policy tooling they already run for containers, and microsegmentation rules work uniformly across VMs and Pods. For workloads that need low-latency networking, the platform supports SR-IOV for direct hardware access.

RBAC and multi-tenancy

Because VMs are native Kubernetes objects, KubeVirt gets Kubernetes RBAC for free. Upstream ships three default ClusterRoles, documented in the authorization guide:

  • kubevirt.io:view grants read-only access to VM resources.
  • kubevirt.io:edit allows creating, modifying, and accessing VMs, including console and VNC.
  • kubevirt.io:admin adds runtime configuration control.

These are bound at the namespace level via RoleBinding for tenant-scoped access, or cluster-wide via ClusterRoleBinding for operators. Custom roles let you narrow permissions further, for example allowing a user to create VMs but not attach GPUs or trigger live migration.

Above the RBAC layer, Kubermatic Virtualization 1.1 ships built-in authentication with three modes: No Auth, Basic Auth, and OIDC/SSO, with an optional in-cluster Dex deployment for enterprise-grade login without an external identity provider. Once a user is authenticated, the same Kubernetes RBAC binds them to whatever scope the operator has defined.

The platform also installs a default set of Kyverno policies that enforce common VM security best practices, so tenants inherit a baseline policy posture without operator intervention.

Combined with Kube-OVN’s VPC-level isolation and standard Kubernetes ResourceQuota, this gives each tenant a namespace with its own network boundary, identity layer, RBAC policies, baseline security policies, and resource limits, all enforced through primitives your operators already understand.

GPU support

Kubermatic Virtualization exposes GPUs to VMs through two mechanisms, both declared under spec.domain.devices.gpus on the VM spec and documented in the host-devices guide.

PCI passthrough dedicates a whole physical GPU to one VM using the VFIO framework. The host releases the GPU from its native driver, binds it to vfio-pci, and passes it into the guest. Performance is near-native. This requires IOMMU support (Intel VT-d or AMD-Vi) enabled in firmware, and is the right choice for workloads that want a full GPU, such as ML training or scientific simulation.

Mediated devices (vGPU) split a physical GPU across multiple VMs using the Linux mdev framework. The cluster admin declares the allowed mediated-device types in the KubeVirt CR, the vendor driver on the host creates the mdev instances, and VMs request them like any other device. NVIDIA vGPU requires NVIDIA’s driver on the host, and other vendors have equivalent driver requirements. This is the right choice for inference, remote desktops, and visualization, where full-GPU dedication is wasteful.

In both cases, GPU-bearing nodes are labeled, and the Kubernetes scheduler places VMs that request GPUs on nodes that can satisfy the request.

One platform, one control plane

With Kubermatic Virtualization the boundary between container management and VM management stops being a meaningful line in your architecture. You run both on the same Kubernetes, govern both with the same APIs, and observe both through the same pipeline. Tenant Kubernetes clusters come up inside VMs that your operators never had to provision manually. Day-two operations, from live migration to backups to RBAC, all live in one control plane.

For what’s new in the latest release, see Meet Kubermatic Virtualization 1.1. If you want to see it in action, book a demo or browse the documentation.

Abubakar Siddiq Ango

Abubakar Siddiq Ango

Senior Developer Advocate

Kubermatic named in the 2025 Gartner® Magic Quadrant™ for Container Management

Access the Report