KubeVirt Workload Update Strategy#
During a KubeVirt control plane upgrade, existing VMI workloads (virt-launcher, libvirt, qemu) are not updated by default. Opting in to automated workload updates requires configuring spec.workloadUpdateStrategy on the KubeVirt CR — available since v0.39.0.
API Structure#
KubeVirtWorkloadUpdateStrategy is embedded in KubeVirtSpec :
| Field | Type | Default | Purpose |
|---|---|---|---|
workloadUpdateMethods | []WorkloadUpdateMethod | [] (none) | Methods to use; empty list disables all automated updates |
batchEvictionSize | *int | 10 | Max VMIs evicted per interval (Evict only) |
batchEvictionInterval | *metav1.Duration | 1m | Wait between eviction batches (Evict only) |
Two WorkloadUpdateMethod constants are defined :
LiveMigrate— live-migrates the VMI into a new pod with updated components; zero downtime for the guest.Evict— issues a pod eviction. If the VMI is owned by aVirtualMachinewithrunStrategy: Always, a new VMI starts automatically; standalone VMIs shut down.
When both methods are listed, LiveMigrate takes precedence: only VMIs that cannot be live-migrated are evicted .
Example — LiveMigrate + Evict with batching:
spec:
workloadUpdateStrategy:
workloadUpdateMethods:
- LiveMigrate
- Evict
batchEvictionSize: 10
batchEvictionInterval: "1m"
(full examples in the user guide)
Controller Logic#
The WorkloadUpdateController runs inside virt-controller and is the sole actor driving workload updates.
Safety Gates#
execute() enforces two hard preconditions before any action is taken:
kv.Status.Phase == KubeVirtPhaseDeployedkv.Status.ObservedDeploymentID == kv.Status.TargetDeploymentID
Both must be true, ensuring workload updates only begin after all KubeVirt infrastructure components have fully rolled out .
Staleness Detection#
isOutdated() compares vmi.Status.LauncherContainerImageVersion against the controller's current launcherImage. VMIs still initializing or mid-migration (empty LauncherContainerImageVersion) are skipped.
Update Categorization#
getUpdateData() buckets all running VMIs into:
migratableOutdatedVMIs— outdated + live-migratable (whenLiveMigrateenabled)evictOutdatedVMIs— outdated + not live-migratable (whenEvictenabled)abortChangeVMIs— VMIs whose in-flight workload-update migration should be cancelled
VMIs already migrating are excluded from action lists to avoid duplicate operations .
Batching and Concurrency#
sync() applies two independent rate controls:
- Live migration cap: new migrations are bounded by
ParallelMigrationsPerClusterminus currently active migrations . Migration candidates are randomly shuffled to avoid repeatedly retrying stuck VMIs . - Eviction batching: evictions respect
BatchEvictionSizeandBatchEvictionInterval(defaulting to 10 / 60 s) via alastDeletionBatchtimestamp .
Each workload-update migration is annotated with WorkloadUpdateMigrationAnnotation for tracking and given PrioritySystemCritical priority unless the migration is hotplug- or volume-change-driven .
The count of pending outdated VMIs is surfaced as kv.Status.OutdatedVirtualMachineInstanceWorkloads and a Prometheus metric via SetOutdatedVirtualMachineInstanceWorkloads.
Key Source Files#
| File | Purpose |
|---|---|
staging/src/kubevirt.io/api/core/v1/types.go | WorkloadUpdateMethod constants and KubeVirtWorkloadUpdateStrategy struct |
pkg/virt-controller/watch/workload-updater/workload-updater.go | Full controller implementation |
| KubeVirt user guide — Updating and deletion | Configuration examples and upgrade paths |