Clase 5: OpenTofu + libvirt - Creación de escenarios
¿Qué vas a aprender en esta clase?
- Creación de escenarios con OpenTofu.
- Configuración de máquinas virtuales con cloud-init
Teoría
En OpenTofu, un módulo es un conjunto de archivos de configuración que agrupan recursos relacionados, de forma que puedan reutilizarse, organizarse y parametrizarse fácilmente.
Qué es un módulo
Un módulo es, esencialmente, una unidad lógica de infraestructura que encapsula uno o más recursos de OpenTofu. El directorio raíz de un proyecto de OpenTofu ya es un módulo implícito (llamado root module), y puedes crear módulos adicionales en subdirectorios o reutilizar módulos externos (por ejemplo, del OpenTofu Registry).
Para qué sirve
- Reutilización: permite definir una infraestructura una sola vez y usarla en múltiples entornos (desarrollo, pruebas, producción).
- Organización: ayuda a estructurar configuraciones grandes en partes más manejables.
- Estandarización: garantiza que recursos similares (por ejemplo, una red o una máquina virtual) se creen siempre de forma coherente.
Variables
Los módulos suelen definir variables de entrada (variable "nombre" { ... }) que permiten parametrizar su comportamiento sin modificar su código interno.
También pueden exportar valores mediante outputs (output "nombre" { ... }) para que otros módulos o el módulo raíz los utilicen.
Las variables permiten que un mismo módulo sirva para múltiples escenarios simplemente cambiando los valores de entrada.
Analogía con funciones
Sí, puede asimilarse a una función en un lenguaje de programación:
- Las variables de entrada son como los parámetros de la función.
- Los outputs son como los valores de retorno.
- La lógica interna del módulo describe los recursos que se crearán, análogamente al código del cuerpo de la función.
Llamar a un módulo desde otro archivo es como invocar una función con argumentos específicos.
Ejercicios
Seguimos trabajando con el repositorio de ejemplos: https://github.com/josedom24/opentofu-libvirt/.
Ejemplo 4: Máquina virtual conectada a dos redes: una con DHCP y otra con direccionamiento estático
En este ejemplo seguimos trabajando con redes. En esta ocasión vamos a aprender a configurar una interfaz de red de forma estática.
En el fichero networks.tf:
- Se crea una red NAT con DHCP con el recurso
resource "libvirt_network" "nat_dhcp". - Se crea un red aislada sin DHCP, con el recurso
resource "libvirt_network" "aislada-static". Estudia los parámetro que hemos indicado.
Recuerda: el hecho de que conectemos una máquina virtual a dos redes no significa que netplan configure las dos interfaces. Tenemos que configurarlo nosotros, para ello:
- Creamos el fichero
cloud-init/server1/network-config.yamldonde guardaremos la configuración netplan de la máquina, en este ejemplo puedes observar como se ha configurado de forma estárica. Si fuera necesario podríamos indicar la puerta de enlace, el servidor DNS o cualquier otra configuración de red que necesitemos. - Recuerda que añadimos este fichero en la imagen ISO junto al fichero
cloud-init/server1/user-data.yaml. Esto se hace con el parámetronetwork_configdel recursoresource "libvirt_cloudinit_disk" "server1-cloudinit"en el ficheromain.tf.
¿Qué tienes que realizar?
- Configura tu escenario de forma adecuada para crear una máquina virtual con debian13. Ejecuta la configuración del ejemplo 4 y comprueba que efectivamente las dos interfaces están configuradas. ¿Puedes hacer ping a la dirección que hemos configurado de forma estática?. Razona la respuesta. Destruye el escenario,
- Crea una nueva red muy aislada y cambia la configuración para conectar la máquina virtual a esta red. Configúrala con una dirección en el direccionamiento
172.16.0.0/16. ¿Puedes hacer ping a esta dirección que hemos configurado?. Razona la respuesta. Destruye el escenario.
Ejemplo 5: Dos máquinas virtuales conectadas entre sí
En este ejemplo vamos a comenzar a crear escenarios, es decir a crear varias máquinas interconectadas. En este ejemplo concreto tenemos dos máquinas que están conectadas entre sí, para conseguirlo tenemos los siguientes ficheros:
main1.tfymain2.tf: en cada uno de estos ficheros está la definición de una máquina.- Dentro del directorio
cloud-inittenemos dos directorios, para guardar eluser-data.yamly elnetwork-config.yamlpara configurar cada una de las máquinas. - El fichero
outputse ha modificado para que devuelva información de cada máquina.
En este ejemplo, el primer servidor está conectado a una red NAT y una red muy aislada. El segundo servidor se conecta sólo a la red muy aislada.
Limitación de esta solución para crear escenarios:
- Es muy repetitiva, tenemos que crear los siguientes ficheros según el número de máquinas que queremos. Si queremos crear un escenario con 3 máquinas:
- Tenemos que crear 3 ficheros
mainX.tf. - Tenemos que crear 3 directorios
cloud-init/serverXpara guardar la configuración cloud-init de cada máquina. - Tenemos que modificar el fichero
output.tfpara mostrar información de las 3 máquinas.
- Tenemos que crear 3 ficheros
¿Qué tienes que realizar?
- Configura tu escenario de forma adecuada para crear las máquinas virtuales del ejemplo 5. Accede a la primera por ssh y comprueba que puedes hacer ping a la segunda. Accede de forma adecuada por ssh a la primera máquina para desde ella acceder a la segunda. Destruye el escenario.
- Modifica lo necesario para crear otra máquina conectada a la red muy aislada. Comprueba que todo funciona de manera adecuada. Destruye el escenario.
Ejemplo 6: Generados de escenarios con módulos
Para solucionar el problema del ejemplo anterior. en este ejemplo vamos a usar módulos de OpenTofu para generar máquinas virtuales y redes.
Los módulos se encuentra en el directorio fuera del directorio de trabajo, de esta forma podremos reutilizarlos en distintos proyectos. En nuestro ejemplo, los módulos están guardaos en el directorio /terraform/modules/. Tenemos dos módulos:
/terraform/modules/vm: Contendrá todos los ficheros necesarios para crear máquinas virtuales según los parámetros que le mandemos./terraform/modules/network: Contendrá todos los ficheros necesarios para crear redes según los parámetros que le mandemos.
Estudiemos lo ficheros más importantes:
- En el fichero
main.tfvemos como utilizamos los dos módulos:- El módulo
networkcrea una red, por tanto se recorre la declaración de las variables (for_each = local.networks) donde definimos las redes que queremos crear y se van creando cada una de ellas. - El módulo
mvcrea una máquina virtual, por tanto se recorre la declaración de las variables (for_each = local.servers) donde definimos las máquinas virtuales que queremos crear y se van creando cada una de ellas. Por ejemplo para usar el módulomodules/mv:module "server" { source = "../../terraform/modules/vm"
- El módulo
- En el fichero
escenario.tfdefinimos las variables de las redes y de las máquinas virtuales que queremos crear:local.networkses una lista de diccionario, en cada uno de ellos se definen las variables necesarias para crear una red:name: El nombre de la red que se crea en libvirt.mode: Tipo de red. El valor para la red de tipo nat, esnat, para las redes aisladas y muy aisladas,noney para la red públicabridge.domain: El nombre de dominio que envía el servidor DHCP.adresses: Si es necesario, el direccionamiento de la red.bridge: El nombre del bridge que se crea.dhcp:trueofalsesegún activemos el servidor DHCP.dns:trueofalsesegún activemos el servidor DNS.autostart:trueofalsesegún activemos el inicio automática de la red.
local.serverses una lista de diccionarios donde definimos las variables necesarias para crear cada máquina virtual:name: El nombre de la máquina virtual que se crea en libvirt.memory: Memoria de la máquina.vcpu: Número de núcleos virtuales de la máquina.base_image: Nombre de la imagen base desde la que se crea el volumen de la máquina virtual.network: Es un diccionario donde se definen las redes a las que está conectada la máquina. Para cada red se indica:network_name: Nombre de la red a la que está conectada.wait_for_lease = true: Esta opción se indica si la red tiene activo el servidor DHC.
disks: Es un diccionario donde se definen los discos que tiene la máquina. Para cada disco se indica:name: Nombre del disco.size: Tamaño del disco.
user_data: Directorio donde se encuentra el fichero de configuraciónuser_data.yaml.network_config: Directorio donde se encuentra el fichero de configuraciónnetwork-config.yaml.
¿Qué tienes que entregar?
- Configura tu escenario de forma adecuada para crear las máquinas virtuales del escenario del ejeemplo6. Accede a la primera por ssh y comprueba que puedes hacer ping a la segunda. Accede de forma adecuada por ssh a la primera máquina para desde ella acceder a la segunda. Destruye el escenario.
- Crea una nueva red de tipo NAT y crea un nuevo servidor con Ubuntu que esté conectado a esa red y a la red aislada. Accede a esa máquina y comprueba qsu direccionamiento y que puede hacer ping a las otras dos máquinas. Destruye el escenario.