En esta ocasión, nos centraremos en cómo automatizar despliegues de máquinas virtuales en una infraestructura on-premise operada con Proxmox. Usaremos Ansible tanto para comunicarnos con Proxmox como para hacer la configuración de la máquina después del despliegue.
Escenario previo
Para poder poner en práctica la automatización, es deseable tener configurado un escenario que cuente con VLANs configuradas, un servidor de DHCP en cada una de las VLANs y una zona DNS con actualización dinámica por DHCP (RFC 2136).
En nuestro caso, tenemos configurado Pfsense como firewall y servidor DHCP de las dos VLANs:
- VLAN001: red de gestión donde se encontrarán los servicios publicados a todas las redes. En nuestro caso, solo necesitamos el servidor DNS con Bind9.
- VLAN002: red de despliegue donde crearemos las nuevas máquinas.
Para mayor información sobre estas configuraciones, consultar los enlaces correspondientes:
Por último, debemos tener disponibles plantillas de máquinas virtuales. En nuestro caso, solo usaremos plantillas de Ubuntu y Debian. A partir de estas plantillas, el automatismo podrá generar las nuevas máquinas virtuales. Para más información, consultar el siguiente enlace.
Creación y borrado de máquinas virtuales con proxmox-ansible
Para esta automatización, hemos preparado el repositorio proxmox-ansible. Se trata de un role de Ansible que realiza acciones concretas en función de la variable action
. Concretamente, este role permite realizar dos acciones que nos interesan en este momento:
-
create_vm
: Clona de una máquina virtual a partir de una plantilla existente. Para más información, accede aquí. -
delete_vm
: Borra una máquina virtual. Para más información, accede aquí.
Para usar este role, tenemos dos opciones:
- Clonar el repositorio en
~/.ansible/roles/
e instalar las dependencias que aparecen en el ficherorequirements.txt
. - Ejecutar el playbook desde la imagen de docker
atorrescogollo/proxmox-ansible:latest
.
En este caso, usaremos la imagen de docker del siguiente modo:
- Creamos el playbook
create_vm.yml
indicando la acción y los parámetros que requiere:$ cat create_vm.yml - name: Create VM hosts: localhost roles: - role: proxmox-ansible vars: action: create_vm proxmox_host: 10.0.0.2:8006 proxmox_user: user@pam proxmox_pass: password vm_name: testvm01 cpu_sockets: 1 cpu_cores: 1 ram_mb: 2048 disk_gb: 20 datastore: ds01 vlan: 2 template_name: TEMPLATE-UBUNTU-SERVER-20-04 proxmox_node: proxmoxnode01
- Ejecutamos el role montando el fichero de playbook como un volumen:
$ docker run --rm \ -v "$PWD/create_vm.yml:/playbook.yml" \ atorrescogollo/proxmox-ansible:latest
Por otro lado, el borrado de la máquina, se podría ejecutar de igual forma pero usando el playbook delete_vm.yml
:
$ cat delete_vm.yml - name: Delete VM hosts: localhost roles: - role: proxmox-ansible vars: action: delete_vm proxmox_host: 10.0.0.2:8006 proxmox_user: user@pam proxmox_pass: password vm_name: testvm01
$ docker run --rm \ -v "$PWD/delete_vm.yml:/playbook.yml" \ atorrescogollo/proxmox-ansible:latest
Configuración tras despliegue con linux-ansible
Una vez ya podemos crear máquinas de forma automatizada, necesitamos realizar algunas configuraciones. Por ejemplo, queremos adecuar los volumenes lógicos de LVM, actualizar el nombre del host según el nombre de la máquina virtual, actualizar los paquetes de la máquina, etc.
Todas las configuraciones para máquinas Linux forman parte de otro role de Ansible disponible en el repositorio linux-ansible y, de igual modo, podemos configurar la máquina que acabamos de desplegar. El procedimiento, en este caso, es ligeramente distinto ya que necesitamos un inventario:
- Creamos el playbook
post_deploy.yml
:$ cat post_deploy.yml - name: Configure VM hosts: vms roles: - role: linux-ansible vars: action: post_deploy lvmap: "/tmp": "+500M" "/var/log": "2G" "/var": "+30%FREE" "/": "+100%FREE" install_packages: - vim - tmux
Similar a lo que vimos anteriormente, estos parámetros se pueden consultar en este enlace. En esta documentación, además, se indica que la acción post_deploy simplemente es una agrupación de acciones, por lo que podemos personalizar nuestro despliegue en función de lo que necesitemos. - Creamos el fichero de inventario:
$ cat inventory.ini [vms] testvm01.example.org ansible_host=10.0.2.150 [vms:vars] ansible_user=adminuser ansible_ssh_extra_args='-o StrictHostKeyChecking=no'
Es importante definir la IP ya que la plantilla aún no tiene el hostname correcto por lo que el DNS no ha registrado ese hostname. Además, el usuario con el que nos vamos a conectar necesita tener acceso con sudo sin contraseña para realizar las tareas que requieren ciertos privilegios. - Ejecutamos el role usando la imagen de docker
atorrescogollo/linux-ansible:latest
:$ ssh-add ~/.ssh/id_rsa # Cargar la clave privada en ssh-agent $ docker run -it --rm \ -v $SSH_AUTH_SOCK:/ssh-agent \ -e SSH_AUTH_SOCK=/ssh-agent \ -v $PWD/inventory.ini:/inventory \ -v $PWD/post_deploy.yml:/playbook.yml \ atorrescogollo/linux-ansible:latest
Cabe destacar que, en este caso, hemos tenido que compartir elssh-agent
con el contenedor a través de la variable de entornoSSH_AUTH_SOCK
para poder usar la clave privada cargada conssh-add
. Para más información sobre esta característica, acceder a este enlace.
Conclusiones
Hemos logrado estandarizar el proceso de creación y configuración de máquinas virtuales. Esto nos permite definir políticas de bastionado, configuraciones comunes en todo el entorno, etc, que se aplicarán en todos los despliegues.
También, hemos propuesto un tratamiento distinto al modelo estándar de roles de Ansible. En este caso, cada role agrupa todas las automatizaciones realizacionadas con un ámbito concreto usando la variable action. Por ejemplo, proxmox-ansible
es el role que trata todos los procedimientos de interacción con nuestro hipervisor y linux-ansible
es el role que define todos los procedimientos de configuración de máquinas Linux.
Por otro lado, cabe mencionar que existen otros mecanismos para ejecutar la configuración de una máquina después del despliegue: suele ser la opción más usada. Esto no quiere decir que la fase de configuración de la máquina sea completamente reemplazable por cloud-init
. Habiendo implementado el role linux-ansible
tenemos dos posibilidades:
- Ejecutar el role desde fuera de la máquina, como hemos presentado.
- Ejecutar el role en local dentro de la máquina con
cloud-init
.
Por tanto, Ansible nos aporta, principalmente, dos beneficios con respecto a otras opciones:
- Versatilidad en los modos de configuración: una vez se definen las tareas, solo hace falta indicar sobre qué máquinas ejecutar el automatismo.
- Facilidad de mantenimiento: la complejidad debe residir en el módulo de Ansible (en la mayoría de casos, ya mantenido por la comunidad) para que las tareas, roles y playbooks sean fáciles de interpretar.
Sabiendo esto, ¿te atreves a automatizar tu infraestructura?
Álvaro Torres Cogollo.
Quieres contactar conmigo? Te dejo mis redes sociales a continuación.