Problema
En entornos donde se crean imágenes base con Packer, Terraform o scripts personalizados, la plantilla de una VM parece estar lista en cuanto el proceso de build termina sin errores. Sin embargo, la primera clonación suele revelar fallos: el guest‑agent no arranca, cloud‑init no genera una dirección IP, la configuración de red queda corrupta o, en Windows, el proceso de sysprep deja la instalación en un estado inestable. El síntoma típico es que la plantilla “funciona” en el pipeline de construcción pero falla en producción, obligando a revertir o a crear una nueva plantilla desde cero.
Este patrón se repite en la mayoría de los data‑centers que automatizan despliegues de VMs: la confianza ciega en la salida del builder genera interrupciones inesperadas y retrasa la entrega de servicios. Necesitamos un punto de aceptación objetivo que garantice que una plantilla es realmente reutilizable antes de que cualquier equipo la consuma.
Causa
-
Estado residual del proceso de instalación
- En Linux, paquetes que requieren un reinicio (por ejemplo, kernel) pueden quedar pendientes.
- En Windows, el sysprep puede dejar servicios marcados como “pending” o generar SID duplicados si no se ejecuta correctamente.
-
Configuración de cloud‑init incompleta
- Archivos de configuración (
/etc/cloud/cloud.cfg.d/) pueden contener rutas absolutas que solo existen en la máquina de build. - La clave
network: {config: disabled}a veces se hereda sin ser sobrescrita, dejando la red sin DHCP.
- Archivos de configuración (
-
Guest‑agent desincronizado
- El agente de Proxmox (
qemu-guest-agent) necesita estar habilitado y configurado para iniciar al arranque. Si el servicio está desactivado o la versión del agente no coincide con la del host, la comunicación falla.
- El agente de Proxmox (
-
Persistencia de datos temporales
- Archivos de logs, caches de paquetes o claves SSH generadas durante el build quedan en la imagen. Al clonar, el mismo fingerprint aparece en todas las máquinas, lo que rompe la seguridad de acceso.
-
Hardware virtual distinto al de build
- Cambios en la cantidad de CPU, tipo de disco (scsi vs virtio) o firmware (BIOS vs UEFI) pueden impedir que scripts de post‑instalación se ejecuten correctamente.
Solución
Adoptar un pipeline de validación de plantilla que incluya una clonación completa, arranque controlado y pruebas de verificación antes de marcar la imagen como “aprobada”. El flujo recomendado es:
-
Construcción de la plantilla
- Ejecutar Packer con
post-processorsque generen una snapshot limpia. - Desactivar servicios que no deben iniciarse en la plantilla (por ejemplo,
systemd-machine-id-commiten Linux,sysprepen Windows).
- Ejecutar Packer con
-
Clonación de prueba
- Crear un full clone (no linked) para garantizar que todas las capas de disco se materializan.
- Asignar una VM ID temporal y recursos mínimos (1 CPU, 1 GB RAM) para acelerar el arranque.
-
Arranque y espera de señal
- Configurar un timeout (ej. 300 s) y esperar a que el guest‑agent informe su IP.
- Si el agente no responde, registrar el error y abortar la validación.
-
Pruebas de conectividad
- Ejecutar un ping o una conexión SSH/WinRM a la IP obtenida.
- Verificar que
cloud-init status --waitfinaliza sin errores.
-
Checks de servicios críticos
- En Linux, validar que
systemdestá activo y quecloud-initha creado los usuarios esperados. - En Windows, comprobar que el servicio
Windows Remote Managementestá escuchando y que elSIDes único (whoami /user).
- En Linux, validar que
-
Limpieza de datos sensibles
- Borrar
/etc/ssh/ssh_host_*y cualquier clave SSH generada. - En Windows, ejecutar
Remove-Item -Path C:\Windows\System32\Sysprep\Panther\* -Recurse.
- Borrar
-
Promoción a plantilla aprobada
- Si todas las pruebas pasan, etiquetar la imagen con una versión y moverla a la librería de plantillas oficial.
- Registrar el hash de la plantilla y la fecha de aprobación en un archivo de auditoría.
Este enfoque es modular: cada paso puede ser implementado con scripts de Bash, PowerShell o Ansible, y se integra fácilmente en pipelines CI/CD (GitLab CI, GitHub Actions, Jenkins).
Código de ejemplo (bash)
#!/usr/bin/env bash
set -euo pipefail
TEMPLATE="local:templates/ubuntu-22.04-cloudinit"
CLONE_ID=$(pvesh get /cluster/nextid)
HOST="proxmox01"
# 1. Crear full clone
pvesh create /nodes/$HOST/qemu -vmid $CLONE_ID -name "test-clone-$(date +%s)" \
-clone $TEMPLATE -full 1 -memory 1024 -cores 1 -net0 virtio,bridge=vmbr0
# 2. Iniciar VM
pvesh create /nodes/$HOST/qemu/$CLONE_ID/status/start
# 3. Esperar a que el guest‑agent reporte IP (máx 300 s)
timeout 300 bash -c "
while true; do
IP=\$(pvesh get /nodes/$HOST/qemu/$CLONE_ID/agent/network-get-interfaces \
| jq -r '.result[] | select(.name==\"eth0\") | .ip-addresses[]?.ip-address')
[[ -n \$IP ]] && echo \$IP && break
sleep 5
done
"
# 4. Verificar SSH (Linux) o WinRM (Windows)
# ejemplo Linux:
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 user@$IP 'cloud-init status --wait'
# 5. Apagar y destruir clone
pvesh create /nodes/$HOST/qemu/$CLONE_ID/status/shutdown
pvesh delete /nodes/$HOST/qemu/$CLONE_ID
Cuándo aplicar esta solución
- Entornos de producción o staging donde la disponibilidad de la VM es crítica y cualquier fallo de arranque implica downtime.
- Plantillas multi‑tenant que se comparten entre equipos; la consistencia es obligatoria.
- Automatización con Packer/Terraform donde el proceso de build es parte de un pipeline CI/CD.
No es necesario aplicar este flujo completo en laboratorios personales o pruebas rápidas donde la tolerancia a fallos es alta y el coste de una clonación fallida es bajo.
Verificación
- Ejecutar el script de validación y observar que la salida muestra una IP y el mensaje
cloud-init status --waitfinaliza sin errores. - Confirmar que el guest‑agent reporta
agent=runningen la UI de Proxmox. - Verificar que los usuarios y claves esperados existen dentro de la VM.
- Revisar el log de
cloud-init(/var/log/cloud-init.log) para asegurarse de que no haya excepciones. - En Windows, abrir una sesión RDP y ejecutar
systeminfopara confirmar que elSystem Boot Timecorresponde al arranque del clone y que elProduct IDno está duplicado.
Si cualquiera de estos pasos falla, la plantilla debe volver al paso de build, corregir la causa raíz y repetir el ciclo.
Notas adicionales
- Persistencia de MAC: Proxmox asigna una MAC estática a la VM; si la plantilla la guarda, los clones pueden colisionar en la red. Configura
net0convirtio=00:00:00:00:00:00para que Proxmox genere una nueva MAC en cada clonación. - Desactivar cloud‑init en la plantilla: Añade
cloud_init: disableden la configuración de la plantilla y habilítalo solo en los clones mediante una variable de Terraform. - Versionado de plantillas: Usa etiquetas semánticas (
v1.2.0) y guarda el hash SHA256 del disco en un archivomanifest.json. Facilita auditorías y rollback. - Tiempo de espera: Los entornos con discos lentos pueden necesitar más de 300 s; ajusta el timeout según la infraestructura.
- Pruebas de carga: Si la VM será parte de un clúster (K8s, Elasticsearch), considera ejecutar un test de rendimiento básico después de la validación para detectar cuellos de botella de CPU o I/O.