Introducción
Tenés un cluster de Kubernetes con KubeVirt corriendo VMs en producción. Las workloads andan bien, el equipo gana confianza, y surge la pregunta inevitable: «¿Podemos migrar una VM en vivo a otro cluster?». Los casos de uso son claros: recovery ante desastres, actualizaciones de clusters, balanceo de capacidad. KubeVirt desde la versión 1.6 (julio 2025) soporta decentralized live migration, que en teoría debería resolverlo. Pero el equipo de red respondió con un «no tan rápido»: la VM necesita mantener su IP y MAC en el cluster destino, lo que implica estirar un dominio de Layer 2 entre sites. En infraestructura tradicional, eso significa nuevos VLANs, cambios en switches, posiblemente hardware adicional, una ventana de cambio y un ticket que puede tardar semanas.
Qué ocurrió
El problema no está en la tecnología de migración de KubeVirt, sino en los requisitos de red que Kubernetes no resuelve por defecto. Para migrar una VM entre clusters sin cortar conexiones, se necesitan dos cosas:
En plataformas de virtualización tradicionales (vmware NSX, OpenStack + Neutron), estos problemas se resuelven con VLANs dedicadas para migración y constructs de switches virtuales propietarios. Pero estas soluciones están acopladas al hardware, son específicas de vendor y a menudo requieren licencias por socket.
Impacto para DevOps / Infraestructura / Cloud / Seguridad
El principal impacto es operacional: la imposibilidad de migrar VMs entre clusters limita la flexibilidad de la infraestructura. Sin movilidad cross-cluster:
- Recovery ante desastres requiere recrear VMs en el cluster de backup con nuevas IPs, lo que alarga el RTO y puede requerir cambios manuales en aplicaciones dependientes.
- Actualizaciones de clusters obligan a apagar VMs o a mantener clusters viejos hasta que las aplicaciones puedan redirigirse, aumentando costos y riesgos de seguridad (ej.: clusters sin parches).
- Balanceo de carga no puede redistribuir VMs según la capacidad disponible, llevando a sobreutilización en algunos clusters y subutilización en otros.
Para el equipo de seguridad, esto también significa menor agilidad para aislar workloads problemáticas o moverlas a clusters con políticas de seguridad más estrictas. Además, si se implementan soluciones ad-hoc (como tunnels VPN punto a punto para migración), se introduce complejidad y riesgos de configuración inconsistente.
En entornos cloud (ej.: EKS), el problema persiste: aunque la red subyacente sea manejada por AWS, los clusters de Kubernetes son dominios de red independientes y no comparten un dominio L2 por defecto.
Detalles técnicos
La solución open source para este problema combina EVPN/VXLAN como overlay de red y OpenPERouter para gestionarlo de manera nativa en Kubernetes.
Cómo funciona EVPN/VXLAN
EVPN (Ethernet VPN) es un estándar IETF (RFC 7432) que permite crear overlays de Layer 2 y Layer 3 sobre redes IP existentes. Usando VXLAN como encapsulamiento (puerto UDP 8472), los endpoints (VTEPs) establecen tunnels entre sí y distribuen información de MAC e IP via BGP. Esto permite:
- Estirar un dominio L2 ( broadcast domain) entre sites sin depender de VLANs físicas.
- Aislar tráfico con VRFs (Virtual Routing and Forwarding).
- Crear overlays sobre cualquier infraestructura IP subyacente (puede atravesar routers, firewalls, incluso Internet).
OpenPERouter: EVPN como CRD
OpenPERouter es un proyecto open source que implementa EVPN/VXLAN para Kubernetes mediante Custom Resource Definitions (CRDs). Tres recursos clave:
apiVersion: metal3.io/v1alpha1
kind: Underlay
metadata:
name: underlay-main
spec:
type: BGP
bgp:
myASN: 65001
peerASN: 64500
peerAddress: 192.168.1.1
peerInterface: eth0
ipPool: 192.168.2.0/24
apiVersion: metal3.io/v1alpha1
kind: L2VNI
metadata:
name: app-network
spec:
vni: 110
vrf: red
network: 192.170.1.0/24
Para la migración, se define un segundo L2VNI dedicado:
apiVersion: metal3.io/v1alpha1
kind: L2VNI
metadata:
name: migration-network
spec:
vni: 666
vrf: rouge
network: 192.170.2.0/24
Este overlay usa el mismo patrón que la red de aplicaciones, pero con un VNI distinto (666), lo que aisla el tráfico de migración del tráfico de applications. El overlay se construye sobre la conectividad IP existente entre sites; los endpoints VXLAN no necesitan estar en el mismo segment de red.
Migración de VMs
Con la infraestructura de red en su lugar, la migración de una VM entre clusters requiere tres recursos:
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: my-vm
spec:
runStrategy: WaitAsReceiver
template:
spec:
networkInterfaces:
– name: default
multus:
networkName: app-network
…
apiVersion: kubevirt.io/v1
kind: VirtualMachineInstanceMigration
metadata:
name: migration-my-vm-to-b
spec:
vmName: my-vm
targetNode: node-b-1
liveMigrate: true
apiVersion: kubevirt.io/v1
kind: VirtualMachineInstanceMigration
metadata:
name: migration-my-vm-to-b
spec:
vmName: my-vm
targetNode: node-b-1
liveMigrate: true
nodeSelector: {}
tolerance:
– key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
El tráfico de migración fluye sobre el VNI 666, aislado del VNI 110 de aplicaciones. EVPN actualiza las advertencias MAC/IP en el fabric, y el tráfico hacia la VM comienza a llegar al nuevo cluster sin cambios en DNS o IPs.
IPAM cross-cluster
Para evitar conflictos de IPs entre clusters, se necesita una estrategia de IPAM que partione el subnet. El ejemplo usa Whereabouts (un CNI para asignación de IPs) con rangos excluyentes:
- Cluster A: 192.170.1.0/25 (192.170.1.0-127)
- Cluster B: 192.170.1.128/25 (192.170.1.128-255)
Configuración en el NetworkAttachmentDefinition:
apiVersion: «k8s.cni.cncf.io/v1»
kind: NetworkAttachmentDefinition
metadata:
name: app-network
spec:
config: |-
{
«cniVersion»: «0.3.1»,
«type»: «whereabouts»,
«ipam»: {
«type»: «host-local»,
«range»: «192.170.1.0/25»,
«excludeRanges»: [
{«start»: «192.170.1.128», «end»: «192.170.1.255»}
]
}
}
Qué deberían hacer los administradores y equipos técnicos
kubectl apply -f https://github.com/metal3-io/OpenPERouter/releases/download/v0.6.0/manifests.yaml
Verificar que el daemon openperouter se ejecute en los nodos con la interfaz de red correcta (ej.: eth0).
– Definir un Underlay CR por cluster, con el ASN y peer BGP correspondientes al switch ToR.
– Si los switches ToR no soporten BGP, usar un BGP speaker en cada nodo (ej.: FRR) y configurar peering entre nodos.
– Un L2VNI para la red de aplicaciones (mismo VNI y VRF en todos los clusters).
– Un L2VNI separado para migración (VNI y VRF distintos).
– Implementar Whereabouts o otro CNI con soporte para rangos excluyentes.
– Asegurarse de que cada cluster tenga un rango único dentro del subnet estirado.
– Crear una VM en el cluster A.
– Definir los recursos VirtualMachine (con WaitAsReceiver), VirtualMachineInstanceMigration (receiver) en el cluster B, y VirtualMachineInstanceMigration (sender) en el cluster A.
– Verificar que la VM migre sin perder conectividad:
kubectl get vmi -w # Monitorear el estado de la VM
kubectl get virtualmachineinstancemigration -o wide # Ver progreso de la migración
– Verificar el estado de los peers BGP:
kubectl exec -n openperouter openperouter-cpxd — vrf show
kubectl exec -n openperouter openperouter-cpxd — bgp neighbor
– Monitorear tráfico VXLAN con herramientas como tcpdump (filtrando por puerto UDP 8472).
Conclusión
La migración cross-cluster de VMs en KubeVirt no es un problema técnico de la herramienta, sino un desafío de red. EVPN/VXLAN proporcionan el overlay necesario para estirar dominios L2 y aislar el tráfico de migración, mientras que OpenPERouter los expone como recursos nativos de Kubernetes. El cambio es operacional: la configuración de la red pasa de ser un ticket al equipo de networking (con ventanas de cambio y dependencias de hardware) a ser un CRD aplicado por el equipo de plataforma, versionado en Git y revisable via PR.
Esta aproximación no solo habilita la movilidad de VMs, sino que también sienta las bases para otros casos de uso multi-cluster, como estirar redes de Pods entre clusters o implementar servicios distribuidos. KubeVirt (proyecto incubado en CNCF desde abril 2022) y OpenPERouter son open source, sin costos de licencia por socket, y funcionan sobre cualquier infraestructura IP.
Fuentes
- https://thenewstack.io/kubevirt-evpn-vm-migration/
- https://kubernetes.io/blog/
- https://labs.ripe.net/
