---
title: "Save the Address, Save the Cloud: A Hands-on KubeVirt Live Migration Workshop"
source: "https://www.tigera.io/blog/save-the-address-save-the-cloud-a-hands-on-kubevirt-live-migration-workshop/"
---

[Technical Blog](https://www.tigera.io/category/technical-blog/)

# Save the Address, Save the Cloud: A Hands-on KubeVirt Live Migration Workshop

By [Reza Ramezanpour](https://www.tigera.io/blog/author/rezar/) on Jul 09, 2026 • 6 min read

In the [previous post in this series](https://www.tigera.io/blog/save-the-address-save-the-cloud-kubevirt-vm-migration-story/), we covered why Virtual Machine (VM) Live Migration in Kubernetes is difficult: a VM’s IP is its identity, and the “new” VM on the destination node has to come up with the same IP, this something that Kubernetes is not known for, and on top of that, traffic has to switch over only after network security policies are in place. Calico v3.32.0 delivers all the above and allows you to Live Migrate a VM without any network disruptions and this post is a short, do-it-yourself workshop to achieve it.

In about 5 minutes you’ll bring up a 3-node cluster, install Calico + KubeVirt, run a VM, and migrate it live.

## Requirements

- A Linux or a Windows Machine preferably WSL2 (**Mac Is not supported by KubeVirt**)

- Docker or Podman with at least 8 GB RAM

- [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl)

- [KIND (v0.31.0)](https://kind.sigs.k8s.io/docs/user/quick-start/#installation)

- [virtctl (v1.8.2)](https://kubevirt.io/user-guide/user_workloads/virtctl_client_tool/)

**Note:** In many Linux distros the default for most kernel parameters are too low, for a kind cluster running [KubeVirt](https://www.tigera.io/learn/guides/kubevirt/). Use the following command to temporarily increase these limits.

```
`sudo sysctl -w fs.inotify.max_user_instances=2048 sudo sysctl -w fs.inotify.max_user_watches=1048576`
```

If you face any challenges during the [KubeVirt live migration](https://www.tigera.io/learn/guides/kubevirt/kubevirt-live-migration/), make sure to drop by [our Slack](http://slack.projectcalico.org) to ask your questions.

## Create a multi-node cluster

By default KIND is shipped with a simple default CNI, use the following command to disable the default CNI and create the demo cluster:

```
`kind create cluster --config -<<EOF kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 name: calico-lab nodes: - role: control-plane - role: worker - role: worker networking: disableDefaultCNI: true podSubnet: 192.168.0.0/16 EOF`
```

## Install Calico

Live local [VM migration](https://www.tigera.io/learn/guides/vmware-migration/) is part of Calico v3.32.0 release and it’s important that you install or upgrade to this specific version. If you are already running Calico Unified Platform in your environment skip this part and go directly to the “Version and feature verifications” step there you can check your version of Calico.

Use the following command to install Tigera Operator:

```
`kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.0/manifests/tigera-operator.yaml`
```

Wait for the rollout to complete:

```
`kubectl -n tigera-operator rollout status deploy/tigera-operator --timeout=2m`
```

Next, create the installation resource:

```
`kubectl create -f - <<'EOF' apiVersion: operator.tigera.io/v1 kind: Installation metadata: name: default spec: kubeletVolumePluginPath: None calicoNetwork: bgp: Enabled ipPools: - blockSize: 26 cidr: 192.168.0.0/16 encapsulation: IPIP natOutgoing: Enabled nodeSelector: all() --- apiVersion: operator.tigera.io/v1 kind: APIServer metadata: name: default EOF`
```

Wait for Calico installation to finish, you can verify that by running the following command:

```
`kubectl wait --for=condition=Available tigerastatus/calico --timeout=2m`
```

## Install KubeVirt

To extend Kubernetes to manage stateful virtual machines just like ordinary containers, you first need to install KubeVirt, which acts as the crucial abstraction layer between your cluster and the underlying QEMU emulator.

Use the following command to install KubeVirt

```
`kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/v1.8.2/kubevirt-operator.yaml kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/v1.8.2/kubevirt-cr.yaml`
```

Use the following command

```
`kubectl -n kubevirt rollout status deploy/virt-operator --timeout=5m`
```

## Preparing KubeVirt

To prepare the cluster for live migration, we must first configure KubeVirt to enable bridge networking on the pod network. This is the only networking mode that allows Calico to successfully persist a VM’s IP address across nodes. The permitBridgeInterfaceOnPodNetwork flag is a cluster-wide configuration in KubeVirt that determines whether a Virtual Machine (VM) can utilize the bridge interface type for its default pod network. While this is often set to true by default, cluster administrators sometimes disable it (set it to false) for security or architectural reasons.

```
`kubectl -n kubevirt patch kubevirt kubevirt --type=merge -p '{ "spec": {"configuration": { "developerConfiguration": {"useEmulation": true,"clusterProfiler": true}, "network": {"defaultNetworkInterface": "bridge", "permitBridgeInterfaceOnPodNetwork": true} }}}'`
```

After configuration is in place KubeVirt will spawn handler and API pods, this can take some time depending on your machine.

Use the following command to make sure KubeVirt deployment is complete:

```
`kubectl -n kubevirt wait --for=condition=Available kubevirt/kubevirt --timeout=10m`
```

## Create a VM

Two things make this VM migratable: `bridge: {}` networking, and the `allow-pod-bridge-network-live-migration` annotation (KubeVirt blocks bridge-mode migration without it).

Use the following command to create a VM:

```
`kubectl create -f https://raw.githubusercontent.com/frozenprocess/kubevirt-migration-observer/main/examples/vm.yaml`
```

## Live VM Migration

[Live VM migration](https://www.tigera.io/learn/guides/vmware-migration/vmware-live-migration/) is a marathon relay, there are multiple KubeVirt and Calico components that work together in order to make this migration happen and the beauty of this integration is that all the complexity is hidden behind a single command `virtctl migrate`. While Calico Unified Platform is heavily involved in the security and networking side of a VM migration process, KubeVirt handles the compute lifecycle, specifically racing the guest’s memory across the wire and cutting the CPU over to the new node.

To better understand this dance let’s use the KubeVirt [observer app](https://github.com/frozenprocess/kubevirt-migration-observer/tree/main), this app will gather all the information regarding your cluster during the migration and organize it in a searchable way.

Use the following command to deploy the observer app inside the cluster:

```
`kubectl create -f https://raw.githubusercontent.com/frozenprocess/kubevirt-migration-observer/main/examples/observer-job.yaml`
```

After observer is running

```
`virtctl migrate demo-vm`
```

## Gathering The Report

To make sure that the report is generated use the following command to take a peak at the observer status:

```
`kubectl logs -l job-name=kubevirt-migration-observer`
```

The expected result should be the following:

report written:

```
`report written: markdown: /work/reports/demo-vm-20260604T232645Z.md json : /work/reports/demo-vm-20260604T232645Z.json html : /work/reports/demo-vm-20260604T232645Z.html audit : /work/reports/demo-vm-20260604T232645Z-audit/audit.md [observer] report written to /work/reports; holding 3600s for kubectl cp`
```

Use the following command to copy the report to your workstation:

```
`pod=$(kubectl -n default get pod -l app=kubevirt-migration-observer -o name) kubectl -n default cp "${pod#pod/}:/work/reports" ./reports`
```

 

Now head over to the reports folder on your local machine where you executed the command and examine the report.

**Note:** observer app also has the ability to collect performance logs, and flamegraphs. If you are interested in running a full VM migration profile checkout the full tutorial [here](https://github.com/frozenprocess/kubevirt-migration-observer).

The following table compares two independent migration reports:

**data plane Configuration**
**Cutover VM Downtime (Via a TCP Probe)**
**Total Migration Time**

BGP + IP-in-IP
0s (None observed)
1m 13.7s

VXLAN + BGP
1s
1m 44.5s

## Clean up

Run the following command to delete the demo environment:

```
`kind delete clusters calico-lab`
```

## Conclusion

Three resources do all the heavy lifting: the `kubeVirtVMAddressPersistence` setting on Calico’s IPAM config, the `allow-pod-bridge-network-live-migration` annotation on the VM, and bridge-mode networking so the VM uses the pod IP directly. Get those right and a stateful VM moves between machines with its TCP connections open and its identity intact. The observer just makes the proof visible.

[Try Calico VM migration in your browser](https://calico-vm-demo-ui.calico-labs.com/)

[VM Migration](https://www.tigera.io/tags/vm-migration/)[How-To](https://www.tigera.io/tags/how-to/)

## Related posts

[![You’ve Been Running a Kubernetes Security Model in NSX and Didn’t Even Know It](https://www.tigera.io/app/uploads/2026/08/Youve-Been-Running-a-Kubernetes-Security-Model-in-NSX-and-Didnt-Even-Know-It.png)](https://www.tigera.io/blog/youve-been-running-a-kubernetes-security-model-in-nsx-and-didnt-even-know-it/)

#### [You’ve Been Running a Kubernetes Security Model in NSX and Didn’t Even Know It](https://www.tigera.io/blog/youve-been-running-a-kubernetes-security-model-in-nsx-and-didnt-even-know-it/)

By [Veronika Smolik](https://www.tigera.io/blog/author/veronika-smolik/)
on Aug 10, 2026

One of the blockers to moving VMs off vSphere and onto Kubernetes is losing NSX and the protection it provides. Security teams that have spent years building out distributed firewall policy look at Kubernetes and...

[Read more](https://www.tigera.io/blog/youve-been-running-a-kubernetes-security-model-in-nsx-and-didnt-even-know-it/)

[![VM Migration – What Happens to Your NSX Segments in Kubernetes?](https://www.tigera.io/app/uploads/2026/08/VM-Migration-What-Happens-to-Your-NSX-Segments-in-Kubernetes.png)](https://www.tigera.io/blog/vm-migration-what-happens-to-your-nsx-segments-in-kubernetes/)

#### [VM Migration – What Happens to Your NSX Segments in Kubernetes?](https://www.tigera.io/blog/vm-migration-what-happens-to-your-nsx-segments-in-kubernetes/)

By [Veronika Smolik](https://www.tigera.io/blog/author/veronika-smolik/)
on Aug 5, 2026

Planning a migration off NSX usually starts with a networking conversation. Segments, VLANs, routing topology and BGP peering are not things that map cleanly to Kubernetes-native constructs the way the NSX distributed firewall maps to...

[Read more](https://www.tigera.io/blog/vm-migration-what-happens-to-your-nsx-segments-in-kubernetes/)

[![Bring Your Own VLAN: Moving VMs to Kubernetes Without Changing a Single IP](https://www.tigera.io/app/uploads/2026/07/Bring-Your-Own-VLAN-Moving-VMs-to-Kubernetes-Without-Changing-a-Single-IP.png)](https://www.tigera.io/blog/bring-your-own-vlan-moving-vms-to-kubernetes-without-changing-a-single-ip/)

#### [Bring Your Own VLAN: Moving VMs to Kubernetes Without Changing a Single IP](https://www.tigera.io/blog/bring-your-own-vlan-moving-vms-to-kubernetes-without-changing-a-single-ip/)

By [Veronika Smolik](https://www.tigera.io/blog/author/veronika-smolik/)
on Jul 28, 2026

For many organizations, modernizing their VMs before migrating them is not a realistic option, especially when external events trigger the migration. Mapping dependencies and refactoring network configurations before the deadline is impractical, forcing VMs to...

[Read more](https://www.tigera.io/blog/bring-your-own-vlan-moving-vms-to-kubernetes-without-changing-a-single-ip/)

<!-- plugin=object-cache-pro client=phpredis metric#hits=3371 metric#misses=35 metric#hit-ratio=99.0 metric#bytes=1476258 metric#prefetches=158 metric#store-reads=47 metric#store-writes=11 metric#store-hits=166 metric#store-misses=24 metric#sql-queries=28 metric#ms-total=571.00 metric#ms-cache=19.11 metric#ms-cache-avg=0.3353 metric#ms-cache-ratio=3.4 sample#redis-hits=33213328 sample#redis-misses=9269210 sample#redis-hit-ratio=78.2 sample#redis-ops-per-sec=32 sample#redis-evicted-keys=0 sample#redis-used-memory=135486272 sample#redis-used-memory-rss=105799680 sample#redis-memory-fragmentation-ratio=0.8 sample#redis-connected-clients=1 sample#redis-tracking-clients=0 sample#redis-rejected-connections=0 sample#redis-keys=116809 -->
