Problema
Los ingenieros que entrenan modelos de lenguaje, ejecutan inferencias de 70 B + parámetros o corren contenedores de inferencia suelen recurrir a servicios en la nube. El coste mensual y la dependencia de APIs externas son obstáculos cuando se busca experimentar sin compromisos financieros ni de privacidad. La necesidad típica es disponer de una GPU dedicada que pueda ser usada tanto por una máquina virtual (para aplicaciones Windows) como por contenedores Linux en el mismo host, todo dentro de la red doméstica.
En un entorno de homelab, el patrón que se repite es:
- Un servidor Linux con soporte de virtualización.
- Una o más GPU que deben estar disponibles para una VM (passthrough) y, al mismo tiempo, para workloads nativos en Linux.
- Acceso remoto seguro para la VM y los contenedores.
- Un proceso reproducible que permita volver a levantar el entorno después de una falla o una actualización de hardware.
El reto es alinear BIOS, kernel, libvirt y drivers de Windows sin crear cuellos de botella ni perder la capacidad de usar Docker para los servicios de IA.
Causa
Los fallos más habituales aparecen por:
- IOMMU desactivado en la BIOS o en el kernel, impidiendo que el hipervisor reasigne dispositivos PCIe.
- Grupos de IOMMU que mezclan la GPU con otros dispositivos (USB, audio) y provocan “device is busy” al intentar el passthrough.
- Controladores de la GPU en el host que siguen cargados, bloqueando la exclusión de la tarjeta.
- Configuración de libvirt incompleta: falta de
vfio-pcienhost-passthrough, o ausencia demachineconq35ycpuconhost-passthrough. - Windows 11 que requiere firmas de driver y, a veces, un reinicio de la GPU que el host no permite sin
resetoACS(Access Control Services) habilitado. - Redirección de pantalla: sin un monitor conectado o sin “dummy HDMI”, la GPU entra en modo de bajo consumo y la VM no recibe señal.
- Problemas de red cuando se combina VNC con túnel SSH: puertos mal mapeados o firewall bloqueando el tráfico.
Solución
Una arquitectura reutilizable se basa en tres capas:
- Host Linux (Ubuntu 26.04 o similar) – habilita IOMMU, prepara
vfio-pci, y asegura que la GPU no sea gestionada por el driver nativo. - Máquina virtual Windows 11 – configurada con libvirt para usar
host-passthroughy con una pantalla virtual (VNC) accesible vía SSH. - Servicios Docker – corren en el host, consumen la segunda GPU (si la hay) o la CPU, y se exponen mediante
docker compose.
Paso 1: Preparar el host
-
Activar IOMMU
En la BIOS, habilita VT‑d (Intel) o AMD‑IOMMU.
Añade al kernel:intel_iommu=onoamd_iommu=onsegún corresponda. -
Configurar GRUB
sudo nano /etc/default/grubModifica la línea
GRUB_CMDLINE_LINUX_DEFAULTpara incluir:intel_iommu=on iommu=pto la variante AMD. Luego:
sudo update-grub && sudo reboot -
Verificar grupos IOMMU
sudo dmesg | grep -e DMAR -e IOMMUBusca que cada dispositivo tenga su propio group.
-
Aislar la GPU
Identifica el PCI ID de la tarjeta que será pasada:lspci -nn | grep -i nvidiaSupongamos
01:00.0. Añade al archivo de módulos:sudo nano /etc/modprobe.d/vfio.confContenido:
options vfio-pci ids=10de:2488,10de:228b(reemplaza con los IDs de tu modelo).
Desactiva los drivers nativos:echo "blacklist nouveau" | sudo tee -a /etc/modprobe.d/blacklist.conf sudo update-initramfs -u && sudo reboot -
Instalar KVM y libvirt
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager sudo systemctl enable --now libvirtd
Paso 2: Definir la VM
Crea una definición XML mínima y añádela a libvirt:
sudo virsh define /tmp/windows11.xml
Contenido esencial (/tmp/windows11.xml):
<domain type='kvm'>
<name>win11-ai</name>
<memory unit='MiB'>16384</memory>
<vcpu placement='static'>8</vcpu>
<os>
<type arch='x86_64' machine='q35'>hvm</type>
<loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
<nvram>/var/lib/libvirt/qemu/nvram/win11-ai_VARS.fd</nvram>
</os>
<features>
<acpi/>
<apic/>
<hyperv>
<relaxed state='on'/>
<vapic state='on'/>
<spinlocks state='on' retries='8191'/>
</hyperv>
</features>
<cpu mode='host-passthrough' check='none'/>
<devices>
<hostdev mode='subsystem' type='pci' managed='yes'>
<source address='0000:01:00.0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</hostdev>
<hostdev mode='subsystem' type='pci' managed='yes'>
<source address='0000:01:00.1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
</hostdev>
<graphics type='vnc' port='-1' listen='127.0.0.1' keymap='es'/>
<sound model='ich9'/>
<input type='tablet' bus='usb'/>
</devices>
</domain>
- La sección
<hostdev>incluye la GPU y su controlador de audio. graphicsabre VNC en un puerto aleatorio; el acceso se hará mediante túnel SSH.
Arranca la VM y procede con la instalación de Windows 11 (ISO en /var/lib/libvirt/images). Instala los drivers de NVIDIA desde la web oficial; el instalador detectará la GPU como “passthrough”.
Paso 3: Acceso remoto seguro
En el cliente, abre un túnel SSH:
ssh -L 5901:127.0.0.1:5901 usuario@host-ip
Luego, con un visor VNC (virt-viewer o remmina) conecta a localhost:5901. La VM queda accesible desde cualquier dispositivo dentro de la red, siempre que el túnel esté activo.
Paso 4: Contenedores Docker para servicios de IA
En el host, crea un docker-compose.yml que lance, por ejemplo, Ollama, vLLM o Text Generation Inference:
version: '3.8'
services:
ollama:
image: ollama/ollama:latest
restart: unless-stopped
ports:
- "11434:11434"
volumes:
- ollama-data:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
volumes:
ollama-data:
Asegúrate de que nvidia-container-toolkit esté instalado y que el daemon de Docker reconozca la segunda GPU (si la hay) o la CPU.
sudo apt install -y nvidia-docker2
sudo systemctl restart docker
docker compose up -d
Con esto, los modelos se sirven en la red local sin tocar la VM.
Cuándo aplicar esta solución
- Necesitas GPU dedicada para Windows (por ejemplo, para software que solo corre en ese SO) y al mismo tiempo contenedores Linux que consuman otra GPU o la CPU.
- Presupuesto limitado: prefieres hardware propio a servicios en la nube.
- Privacidad: los datos nunca abandonan tu red local.
- Escalabilidad moderada: el host tiene al menos 16 GB RAM y una GPU con 12 GB VRAM o más.
No es apropiado cuando:
- Solo se requiere inferencia en Linux; en ese caso, el passthrough a Windows es sobre‑ingeniería.
- El hardware no soporta IOMMU o la GPU no permite reset de forma fiable (modelos antiguos).
- Se necesita alta disponibilidad multi‑nodo; KVM en un solo host no brinda redundancia.
Código
# 1. Habilitar IOMMU