Whitepaper: Trilio Site Recovery (TSR) — DR for Kubernetes-native VMs

Moving from a traditional hypervisor to a cloud-native platform is not just a migration—the way that VMs are defined, scheduled, and managed changes completely. On a traditional hypervisor, VMs run on dedicated infrastructure managed through a separate control plane. On a cloud-native platform, they run as Kubernetes workloads alongside containers, using the same networking, storage, and access control model.  That shift brings real operational benefits. It also brings a learning curve. Practices that worked well on vSphere or Hyper-V do not map cleanly onto Kubernetes primitives. This applies to resource sizing, backup strategy, placement rules, and more. This article explains what cloud-native virtualization is, how it differs from what most teams are used to, and what the practices are that keep the transition working in production.

Summary of cloud-native virtualization best practices

Best practice Description
Understand what cloud-native virtualization is and how it differs from traditional hypervisors KubeVirt runs VMs as Kubernetes workloads through pod-like VM objects, replacing hypervisor-managed infrastructure. The operational model, storage layer, networking, and lifecycle management all change with the switch.
Treat VMs and containers as first-class citizens on one platform VMs and containers share the same cluster, network model, and RBAC policies. Managing them with separate toolchains creates inconsistency and overhead.
Right-size VM resources with Kubernetes-native tooling VMs are defined with resource requests and limits like any other workload. Rightsizing tools that work on containers apply to VMs too.
Apply consistent labeling and namespace boundaries Namespaces and labels are the primary organizational units for both workload types. Carrying over hypervisor-era folder structures loses policy and access control benefits.
Use a Kubernetes-native backup tool that covers both workload types Hypervisor backup tools cannot see inside the Kubernetes layer. A Kubernetes-native tool like Trilio protects VMs and containers under one application-aware policy.
Schedule and place VMs using Kubernetes node constraints DRS rules and host affinity have no direct equivalent. Placement is controlled by node selectors, taints, tolerations, and topology-spread constraints.

Automated Application-Centric Red Hat OpenShift Data Protection & Intelligent Recovery

Understand what cloud-native virtualization is and how it differs from traditional hypervisors

Cloud-native virtualization runs virtual machines as Kubernetes workloads. KubeVirt is the project that makes this possible. It extends Kubernetes to run VMs alongside containers, representing each VM as a custom resource called a VirtualMachine, managed by the Kubernetes control plane.

The VM’s compute, storage, and networking are expressed as Kubernetes objects rather than hypervisor constructs. That makes each VM schedulable, observable, and manageable with standard Kubernetes tooling. A VM becomes something kubectl can describe, the scheduler can place, and Prometheus can scrape.

The traditional approach

Traditional hypervisors manage VMs through dedicated control planes with proprietary APIs. VMware vSphere has vCenter. Hyper-V has its own management layer. Each runs separately from any container orchestration. On a cloud-native platform, there is no separate hypervisor control plane. The Kubernetes API server manages VMs and containers through the same interface. The same kubectl get command lists both, and the same RBAC rules govern access to both.

The shared platform model

VMs and containers run on the same nodes. They share the same CNI-based network layer. They use the same CSI storage drivers for persistent volumes. The hard boundary between VM and container infrastructure disappears.

That consolidation is the main draw. It also forces a rethink of every operational layer, from network policy to backup strategy. A practice that assumed two separate stacks no longer fits one shared stack.

Automated Red Hat OpenShift Data Protection & Intelligent Recovery

Perform secure application-centric backups of containers, VMs, helm & operators

Use pre-staged snapshots to instantly test, transform, and restore during recovery

Scale with fully automated policy-driven backup-and-restore workflows

What changes when you make the switch

VM lifecycle operations move to new tools. Start, stop, migrate, and snapshot no longer run through vCenter or Hyper-V Manager; they run through kubectl, virtctl, or a Kubernetes-native console.

Existing runbooks, backup schedules, monitoring dashboards, and access control models were built around the hypervisor layer. Each one needs to be rebuilt around Kubernetes primitives. The rest of this article walks through where that rebuild matters most.

Treat VMs and containers as first-class citizens on one platform

The biggest mistake teams make after migration is running VMs as a separate island inside the cluster. The platform consolidates VMs and containers; the operational model should follow.

Apply the same RBAC roles, network policies, and resource quotas to VM namespaces that you apply to container workloads. A separate access model for VMs recreates the silo you just removed. If a developer can read pod logs in a namespace, the rules for reading VM state in that namespace should follow the same pattern.

Use one observability stack for both. KubeVirt exposes VM metrics through the standard Kubernetes metrics pipeline, so Prometheus and Grafana can monitor VMs and containers together. Two separate monitoring systems mean two places to look during an incident and two sets of dashboards to keep current.

Avoid managing VMs through a separate UI when the same operation is available through Kubernetes-native tooling. Diverging toolchains are where operational inconsistency takes root. A VM started through one tool and a pod started through another drift apart in how they are labeled, monitored, and backed up.

Right-size VM resources with Kubernetes-native tooling

On a hypervisor, you size a VM by picking a tier, e.g. two vCPUs and 8 GB of memory, often chosen from a “T-shirt-sizing” menu. That number tended to stick for the life of the VM, whether or not the workload used it.

On Kubernetes, a VM is sized the way every other workload is sized. You define CPU and memory as resource requests and limits in the VirtualMachine spec:

				
					apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: app-vm
spec:
  template:
    spec:
      domain:
        resources:
          requests:
            cpu: "2"
            memory: 4Gi
          limits:
            cpu: "4"
            memory: 8Gi
				
			

This means the same rightsizing tools you use for containers apply to VMs. The Vertical Pod Autoscaler can produce recommendations. Dedicated tools such as Kubecost or Kubex surface over-provisioned VMs against actual utilization, the same way they do for container workloads.

Do not carry forward hypervisor-era VM sizes without checking them. A VM that ran fine on four vCPUs in vSphere may behave differently on Kubernetes, where it shares nodes with other workloads under different scheduling pressure. Review real utilization data after migration before you lock in a size.

Apply consistent labeling and namespace boundaries across all workloads

Namespaces and labels are how Kubernetes organizes everything. For VMs, they replace the folders, clusters, and resource pools that vCenter used. Getting this structure right shapes how policy, access control, and observability work for the rest of the platform’s life.

Assign VMs to namespaces that reflect team ownership or application boundaries, not infrastructure zones. This mirrors how container workloads are organized and keeps policy consistent across both. A namespace per team or per application is far more useful than a namespace that maps to a rack or a storage array.

Use one label schema across VMs and containers. Common keys such as environment, team, and application tier let network policies, backup plans, and monitoring selectors work uniformly across workload types:

				
					metadata:
  labels:
    environment: production
    team: payments
    app-tier: database
    backup-tier: standard
				
			

Define namespace-level resource quotas that account for both VMs and containers sharing the same pool. VM resource requests are large relative to most pods. Left unmanaged, a handful of VMs can exhaust node capacity quietly, and the first signal you get is a pod that will not schedule.

Use a Kubernetes-native backup tool that covers both workload types

Backup is the practice that breaks most often after migration, because the old tools simply cannot see the new layer. Hypervisor backup agents, such as Veeam or Commvault in VM mode, have no visibility into Kubernetes resources. They do not understand the namespace structure or the application state spread across pods and VMs. When pointed at a cloud-native platform, they capture disks without the Kubernetes context, which makes a restore work.

Generic Kubernetes backup tools have the opposite problem. Velero protects Kubernetes resources well, but it predates KubeVirt and treats VM disks as generic PersistentVolumeClaims. It snapshots the volume without application-consistency hooks built for VM workloads. The backup completes, but a database inside that VM may restore to an inconsistent state.

A Kubernetes-native, application-aware tool closes both gaps. Trilio protects VMs and containers under a single BackupPlan, using application-aware hooks for consistency and a consistent recovery model across both workload types, as shown in this code example.

				
					apiVersion: triliovault.trilio.io/v1
kind: BackupPlan
metadata:
  name: mixed-workload-plan
spec:
  backupConfig:
    target:
      name: s3-backup-target
  backupComponents:
    - type: vm
      labelSelector:
        matchLabels:
          backup-tier: standard
    - type: helm
      labelSelector:
        matchLabels:
          backup-tier: standard
				
			

Trilio supports incremental backups to keep storage and bandwidth in check across cycles. One detail worth setting expectations on is that incremental VM backup driven by KubeVirt change block tracking is on the roadmap rather than available today, so plan current schedules around the incremental support that ships now, not a CBT-based model. The practical takeaway holds regardless of vendor: Pick a tool built for the Kubernetes layer, and confirm how it handles VM consistency and incrementals before you rely on it.

Schedule and place VMs using Kubernetes node constraints

vSphere handled placement for you. DRS balanced load across hosts, and affinity rules kept certain VMs together or apart. None of that carries over directly. On Kubernetes, you describe placement intent declaratively and let the scheduler act on it.

Replace DRS rules and host affinity with node selectors and affinity rules in the VirtualMachine spec. You state which nodes a VM belongs on, and the scheduler honors it, as follows:

				
					spec:
  template:
    spec:
      nodeSelector:
        node-role: vm-workloads
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: cpu-generation
                    operator: In
                    values: ["cascade-lake"]
				
			

Use taints and tolerations to reserve nodes for VM-only or container-only workloads. This matters where hardware profiles make co-scheduling undesirable, such as nodes with specific CPU generations, large memory, or local NVMe. A taint keeps general pods off those nodes, and a matching toleration lets the right VMs land there.

Apply topology-spread constraints to distribute VMs across availability zones or rack-level failure domains. This replaces the fault-domain model that vSphere managed automatically. Without it, the scheduler may pack several copies of a workload onto one zone, and a single zone failure can take them all down at once.

Conclusion

Cloud-native virtualization changes the model, not just the location. VMs become Kubernetes objects, and the platform that runs your containers now runs your virtual machines too. The benefit is one stack, one API, and one set of policies. The cost is that nearly every hypervisor-era practice needs revisiting.

Treat VMs and containers as equal citizens, and the consolidation pays off. Size VMs against real utilization rather than inherited tiers. Let namespaces and labels carry policy across both workload types. Choose a backup tool built for the Kubernetes layer, and verify how it handles VM consistency before you depend on it. Describe placement with node constraints instead of expecting an automatic balancer.

Get these right from the start, and running VMs on Kubernetes becomes an operational gain rather than a source of surprises.

Table Of Contents

Like This Article?

Subscribe to our LinkedIn Newsletter to receive more educational content

Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.