¿Qué son los módulos Terraform y cómo funcionan?

Sorprendentemente, muchos principiantes se saltan los módulos de Terraform en aras de la simplicidad, o eso creen.

Más tarde, se encuentran pasando por cientos de líneas de código de configuración.

Supongo que ya conoce algunos de los conceptos básicos sobre Terraform, e incluso ha intentado usarlo antes. De lo contrario, consulte esta descripción general de Terraform y este video tutorial antes de continuar leyendo.

Tenga en cuenta: no utilizo ejemplos de código real con algún proveedor específico como AWS o Google intencionalmente, solo por simplicidad.

Módulos terraform

Ya escribes módulos

Incluso cuando no crea un módulo intencionalmente, si usa Terraform, ya está escribiendo un módulo, un módulo llamado " raíz ".

Cualquier archivo de configuración de Terraform ( .tf) en un directorio, incluso solo uno, forma un módulo.

¿Qué hace un módulo?

Un módulo Terraform le permite crear abstracción lógica en la parte superior de algún conjunto de recursos. En otras palabras, un módulo le permite agrupar recursos y reutilizar este grupo más tarde, posiblemente muchas veces.

Supongamos que tenemos un servidor virtual con algunas funciones alojadas en la nube. ¿Qué conjunto de recursos podría describir ese servidor? Por ejemplo:

  • la propia máquina virtual, creada a partir de alguna imagen
  • un dispositivo de bloque adjunto de un tamaño específico para almacenamiento adicional
  • una IP pública estática asignada a la interfaz de red virtual del servidor
  • un conjunto de reglas de firewall que se adjuntarán al servidor
  • otras cosas como otro dispositivo de bloque, interfaz de red adicional, etc.

Ahora supongamos que necesita crear este servidor con un conjunto de recursos muchas veces. Aquí es donde los módulos son realmente útiles: no desea repetir el mismo código de configuración una y otra vez, ¿verdad?

Aquí hay un ejemplo que ilustra cómo podría llamarse nuestro módulo "servidor".

" Llamar a un módulo " significa usarlo en el archivo de configuración.

Aquí creamos 5 instancias del "servidor" usando un solo conjunto de configuraciones (en el módulo):

module "server" { count = 5 source = "./module_server" some_variable = some_value }

Organización del módulo: hijo y raíz

Por supuesto, probablemente desee crear más de un módulo. A continuación, se muestran algunos ejemplos comunes:

  • una red como una nube privada virtual (VPC)
  • alojamiento de contenido estático (es decir, depósitos)
  • un equilibrador de carga y sus recursos relacionados
  • una configuración de registro
  • o cualquier otra cosa que considere un componente lógico distinto de la infraestructura

Digamos que tenemos dos módulos diferentes: un módulo de "servidor" y un módulo de "red". El módulo llamado "red" es donde definimos y configuramos nuestra red virtual y colocamos servidores en ella:

module "server" { source = "./module_server" some_variable = some_value } module "network" { source = "./module_network" some_other_variable = some_other_value }

Una vez que tenemos algunos módulos personalizados, podemos referirnos a ellos como módulos "secundarios". Y el archivo de configuración al que llamamos módulos secundarios se relaciona con el módulo raíz.

Un módulo hijo puede obtenerse de varios lugares:

  • caminos locales
  • el registro oficial de Terraform: si está familiarizado con otros registros como el registro de Docker, entonces ya comprende la idea
  • un repositorio de Git (uno personalizado o GitHub / BitBucket)
  • una URL HTTP a un archivo .zip con el módulo

Pero, ¿cómo se pueden pasar los detalles de los recursos entre módulos?

En nuestro ejemplo, los servidores deben crearse en una red. Entonces, ¿cómo podemos decirle al módulo "servidor" que cree máquinas virtuales en una red que se creó en un módulo llamado "red"?

Aquí es donde entra la encapsulación .

Encapsulación de módulo

La encapsulación en Terraform consta de dos conceptos básicos: alcance del módulo y exposición explícita a los recursos.

Alcance del módulo

Todas las instancias de recursos, los nombres y, por lo tanto, la visibilidad de los recursos, están aislados en el alcance de un módulo. Por ejemplo, el módulo "A" no puede ver y no conoce los recursos del módulo "B" de forma predeterminada.

La visibilidad de los recursos, a veces denominada aislamiento de recursos, garantiza que los recursos tengan nombres únicos dentro del espacio de nombres de un módulo. Por ejemplo, con nuestras 5 instancias del módulo "servidor":

module.server[0].resource_type.resource_name module.server[1].resource_type.resource_name module.server[2].resource_type.resource_name ...

Por otro lado, podríamos crear dos instancias del mismo módulo con diferentes nombres:

module "server-alpha" { source = "./module_server" some_variable = some_value } module "server-beta" { source = "./module_server" some_variable = some_value }

En este caso, la denominación o dirección de los recursos sería la siguiente:

module.server-alpha.resource_type.resource_name module.server-beta.resource_type.resource_name

Exposición explícita a los recursos

Si desea acceder a algunos detalles de los recursos en otro módulo, deberá configurarlo explícitamente.

De forma predeterminada, nuestro módulo "servidor" no conoce la red que se creó en el módulo "red".

Así que debemos declarar un outputvalor en el módulo "red" para exportar su recurso, o un atributo de un recurso, a otros módulos.

El módulo "servidor" debe declarar un variablepara ser utilizado más tarde como entrada:

This explicit declaration of the output is the way to expose some resource (or information about it) outside — to the scope of the 'root' module, hence to make it available for other modules.

Next, when we call the child module "server" in the root module, we should assign the output from the "network" module to the variable of the "server" module:

network_id = module.network.network_id

Here's what the final code for calling our child modules will look like:

module "server" { count = 5 source = "./module_server" some_variable = some_value network_id = module.network.network_id } module "network" { source = "./module_network" some_other_variable = some_other_value }

This example configuration would create 5 instances of the same server, with all the necessary resources, in the network we created with as a separate module.

Wrapping up

Now you should understand what modules are and what do they do.

If you're at the beginning of your Terraform journey, here are some suggestions for the next steps.

I encourage you to take this short tutorial from HashiCorp, the creators of Terraform, about modules: "Organize Configuration".

Also, there is a great comprehensive study guide which covers everything from beginner to advanced concepts about Terraform: "Study Guide - Terraform Associate Certification".

The modular code structure makes your configuration more flexible and yet easy to be understood by others. The latter is especially useful for a team.

If you liked the article, follow me on Twitter (@vasylenko) where I occasionally share my findings and tips about Terraform, AWS, Ansible, and other DevOps-related technologies.