Ansible Proxmox: Automatiza VMs y Contenedores LXC 2026

Ansible Proxmox aprovisionando máquinas virtuales y contenedores LXC

Con Ansible Proxmox dejas de crear máquinas virtuales a golpe de ratón en la interfaz web y pasas a definirlas en un fichero YAML. Diez máquinas idénticas en dos minutos, con sus recursos, su red y su clave SSH ya puesta, y la garantía de que la número diez es exactamente igual que la primera.

Es la combinación que más rendimiento da en un homelab y en infraestructura pequeña: el hipervisor libre por debajo, y la automatización declarativa por encima.

Qué necesitas para empezar con Ansible Proxmox

Los módulos de Ansible Proxmox viven en una colección propia. Durante años estuvieron dentro de community.general, y todavía encontrarás tutoriales que la usan; hoy la forma correcta es instalar la colección específica.

ansible-galaxy collection install community.proxmox
pip install proxmoxer requests

Esa biblioteca de Python es imprescindible: es la que habla realmente con la API del hipervisor, y su ausencia es el primer error que verás si te la saltas. Va instalada en el nodo de control, no en el servidor de virtualización.

Conviene entender bien esa arquitectura porque rompe la intuición de quien viene de usar Ansible con SSH. Aquí no hay conexión a los servidores gestionados: los playbooks se ejecutan contra localhost y hablan por HTTPS con la API del hipervisor, que es quien realmente crea y destruye las máquinas. Solo cuando quieras configurar el sistema operativo dentro de esas máquinas entrará en juego el SSH de toda la vida.

Por eso verás en todos los ejemplos hosts: localhost y gather_facts: false: recopilar hechos de la máquina local no aporta nada y solo hace más lenta la ejecución.

Crear un token de API

Antes de escribir nada en Ansible Proxmox, prepara las credenciales. Usar la contraseña de root en los playbooks funciona, pero es una mala idea: un token es revocable y se le pueden acotar los permisos.

# En el nodo Proxmox
pveum user add automatizacion@pve
pveum aclmod / -user automatizacion@pve -role PVEAdmin
pveum user token add automatizacion@pve ansible --privsep 0

El comando devuelve un identificador y un secreto que solo se muestran una vez: cópialos ya. Guárdalos cifrados con Ansible Vault, igual que hacemos con el resto de secretos en el flujo de gestión de credenciales con Vault.

ansible-vault create group_vars/all/proxmox.yml
pve_host: 192.168.1.10
pve_user: automatizacion@pve
pve_token_id: ansible
pve_token_secret: el-secreto-que-te-dio-el-comando
pve_node: pve01

Crear máquinas virtuales con Ansible Proxmox

La vía práctica en Ansible Proxmox no es instalar desde una ISO, que es lenta y requiere interacción, sino clonar desde una plantilla de nube. Prepara una vez la plantilla con cloud-init y a partir de ahí todo es instantáneo.

---
- name: Aprovisionar maquinas virtuales
  hosts: localhost
  gather_facts: false
  vars_files:
    - group_vars/all/proxmox.yml

  tasks:
    - name: Clonar desde plantilla
      community.proxmox.proxmox_kvm:
        api_host: "{{ pve_host }}"
        api_user: "{{ pve_user }}"
        api_token_id: "{{ pve_token_id }}"
        api_token_secret: "{{ pve_token_secret }}"
        node: "{{ pve_node }}"
        clone: plantilla-debian13
        newid: "{{ item.vmid }}"
        name: "{{ item.nombre }}"
        full: true
        storage: local-lvm
        timeout: 300
        state: present
      loop:
        - { vmid: 201, nombre: web01 }
        - { vmid: 202, nombre: web02 }
        - { vmid: 203, nombre: base-datos }

Cada elemento del bucle crea una máquina completa. El parámetro full: true hace una copia independiente; si lo pones en false obtienes un clon enlazado, que ocupa muchísimo menos pero depende de la plantilla para siempre.

El siguiente paso es ajustar recursos y datos de arranque. Aquí es donde Ansible Proxmox se separa de verdad del trabajo manual: la configuración de red y el usuario inicial se inyectan solos.

    - name: Configurar recursos y cloud-init
      community.proxmox.proxmox_kvm:
        api_host: "{{ pve_host }}"
        api_user: "{{ pve_user }}"
        api_token_id: "{{ pve_token_id }}"
        api_token_secret: "{{ pve_token_secret }}"
        node: "{{ pve_node }}"
        vmid: "{{ item.vmid }}"
        cores: 2
        memory: 4096
        net:
          net0: 'virtio,bridge=vmbr0'
        ipconfig:
          ipconfig0: 'ip={{ item.ip }}/24,gw=192.168.1.1'
        ciuser: admin
        sshkeys: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
        update: true
      loop:
        - { vmid: 201, ip: 192.168.1.201 }
        - { vmid: 202, ip: 192.168.1.202 }
        - { vmid: 203, ip: 192.168.1.203 }

    - name: Arrancar las maquinas
      community.proxmox.proxmox_kvm:
        api_host: "{{ pve_host }}"
        api_user: "{{ pve_user }}"
        api_token_id: "{{ pve_token_id }}"
        api_token_secret: "{{ pve_token_secret }}"
        node: "{{ pve_node }}"
        vmid: "{{ item }}"
        state: started
      loop: [201, 202, 203]

Fíjate en update: true: sin él, el módulo no modifica una máquina que ya existe. Es el motivo más común de «he cambiado la memoria en el playbook y no pasa nada».

Contenedores LXC con Ansible Proxmox

En Ansible Proxmox, para servicios que no necesitan núcleo propio, los contenedores del sistema arrancan en segundos y consumen una fracción de la memoria. El módulo es distinto y bastante más directo.

    - name: Crear contenedor LXC
      community.proxmox.proxmox:
        api_host: "{{ pve_host }}"
        api_user: "{{ pve_user }}"
        api_token_id: "{{ pve_token_id }}"
        api_token_secret: "{{ pve_token_secret }}"
        node: "{{ pve_node }}"
        vmid: 301
        hostname: proxy-inverso
        ostemplate: 'local:vztmpl/debian-13-standard_13.0-1_amd64.tar.zst'
        cores: 1
        memory: 512
        disk: 8
        netif: '{"net0":"name=eth0,ip=192.168.1.31/24,gw=192.168.1.1,bridge=vmbr0"}'
        pubkey: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
        unprivileged: true
        state: present

Deja siempre unprivileged: true salvo que tengas un motivo concreto para no hacerlo: un contenedor privilegiado comparte el usuario root con el anfitrión y reduce mucho el aislamiento. La excepción típica son los contenedores que necesitan montar recursos del anfitrión o usar aceleración por hardware, y aun ahí conviene agotar antes otras vías.


Inventario dinámico en Ansible Proxmox

Con Ansible Proxmox, mantener a mano una lista de máquinas que creas y destruyes constantemente no tiene sentido. El complemento de inventario consulta la API y construye los grupos solo. El fichero debe terminar en .proxmox.yml para que Ansible sepa qué complemento usar.

# inventario.proxmox.yml
plugin: community.proxmox.proxmox
url: https://192.168.1.10:8006
user: automatizacion@pve
token_id: ansible
token_secret: "{{ lookup('env', 'PVE_TOKEN') }}"
validate_certs: false
want_facts: true
exclude_nodes: false

groups:
  produccion: "'pro' in (proxmox_tags_parsed | default([]))"
  contenedores: "proxmox_type == 'lxc'"
  maquinas: "proxmox_type == 'qemu'"

Compruébalo antes de usarlo en serio. Verás las máquinas agrupadas por estado, tipo y etiquetas.

ansible-inventory -i inventario.proxmox.yml --graph
ansible -i inventario.proxmox.yml maquinas -m ping

Este es el punto donde Ansible Proxmox deja de ser una comodidad y pasa a ser infraestructura seria: etiquetas puestas en el hipervisor se convierten en grupos, y esos grupos reciben la configuración que les toca. Es la misma idea que ya vimos aplicada a la nube en el artículo de inventario dinámico multi-cloud.

Encadenar aprovisionamiento y configuración con Ansible Proxmox

El flujo completo de Ansible Proxmox tiene dos mitades: crear la máquina y luego configurarla. La transición entre ambas requiere esperar a que el SSH esté disponible.

    - name: Esperar a que responda SSH
      ansible.builtin.wait_for:
        host: "{{ item.ip }}"
        port: 22
        delay: 10
        timeout: 300
      loop:
        - { ip: 192.168.1.201 }
        - { ip: 192.168.1.202 }

    - name: Anadir al inventario en memoria
      ansible.builtin.add_host:
        name: "{{ item.nombre }}"
        ansible_host: "{{ item.ip }}"
        groups: recien_creadas
      loop:
        - { nombre: web01, ip: 192.168.1.201 }
        - { nombre: web02, ip: 192.168.1.202 }

A partir de ahí, otra tanda del playbook actúa sobre recien_creadas y aplica lo que necesites: endurecimiento del sistema, instalación de Docker con su hardening, o el cortafuegos UFW configurado. La máquina nace y queda lista sin intervención manual en ningún punto.

Instantáneas y ciclo de vida con Ansible Proxmox

Una vez que las máquinas se crean solas, el siguiente paso natural es gestionar también lo que les pasa después. Hay un módulo específico para instantáneas que encaja muy bien antes de cualquier cambio arriesgado.

    - name: Instantanea previa a la actualizacion
      community.proxmox.proxmox_snap:
        api_host: "{{ pve_host }}"
        api_user: "{{ pve_user }}"
        api_token_id: "{{ pve_token_id }}"
        api_token_secret: "{{ pve_token_secret }}"
        vmid: "{{ item }}"
        snapname: "antes-parches-{{ ansible_date_time.date }}"
        description: "Creada por el playbook de mantenimiento"
        state: present
      loop: [201, 202, 203]

El patrón que mejor funciona es encadenar tres bloques en el mismo playbook: instantánea, actualización del sistema, y borrado de la instantánea si todo ha ido bien. Así nunca se te quedan instantáneas olvidadas comiendo disco, que es el efecto secundario clásico de hacerlo a mano.

Merece la pena insistir en eso porque en virtualización es un problema real: una instantánea no es una copia de seguridad, es un punto de retorno temporal. Cuanto más vieja sea, más crece el fichero de diferencias y más penaliza el rendimiento de la máquina. Si tu playbook las crea, que también las borre.

Para consultar el estado del parque sin modificar nada, los módulos de información son la herramienta adecuada. Devuelven datos que puedes usar para condicionar tareas posteriores o simplemente para generar un inventario en un informe.

    - name: Consultar maquinas del nodo
      community.proxmox.proxmox_vm_info:
        api_host: "{{ pve_host }}"
        api_user: "{{ pve_user }}"
        api_token_id: "{{ pve_token_id }}"
        api_token_secret: "{{ pve_token_secret }}"
        node: "{{ pve_node }}"
      register: parque

    - name: Mostrar las apagadas
      ansible.builtin.debug:
        msg: "{{ parque.proxmox_vms | selectattr('status','equalto','stopped') | map(attribute='name') | list }}"

Ese tipo de consulta es la base para automatismos más útiles: avisar de máquinas apagadas que deberían estar arriba, detectar identificadores duplicados o encontrar las que nadie ha etiquetado todavía.


Buenas prácticas con Ansible Proxmox

  • Rangos de identificadores por entorno. Reserva el 100-199 para pruebas, el 200-299 para producción y así. Un identificador repetido da un error poco claro.
  • Etiquetas desde el primer día. Son lo que alimenta los grupos del inventario dinámico; ponerlas después es un trabajo tedioso.
  • Certificado válido en el hipervisor. Usar validate_certs: false es cómodo en el laboratorio y desaconsejable en cualquier otro sitio.
  • Cuidado con state: absent. Borra la máquina y su disco sin preguntar nada. Revisa dos veces los bucles que lo usen.
  • Prueba los roles antes. Un playbook que crea infraestructura merece pasar por Molecule igual que cualquier otro.

Problemas frecuentes con Ansible Proxmox

SíntomaCausaSolución
proxmoxer is requiredFalta la bibliotecapip install proxmoxer en el control
Error de autenticaciónFormato del usuarioDebe incluir el reino: usuario@pve
Los cambios no se aplicanFalta update: trueAñadirlo a la tarea
El inventario sale vacíoNombre del ficheroDebe acabar en .proxmox.yml
Sin IP tras el clonPlantilla sin cloud-initAñadir la unidad de cloud-init a la plantilla

El último es el fallo de Ansible Proxmox que más tiempo hace perder. Una plantilla sin soporte de cloud-init ignora por completo la configuración de red e usuario que le mandas, y la máquina arranca sin dirección. Prepara la plantilla bien una vez y te olvidas para siempre.

Conclusión sobre Ansible Proxmox

El beneficio real de Ansible Proxmox no es la velocidad, aunque también. Es que la infraestructura pasa a estar descrita en un fichero versionado: sabes qué tienes, por qué está ahí y puedes reconstruirlo desde cero si un disco decide morirse un domingo.

Empieza tu Ansible Proxmox por una plantilla con cloud-init y un playbook que cree una sola máquina. Cuando funcione, el salto a bucles e inventario dinámico es cuestión de una tarde. Tienes la referencia en la documentación de la colección, el detalle del módulo en la página de proxmox_kvm, el complemento de inventario en su documentación, la API en el visor oficial de Proxmox y el código en el repositorio de la colección.

Preguntas frecuentes sobre Ansible Proxmox

¿Necesito instalar algo en el hipervisor?

No. Toda la comunicación va por la API en el puerto 8006 desde el nodo de control. En el servidor de virtualización solo hay que crear el usuario y el token.

¿Funciona con un clúster de varios nodos?

Sí. Indicas el nodo destino en cada tarea y puedes repartir la carga con una variable. El inventario dinámico descubre las máquinas de todo el clúster, no solo las de un servidor.

¿Mejor máquinas virtuales o contenedores LXC?

Contenedores para servicios sencillos que compartan núcleo con el anfitrión: arrancan antes y consumen mucho menos. Máquinas virtuales cuando necesites otro sistema operativo, núcleo propio o aislamiento fuerte.

¿Cómo evito borrar algo por accidente?

Acota los permisos del token a lo que realmente necesites en lugar de dar administración total, y ejecuta primero en modo comprobación. Para tareas destructivas, exige confirmación explícita con una variable adicional.

¿Sirve también con Terraform?

Se pueden combinar: Terraform crea las máquinas y Ansible las configura. En un homelab, sin embargo, hacerlo todo con playbooks suele resultar más sencillo, porque evitas mantener un estado adicional.

Avatar

Por Mid

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x
()
x