Durante mucho tiempo mis VMs de Proxmox fueron construidas a mano. Pasaba por el instalador a base de clics, añadía mi usuario, pegaba una clave SSH, instalaba el guest agent y, para cuando llegaba a la siguiente VM, ya se me había olvidado la mitad. Funcionaban. Simplemente no eran reproducibles, y no podría decirte qué diferencia había entre dos máquinas que construí con un mes de separación.
Una plantilla cloud-init resuelve la mayor parte de eso. Este post explica cómo estoy construyendo una a partir de una imagen cloud oficial, usando la CLI qm para que cada paso pueda vivir en un script en Git. No llevo mucho tiempo con esta configuración, así que tómalo como un método que funciona. Señalaré las partes de las que no estoy seguro.
Si todavía no tienes un host Proxmox donde probarlo, el laboratorio Install Proxmox VE cubre la instalación base.
Practicarás la instalación de Proxmox VE en dos SSD en espejo con ZFS y la asignación de una dirección fija al host.
Por qué una imagen cloud y no una VM clonada
La alternativa habitual es instalar una VM a mano, dejarla ordenada y convertirla en plantilla. Funciona, pero la plantilla arrastra cualquier estado que hayas dejado atrás: host keys, machine ID, historial del shell, algún paquete suelto. Limpiar todo eso es una checklist en sí misma, y prefiero no tener que mantenerla.
Una imagen cloud oficial parte limpia. Espera que cloud-init la configure en el primer arranque: usuario, claves SSH, red, hostname. Proxmox puede suministrar esos valores a través de una unidad cloud-init virtual. La plantilla se mantiene genérica y cada clon recibe su identidad en el momento de crearse.
La contrapartida es que renuncias al instalador gráfico y tienes que saber de antemano lo que quieres. Para mí eso es una ventaja. La lista de lo que quiero es justo la documentación que siempre me prometo escribir.
Construir la plantilla
Aquí uso la imagen cloud de Ubuntu. Cualquier distro que publique una imagen cloud funciona de la misma manera. Ejecuta esto en el nodo de Proxmox. El ID de la VM, el nombre del storage y el bridge son los míos, así que cámbialos por los tuyos.
cd /var/lib/vz/template/iso
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
qm create 9000 --name ubuntu-2404-ci \
--memory 2048 --cores 2 \
--net0 virtio,bridge=vmbr0 \
--ostype l26 --agent enabled=1
qm importdisk 9000 noble-server-cloudimg-amd64.img local-zfs
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-zfs:vm-9000-disk-0
qm set 9000 --ide2 local-zfs:cloudinit
qm set 9000 --boot order=scsi0
qm set 9000 --serial0 socket --vga serial0
Algunas notas sobre por qué está cada pieza:
importdiskconvierte la imagen descargada en un disco de VM en tu storage. Las versiones más recientes de Proxmox también tienenqm disk import. Comprueba qué soporta tu versión.- La unidad
cloudinitenide2es donde Proxmox escribe los ajustes de usuario, clave y red que cloud-init lee al arrancar. - La consola serie está ahí porque muchas imágenes cloud esperan una. Sin ella, he visto que la consola web no muestra nada útil. No estoy seguro de que sea imprescindible en todas las imágenes.
Todavía no la conviertas. Primero, ocúpate del guest agent.
El problema del guest agent
La imagen cloud no incluye qemu-guest-agent. Sin él, Proxmox no puede ver la dirección IP de la VM, y los apagados limpios y el quiescing en los backups son menos fiables. Podría instalarlo a mano y convertir el resultado, pero eso devuelve el problema de la plantilla construida a mano.
En su lugar, uso un snippet de vendor-data que cloud-init aplica en el primer arranque:
#cloud-config
package_update: true
packages:
- qemu-guest-agent
runcmd:
- systemctl enable --now qemu-guest-agent
Guárdalo como /var/lib/vz/snippets/vendor.yaml. Los snippets necesitan un storage de tipo directorio con el tipo de contenido Snippets habilitado. El storage local por defecto puede hacerlo, pero un storage sobre ZFS como local-zfs no puede almacenar snippets. Después adjúntalo:
qm set 9000 --cicustom "vendor=local:snippets/vendor.yaml"
qm template 9000
Una advertencia para clusters: ese archivo de snippet está en el storage local de un solo nodo. Si un clon cae en un nodo que no lo tiene, el clon no arrancará. Todavía no he decidido cómo manejarlo. Las opciones que veo son copiar el archivo a todos los nodos desde el mismo script, o poner los snippets en un storage compartido. Copiar es más simple, así que me inclino por eso.
Clonar con ajustes
La plantilla contiene lo que es común. Cada clon añade lo que es específico:
qm clone 9000 120 --name devvm --full
qm set 120 --ciuser priya --sshkeys ~/.ssh/lab_keys.pub
qm set 120 --ipconfig0 ip=dhcp
qm resize 120 scsi0 32G
qm start 120
El flag --sshkeys recibe un archivo con claves públicas. Solo las claves públicas van a la VM. No configuro ninguna contraseña, así que no hay nada que pueda filtrarse ni que rotar. Si quieres una dirección estática, --ipconfig0 ip=10.0.20.50/24,gw=10.0.20.1 lo hace. Yo prefiero una reserva DHCP, ya que mantiene el direccionamiento en un solo lugar.
Tras uno o dos minutos, qm guest cmd 120 network-get-interfaces debería devolver datos una vez que el agente esté activo. Si da timeout, probablemente el agente todavía no está en marcha, o el snippet de vendor no se aplicó.
Qué comprobaría antes de fiarme de ella
Una plantilla que arranca no es lo mismo que una plantilla correcta. Esta es mi checklist corta después de cada reconstrucción:
- Entrar por SSH con la clave y confirmar que el acceso con contraseña está desactivado.
- Confirmar que el hostname coincide con el nombre de la VM, no con el de la plantilla.
- Revisar
cloud-init status --longen busca de errores. - Confirmar que el guest agent está en ejecución y que Proxmox muestra la IP.
- Asegurarse de que dos clones no comparten machine ID:
cat /etc/machine-iden ambos.
El último punto es la razón por la que elegí una imagen cloud. También es el que menos me gustaría descubrir por las malas.
Llevarlo a Git
La idea es justamente que nada de esto viva en mi cabeza. Los comandos de construcción van en un único script de shell, el snippet de vendor está junto a él, y ambos están en un commit. Reconstruir la plantilla pasa a ser: borrar la VM 9000 y ejecutar el script. Todavía no lo he integrado en Ansible. Ese es el siguiente paso, y espero que sea más molesto que la versión en shell, ya que los módulos de Proxmox requieren gestionar credenciales de API. Me gustaría saber si vale la pena para un flujo de trabajo de un nodo a la vez.
De qué no estoy seguro
- Actualizaciones de la imagen. La imagen
currentse reemplaza upstream. Quiero fijarla o al menos registrar un checksum para que una reconstrucción sea realmente el mismo build. No he decidido cómo. - Deriva de la plantilla. Los clones no se actualizan cuando se actualiza la plantilla. Trato las VMs como desechables, con los datos en un storage aparte, así que reconstruir es más barato que parchear un linaje de plantillas. No estoy seguro de que eso valga para todas las VMs que ejecuto.
- Comportamiento en cluster. Solo lo he probado en un nodo a la vez.
¿Cómo lo manejas tú? ¿Construyes plantillas con la CLI qm, Terraform, Packer o algo distinto? Y ¿fijaste tus imágenes base, o las dejas flotar y lidias con las sorpresas?
Have a question about this guide?
Create a free account to ask the community and join the discussion. Members who run the real thing answer every day.
