Conociendo KubeVirt
KubeVirt es una extensión de Kubernetes que permite ejecutar y gestionar máquinas virtuales (VM) junto con contenedores en un clúster de Kubernetes. Su objetivo es proporcionar una plataforma unificada para la administración de cargas de trabajo tanto de contenedores como de máquinas virtuales, integrando las capacidades de virtualización con las de contenedores.

KubeVirt permite gestionar, por tanto, gestionar las máquinas virtuales de manera similar a los pods de Kubernetes, ofreciendo características como escalabilidad, orquestación y administración centralizada.
Características
Las características principales de KubeVirt son:
- Orquestación de máquinas virtuales en Kubernetes: permite ejecutar y gestionar máquinas virtuales (VM) como si fueran contenedores en un clúster de Kubernetes, aprovechando la infraestructura de orquestación de Kubernetes para la administración de VM.
- Compatibilidad con KVM (Kernel-based Virtual Machine): KubeVirt utiliza KVM para la virtualización, lo que permite ejecutar VM en nodos que tienen soporte para KVM.
- Integración con el ecosistema de Kubernetes: al estar basado en Kubernetes, KubeVirt se integra con otras herramientas de Kubernetes, como Helm, Prometheus, y otras soluciones de monitoreo y gestión de redes.
- Escalabilidad y alta disponibilidad: KubeVirt permite escalar las máquinas virtuales de manera automática, como se hace con los contenedores, y ofrece opciones para asegurar la alta disponibilidad de las VM.
- Gestión de infraestructura unificada: ofrece un solo plano de control para gestionar tanto aplicaciones basadas en contenedores como máquinas virtuales, facilitando la administración de ambos tipos de cargas de trabajo desde un único lugar.
- Compatibilidad con carga de trabajo híbrida: soporta cargas de trabajo híbridas que pueden ser contenedores y máquinas virtuales, lo que es útil en entornos de migración o cuando se tienen aplicaciones heredadas que requieren VM.
- Persistencia de volúmenes y almacenamiento: KubeVirt permite el uso de volúmenes persistentes para máquinas virtuales, asegurando que los datos se mantengan disponibles a través de reinicios o migraciones de las VM.
- Interfaz de usuario y APIs: proporciona interfaces de usuario basadas en Kubernetes (como kubectl) y APIs RESTful que permiten la gestión de las máquinas virtuales de manera programática y a través de interfaces gráficas.
- Gestión de redes virtuales: permite configurar redes virtuales para las máquinas virtuales, con opciones de conectividad avanzadas y soporte para redes virtuales de Kubernetes.
- Migración en tiempo real de máquinas virtuales: KubeVirt soporta la migración en vivo de máquinas virtuales, lo que permite moverlas entre nodos sin interrumpir su funcionamiento, similar a las migraciones de contenedores en Kubernetes.
Estas características permiten combinar lo mejor de las máquinas virtuales y los contenedores dentro de un solo ecosistema, facilitando la modernización de infraestructuras heredadas y la gestión de diferentes tipos de cargas de trabajo.
Despliegue de KubeVirt en entorno RKE2
Sin querer meternos en mucho detalle, a continuación vamos a ver cómo desplegar KubeVirt. Así, en primer lugar será necesario lanzar los siguientes comandos:
# Establecer la ultima versión de KubeVirt
export RELEASE=$(curl https://storage.googleapis.com/kubevirt-prow/release/kubevirt/kubevirt/stable.txt)
# Desplegar KubeVirt Operator en su ultima versión stable
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-operator.yaml
# Desplegar KubeVirt CR en su ultima versión stable
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-cr.yaml
Para que levante todo de manera correcta, será necesario poner SELinux en modo permisivo sin que bloquee ninguna acción, ya que si no, virt-handler no levantara:
# Aplicar en cada maquina
sudo setenforce 0
KubeVirt despliega los siguientes elementos:
- Deployments:
- virt-api: sirve para exponer el API server de KubeVirt que maneja las solicitudes relacionadas con máquinas virtuales y recursos asociados, permitiendo interactuar con la infraestructura de virtualización.
- virt-controller: sirve para administrar el ciclo de vida de las máquinas virtuales en el clúster, como crear, iniciar, detener y gestionar las instancias de VM
- virt-operator: sirve para gestionar la instalación, configuración y actualización de KubeVirt en el clúster, actuando como el operador principal que coordina el despliegue de los recursos de KubeVirt.
- DaemonSets:
- virt-handler: se ejecuta en cada nodo del clúster y es responsable de interactuar directamente con los hipervisores (como KVM) para gestionar las máquinas virtuales en ese nodo.

Creación de una maquina virtual con KubeVirt
Vamos a poder crear una maquina virtual con KubeVirt a través del siguiente YAML:
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: fedora-vm
namespace: default
spec:
running: true
template:
metadata:
labels:
kubevirt.io/vm: fedora-vm
spec:
domain:
devices:
disks:
- disk:
bus: virtio
name: mydisk
resources:
requests:
memory: 2Gi # 2 GB de RAM
cpu: 1 # 1 núcleo de CPU
volumes:
- name: mydisk
containerDisk:
image: quay.io/kubevirt/fedora-cloud-registry-disk-demo:latest # Imagen base de Fedora Cloud
- name: cloudinit
cloudInitNoCloud:
userData: |
#cloud-config
users:
- name: fedora # Nombre del usuario
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
plain_text_passwd: fedora # Contraseña del usuario
lock_passwd: false
chpasswd:
expire: false
Una vez creado el YAML, vamos a ejecutarlo mediante el siguiente comando:
kubectl apply -f fedora-vm.yaml
Por defecto, la máquina virtual creada tendrá 2 GB de RAM y 1 núcleo de CPU. Para acceder a ella, se hará a través de fedora mediante el siguiente comando:
kubectl get pod -l kubevirt.io/vm=fedora-vm -o wide

El acceso a la maquina puede ser a través de SSH, o con el binario de virtctl.
Creación de una maquina virtual con disco adicional
Para crear una máquina con un disco adicional de 50GB, será necesario crear los siguientes YAML:
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: fedora-vm
namespace: default
spec:
running: true
template:
metadata:
labels:
kubevirt.io/vm: fedora-vm
spec:
domain:
devices:
disks:
- name: mydisk
disk:
bus: virtio
- name: additional-disk
disk:
bus: virtio
resources:
requests:
memory: 2Gi # 2 GB de RAM
cpu: 1 # 1 núcleo de CPU
volumes:
- name: mydisk
containerDisk:
image: quay.io/kubevirt/fedora-cloud-registry-disk-demo:latest # Imagen base de Fedora Cloud
- name: additional-disk
persistentVolumeClaim:
claimName: pvc-fedora-vm # El PVC que creamos anteriormente
- name: cloudinit
cloudInitNoCloud:
userData: |
#cloud-config
users:
- name: fedora
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
plain_text_passwd: fedora
lock_passwd: false
chpasswd:
expire: false
Además, será necesario la creación de un PV:
apiVersion: v1
kind: PersistentVolume
metadata:
name: kubevirt-disk-pv
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 50Gi
hostPath:
path: /datadrive/onesaitplatform/kubevirt/disk1
storageClassName: 'local-storage'
Y la creación de un PVC asociado a ese PV:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: kubevirt-disk-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
volumeMode: Filesystem
volumeName: kubevirt-disk-pv
Para poder crearla, aplicaremos el YAML creado con el siguiente comando:
kubectl apply -f disk-pv.yaml
kubectl apply -f disk-pvc.yaml
kubectl apply -f fedora-vm.yaml
Una vez accedamos a nuestra maquina recién creada, podremos ver como el disco de 50GB que acabamos de crear aparece pero sin formato y sin montar:

Acceso a la máquina mediante SSH
Se puede acceder a la maquina mediante uno de los nodos que componen el clúster. Para ello, necesitamos saber la IP que se le ha asignado a la máquina virtual:
kubectl get pod -l kubevirt.io/vm=fedora-vm -o wide
Dentro del worker, por ejemplo, accedemos mediante:
ssh fedora@<ipMaquina>

Comprobamos cómo la maquina tiene 1 VCPU y 1 GB de RAM.
Acceso a la máquina mediante virtctl
Para instalar virtctl, será necesario lanzar los siguientes comandos:
# Descargar el binario de virtctl:
curl -LO https://github.com/kubevirt/kubevirt/releases/download/v0.56.0/virtctl-linux-amd64
# Dar permisos al binario de virtctl:
chmod +x virtctl-linux-amd64
# Mover el binario a la ubicacion correcta:
sudo mv virtctl-linux-amd64 /usr/local/bin/virtctl
Para poder acceder a la máquina, se tendrá que ejecutar el siguiente comando:
virtctl console fedora-vm

¿Cómo acceder desde fuera a la maquina?
Sera necesario crear un servicio tipo NodePort o en clouds del tipo de Azure, Amazon o Google. Se podría crear un servicio tipo balanceador que redirija las peticiones a esa maquina.
En el siguiente ejemplo se vera como acceder vía un servicio tipo NodePort. Para ello, deberemos aplicar el siguiente YAML:
apiVersion: v1
kind: Service
metadata:
name: fedora-vm-nodeport
namespace: default
spec:
selector:
kubevirt.io/vm: fedora-vm # Nombre de la máquina virtual
ports:
- protocol: TCP
port: 22 # Puerto al que accederás (en este caso SSH)
targetPort: 22 # Puerto dentro de la VM
nodePort: 30022 # Puerto que se expondrá en los nodos
type: NodePort
Aplicamos mediante el siguiente comando:
kubectl apply -f service-nodeport.yaml
Una vez creado, ya podríamos acceder a la maquina desde cualquier sitio con acceso a internet a través de la IP de máquina del nodo worker y el puerto NodePort que se haya expuesto:
ssh fedora@<ipWorker> -p 30022

Otros comandos de interés
Para ir terminando, os dejamos otros comandos que consideramos interesante conocer:
Parar la máquina
virtctl pause vm fedora-vm
Encencer la máquina
virtctl unpause vm fedora-vm
Borrar la maquina
kubectl delete vm fedora-vm
Imagen de cabecera: KubeVirt + Onesait Platform