La virtualización es una de las tecnologías fundamentales en la infraestructura moderna. Para un ingeniero DevOps, dominar KVM, LXC/LXD y entender como se relacionan con los contenedores de aplicación (Docker, Podman) no es opcional: es parte del conocimiento base que necesitas para disenar, automatizar y operar entornos de producción. En esta guía cubrimos desde la instalación de KVM con libvirt hasta la automatización con Terraform, pasando por GPU passthrough y optimización de rendimiento.

Fundamentos de Virtualización en Linux

Linux soporta virtualización a nivel de kernel gracias a KVM (Kernel-based Virtual Machine), que convierte el kernel en un hipervisor de tipo 1. Esto significa que las maquinas virtuales ejecutan instrucciones directamente en el hardware fisico mediante las extensiones de virtualización del procesador (Intel VT-x o AMD-V).

La diferencia clave con la contenedorización es el nivel de aislamiento:

  • KVM: Virtualización completa. Cada VM tiene su propio kernel, hardware virtual y sistema operativo independiente. Aislamiento fuerte.
  • LXC/LXD: Contenedores de sistema. Comparten el kernel del host pero tienen su propio espacio de usuario (filesystem, procesos, red). Aislamiento medio.
  • Docker/Podman: Contenedores de aplicación. Empaquetan una sola aplicación con sus dependencias. Aislamiento orientado a la aplicación.

Para verificar que tu hardware soporta virtualización:

# Verificar extensiones de virtualizacion del CPU
egrep -c '(vmx|svm)' /proc/cpuinfo

# Verificar soporte de KVM
lsmod | grep kvm

# Herramienta de verificacion en Debian/Ubuntu
sudo apt install cpu-checker
kvm-ok

Instalación y Configuración de KVM con libvirt

libvirt es la capa de abstracción estandar para gestionar hipervisores en Linux. Proporciona una API unificada y herramientas como virsh, virt-install y virt-manager.

Instalación en Ubuntu/Debian

# Instalar KVM, libvirt y herramientas de gestion
sudo apt install -y qemu-kvm libvirt-daemon-system \
  libvirt-clients bridge-utils virtinst virt-manager

# Agregar tu usuario al grupo libvirt
sudo usermod -aG libvirt $(whoami)
sudo usermod -aG kvm $(whoami)

# Verificar que libvirtd esta activo
sudo systemctl enable --now libvirtd
sudo systemctl status libvirtd

Crear una VM con virt-install

virt-install es la herramienta de linea de comandos para crear maquinas virtuales de forma reproducible:

# Crear una VM Ubuntu con 2 vCPUs, 4GB RAM, 20GB disco
virt-install \
  --name ubuntu-server \
  --ram 4096 \
  --vcpus 2 \
  --disk path=/var/lib/libvirt/images/ubuntu-server.qcow2,size=20 \
  --os-variant ubuntu22.04 \
  --network bridge=virbr0 \
  --graphics none \
  --console pty,target_type=serial \
  --location 'http://archive.ubuntu.com/ubuntu/dists/jammy/main/installer-amd64/' \
  --extra-args 'console=ttyS0,115200n8 serial'

Gestión con virsh

virsh es la interfaz principal para administrar VMs en producción:

# Listar todas las VMs (activas e inactivas)
virsh list --all

# Iniciar, detener, reiniciar
virsh start ubuntu-server
virsh shutdown ubuntu-server
virsh reboot ubuntu-server

# Tomar snapshot
virsh snapshot-create-as ubuntu-server --name "pre-update" \
  --description "Antes de actualizar paquetes"

# Listar snapshots
virsh snapshot-list ubuntu-server

# Revertir a snapshot
virsh snapshot-revert ubuntu-server --snapshotname "pre-update"

# Ver informacion de la VM
virsh dominfo ubuntu-server
virsh domblklist ubuntu-server

LXC/LXD: Contenedores de Sistema

LXD es el gestor moderno de contenedores de sistema construido sobre LXC. Ofrece una experiencia similar a gestionar VMs pero con el rendimiento de contenedores, ya que comparten el kernel del host.

Configuración inicial de LXD

# Instalar LXD
sudo snap install lxd

# Inicializar (configuracion interactiva)
lxd init

# Crear un contenedor Ubuntu
lxc launch ubuntu:22.04 mi-contenedor

# Listar contenedores
lxc list

# Ejecutar comandos dentro del contenedor
lxc exec mi-contenedor -- bash

# Limitar recursos
lxc config set mi-contenedor limits.cpu 2
lxc config set mi-contenedor limits.memory 2GB

# Crear perfil personalizado
lxc profile create devops-server
lxc profile set devops-server limits.cpu 4
lxc profile set devops-server limits.memory 8GB
lxc profile set devops-server security.nesting true

La opción security.nesting=true es relevante cuando necesitas ejecutar Docker dentro de un contenedor LXD, un patron comun en entornos de CI/CD.

Comparativa: KVM vs Contenedores

CaracteristicaKVMLXC/LXDDocker/Podman
AislamientoCompleto (kernel propio)Parcial (kernel compartido)Parcial (proceso aislado)
OverheadAlto (~200MB+ por VM)Bajo (~10-50MB)Minimo (~5-20MB)
Tiempo de arranque30-60 segundos1-3 segundosSubsegundo
Caso de usoMulti-OS, seguridad fuerteServidores de desarrollo, CIMicroservicios, aplicaciones
PersistenciaDisco virtual completoFilesystem del contenedorVolumenes, efimero por diseño
NetworkingBridge, NAT, SR-IOVBridge, macvlanBridge, overlay, host

Cuando usar KVM: Necesitas ejecutar diferentes sistemas operativos (Windows en Linux), requieres aislamiento fuerte por regulación, o necesitas acceso directo a hardware (GPU passthrough).

Cuando usar LXC/LXD: Quieres densidad alta de servidores Linux con rendimiento nativo, entornos de desarrollo que simulan servidores reales, o runners de CI/CD aislados.

Virtualización Anidada (Nested Virtualization)

La virtualización anidada permite ejecutar un hipervisor dentro de una VM. Es esencial para laboratorios de prueba, ambientes de CI/CD que necesitan VMs, y plataformas de formación.

# Habilitar nested virtualization para Intel
sudo modprobe -r kvm_intel
sudo modprobe kvm_intel nested=1

# Hacer persistente
echo "options kvm_intel nested=1" | sudo tee /etc/modprobe.d/kvm-nested.conf

# Verificar que esta habilitado
cat /sys/module/kvm_intel/parameters/nested
# Debe mostrar: Y

# Para AMD:
sudo modprobe -r kvm_amd
sudo modprobe kvm_amd nested=1
echo "options kvm_amd nested=1" | sudo tee /etc/modprobe.d/kvm-nested.conf

Al crear la VM que usara nested virtualization, asegurate de exponer las extensiones del CPU:

virt-install \
  --name nested-lab \
  --ram 8192 \
  --vcpus 4 \
  --cpu host-passthrough \
  --disk path=/var/lib/libvirt/images/nested-lab.qcow2,size=40 \
  --os-variant ubuntu22.04 \
  --network bridge=virbr0 \
  --graphics none \
  --console pty,target_type=serial \
  --cdrom /var/lib/libvirt/images/ubuntu-22.04-live-server-amd64.iso

La opción --cpu host-passthrough expone las capacidades del CPU fisico a la VM, incluyendo las extensiones de virtualización.

GPU Passthrough con VFIO

El GPU passthrough permite asignar una GPU fisica directamente a una VM, útil para workloads de machine learning, renderizado o aplicaciones que requieren aceleración por hardware.

# 1. Identificar la GPU y su grupo IOMMU
lspci -nn | grep -i nvidia
# Ejemplo de salida: 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation [10de:2204]

# 2. Habilitar IOMMU en GRUB
# Editar /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on iommu=pt"
sudo update-grub

# 3. Cargar modulos VFIO
echo "vfio-pci" | sudo tee /etc/modules-load.d/vfio-pci.conf
echo "options vfio-pci ids=10de:2204" | sudo tee /etc/modprobe.d/vfio.conf

# 4. Reiniciar y verificar
sudo reboot
dmesg | grep -i vfio

# 5. Asignar GPU a la VM con virsh
virsh edit mi-vm
# Agregar en la seccion <devices>:
# <hostdev mode='subsystem' type='pci' managed='yes'>
#   <source>
#     <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
#   </source>
# </hostdev>

Automatización con Terraform

El provider de libvirt para Terraform permite gestionar VMs como código, integrando la virtualización en tu pipeline de Infrastructure as Code:

terraform {
  required_providers {
    libvirt = {
      source  = "dmacvicar/libvirt"
      version = "~> 0.7"
    }
  }
}

provider "libvirt" {
  uri = "qemu:///system"
}

resource "libvirt_volume" "ubuntu_base" {
  name   = "ubuntu-base.qcow2"
  pool   = "default"
  source = "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img"
  format = "qcow2"
}

resource "libvirt_volume" "web_server_disk" {
  name           = "web-server.qcow2"
  pool           = "default"
  base_volume_id = libvirt_volume.ubuntu_base.id
  size           = 21474836480  # 20GB
}

resource "libvirt_domain" "web_server" {
  name   = "web-server"
  memory = "4096"
  vcpu   = 2

  disk {
    volume_id = libvirt_volume.web_server_disk.id
  }

  network_interface {
    network_name   = "default"
    wait_for_lease = true
  }

  console {
    type        = "pty"
    target_port = "0"
    target_type = "serial"
  }
}

output "vm_ip" {
  value = libvirt_domain.web_server.network_interface[0].addresses[0]
}

Este enfoque permite versionar tu infraestructura de virtualización, reproducir entornos de forma consistente y destruir/recrear VMs en segundos.

Optimización de Rendimiento

CPU Pinning

Asignar vCPUs a cores fisicos específicos reduce la latencia y mejora la consistencia del rendimiento:

<!-- En la definicion XML de la VM -->
<vcpu placement='static'>4</vcpu>
<cputune>
  <vcpupin vcpu='0' cpuset='2'/>
  <vcpupin vcpu='1' cpuset='3'/>
  <vcpupin vcpu='2' cpuset='4'/>
  <vcpupin vcpu='3' cpuset='5'/>
</cputune>

Huge Pages

Las huge pages reducen la sobrecarga de gestión de memoria para VMs con mucha RAM:

# Reservar 4GB de huge pages (2MB cada una)
echo 2048 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

# Hacer persistente en /etc/sysctl.conf
vm.nr_hugepages = 2048

# Habilitar en la VM (XML)
# <memoryBacking>
#   <hugepages/>
# </memoryBacking>

I/O: Virtio y Cache

Usa siempre drivers virtio para disco y red, y configura el cache segun tu caso:

  • cache='writeback': Mejor rendimiento, riesgo de perdida de datos en crash
  • cache='none': Recomendado con almacenamiento con cache propio (SAN, RAID con bateria)
  • cache='writethrough': Mas seguro, menor rendimiento

Conclusion

La virtualización en Linux es un ecosistema maduro con opciones para cada necesidad. KVM con libvirt sigue siendo la base para virtualización pesada en producción, LXD ofrece un punto intermedio para servidores Linux de alta densidad, y la combinación con Terraform permite automatizar todo como código. Dominar estas herramientas te da la capacidad de disenar infraestructura flexible, desde un laboratorio local hasta un cloud privado con cientos de VMs.

Recursos