Problema
Muchos administradores de homelab mantienen sus entornos sobre hipervisores tradicionales (por ejemplo, ESXi) y gestionan máquinas virtuales como “mascotas”. Cada VM se crea manualmente, se le asignan recursos a mano y su configuración se mantiene fuera de cualquier sistema declarativo. Con el tiempo, esa práctica genera tres síntomas recurrentes:
- Ansiedad operativa – siempre está la duda de si una VM va a fallar porque su estado no está versionado.
- Dificultad de replicación – clonar una configuración implica copiar discos, scripts y documentación dispersa.
- Escalabilidad limitada – añadir una nueva instancia requiere repetir los mismos pasos manuales, lo que aumenta la probabilidad de errores.
El reto consiste en migrar a una arquitectura donde los recursos son “cattle”: plantillas inmutables, despliegues reproducibles y todo el ciclo gestionado por código. La solución típica combina un hipervisor basado en Kubernetes (Harvester), infraestructura como código (Terraform), orquestación de configuración (Ansible) y GitOps (Fleet, ArgoCD, etc.).
Causa
Los problemas descritos aparecen por una combinación de factores:
- Dependencia de UI del hipervisor – crear VMs a través de la consola de ESXi obliga a recordar valores de CPU, RAM y discos en la cabeza o en notas sueltas.
- Ausencia de estado declarativo – sin un repositorio que describa la infraestructura, cualquier cambio se hace “ad‑hoc” y no queda registro.
- Falta de separación de roles – los mismos nodos ejecutan workloads críticos y tareas de gestión, lo que dificulta la planificación de capacidad y la aplicación de políticas de seguridad.
- Almacenamiento de datos sin orquestador – volúmenes persistentes gestionados manualmente no se benefician de la reconciliación automática, lo que genera desalineación entre la configuración y la realidad.
Estos patrones son comunes en homelabs que evolucionan de un entorno de pruebas a una plataforma de producción ligera.
Solución
Una arquitectura basada en Harvester permite tratar el hipervisor como un clúster Kubernetes. La solución se divide en cuatro capas:
- Hipervisor Harvester – despliega KubeVirt, RKE2 y Longhorn como componentes integrados. Cada VM es un recurso
VirtualMachinede Kubernetes. - Infraestructura como código con Terraform – describe VMs, redes y volúmenes en archivos
.tf. Terraform mantiene el estado y evita la interacción manual con la UI. - Configuración de la VM con Ansible – una vez que Terraform crea la instancia, Ansible aplica roles (SSH hardening, instalación de paquetes, etc.) usando
ansible-playbook. - GitOps para workloads – los clusters K3s/K8s ejecutan aplicaciones declaradas en repositorios Git. Fleet o ArgoCD observan los cambios y los aplican automáticamente.
Paso a paso resumido
- Instalar Harvester en el hardware existente (ej. Dell DL380 Gen9). La instalación es idéntica a la de cualquier distro ISO: arranca, sigue el asistente y habilita la integración con Longhorn.
- Configurar Terraform:
- Añade el provider
harvestery define recursosharvester_virtualmachine. - Usa módulos para crear plantillas reutilizables (CPU, RAM, discos).
- Añade el provider
- Ejecutar
terraform planyterraform apply. Cada VM aparece como un pod KubeVirt; no hay UI que tocar. - Desencadenar Ansible:
- Usa el inventario dinámico de Terraform (
terraform output -json) para generar la lista de hosts. - Ejecuta playbooks que instalen los servicios que antes estaban en VMs “pet”.
- Usa el inventario dinámico de Terraform (
- Desplegar workloads con GitOps:
- Crea un repo Git con manifests Helm o Kustomize.
- Configura Fleet (o ArgoCD) para observar el repo y sincronizar el clúster.
- Separar roles de nodo:
- Etiqueta el nodo de control‑plane como
node-role.kubernetes.io/control-plane: "". - Marca un nodo como
longhorn.io/drain: "true"para almacenar volúmenes. - El resto quedan como workers sin taints, listos para workloads stateless.
- Etiqueta el nodo de control‑plane como
Con este flujo, cualquier nueva aplicación se agrega mediante un commit en Git; Terraform y Ansible se encargan de la infraestructura subyacente, y el clúster mantiene el estado deseado sin intervención manual.
Cuándo aplicar esta solución
Escenarios ideales
- Homelabs que ya usan ESXi, Proxmox o Hyper‑V y quieren reducir la fricción operativa.
- Equipos que gestionan más de 5 VMs y la complejidad de la UI se vuelve un cuello de botella.
- Necesidad de versionar la infraestructura y los workloads (cumplimiento, auditoría).
- Interés en consolidar almacenamiento con Longhorn o Ceph y aprovechar la auto‑reconciliación.
Señales de que la solución encaja
- Los despliegues de nuevas VMs tardan más de 15 min por la configuración manual.
- Los backups de configuraciones se guardan en documentos de texto sueltos.
- Se percibe “drift” entre lo que debería estar corriendo y lo que realmente está.
Casos donde NO aplicar
- Entornos con requisitos de certificación que prohíben Kubernetes en la capa de virtualización.
- Hardware que no soporta la carga de un clúster RKE2 (p.ej., recursos extremadamente limitados).
- Necesidad de VMs con acceso directo a hardware que KubeVirt no expone (passthrough PCI completo).
Código
# Provider y módulo básico para crear una VM en Harvester
terraform {
required_providers {
harvester = {
source = "harvester/harvester"
version = "~> 0.4"
}
}
}
provider "harvester" {
kubeconfig = "~/.kube/harvester.yaml"
}
module "cattle_vm" {
source = "./modules/cattle_vm"
name = "paperless-ngx"
cpu = 2
memory = 4096
disks = [
{
name = "root"
size = 40
boot_order = 1
},
{
name = "data"
size = 200
boot_order = 0
}
]
}
# Inventario dinámico de Ansible usando salida de Terraform
terraform output -json > tf_output.json
python3 -c "
import json, sys
data = json.load(open('tf_output.json'))
hosts = {vm['value']['name']: vm['value']['ip'] for vm in data['virtual_machines']['value']}
print('[cattle_vms]')
for name, ip in hosts.items():
print(f'{name} ansible_host={ip}')
" > inventory.ini
# Playbook sencillo para instalar Docker y habilitar el servicio
ansible-playbook -i inventory.ini site.yml --limit paperless-ngx
Verificación
- Terraform –
terraform state listdebe mostrar los recursosharvester_virtualmachinecreados. - KubeVirt –
kubectl get vmmuestra las VMs con estadoRunning. - Longhorn –
kubectl -n longhorn-system get podstodos enRunningykubectl get pvcmuestra los volúmenes vinculados. - Ansible –
ansible -m ping all -i inventory.inidevuelvepongpara cada host. - GitOps – verifica que los pods de la aplicación aparecen tras el commit:
kubectl get pods -n paperless.
Notas adicionales
- Versionado del provider: bloquea la versión de
harvesteren Terraform para evitar cambios inesperados en la API. - Persistencia de datos: al migrar PVs de ESXi a Longhorn, usa
rsynco snapshots y restaura los datos antes de aplicar los manifests. - Tolerancias: etiqueta los nodos de Longhorn con
node-role.kubernetes.io/storage: ""y usanodeSelectoren los PVC para forzar la afinidad. - Backup del estado: almacena
terraform.tfstateen un bucket S3 o en un repo Git‑encrypted para evitar pérdida de información. - Monitoreo: habilita Prometheus y Grafana en el clúster para observar la reconciliación de Longhorn y la latencia de los workloads GitOps.
Con este enfoque, el homelab pasa de ser una colección de máquinas “mascotas” a una plataforma declarativa, reproducible y prácticamente libre de mantenimiento manual. La verdadera ganancia no es solo la automatización, sino la tranquilidad de saber que cualquier falla se puede revertir con un git revert y un terraform apply.