Trabajar con módulos de Terraform II

0
6785
Centro cloud con discos duros conectados en paralelo y luz azul.

Índice

1. Introducción

En el tutorial anterior, explicamos el concepto de módulo en Terraform y cómo podíamos utilizar módulos ya existentes para crear nuestra infraestructura en la nube de una forma más rápida y sencilla. En esta ocasión, veremos cómo podemos crear nuestros propios módulos.

Pero, ¿por qué estructurar nuestro código de Terraform en módulos? Es una forma para no repetirnos (DRY). Podemos reutilizar el mismo módulo en varios entornos de la misma aplicación o incluso en distintas aplicaciones. Tan sólo cambiarán los parámetros de configuración para cada caso.

2. Requisitos

Los requisitos para la realización de este tutorial son los mismos que para el anterior: tener instalado Terraform y contar con una cuenta de AWS. Revisa los tutoriales enlazados para más información.

3. Ampliación de la infraestructura

Vamos a partir de la infraestructura que habíamos definido en el tutorial anterior, donde teníamos una VPC con dos instancias EC2. Ahora queremos aprovisionar también un bucket de S3 y queremos definir algunos objetos en él. Como hicimos la vez anterior, buscamos algún módulo en el registro de Terraform y encontramos este módulo para S3. Sin embargo, al comprobar los inputs que permite, nos damos cuenta de algo: no nos ofrece la posibilidad de definir objetos en el bucket.

Parece que tendremos que trabajar un poco más de lo que pensábamos. Podríamos optar por aprovisionar directamente los recursos, pero no sabemos cuándo podemos necesitar otro bucket para un entorno diferente o incluso para otra aplicación. Estaría bien poder aprovechar el esfuerzo que vamos a invertir en el futuro.

Finalmente, optamos por crear nuestro propio módulo. Pero, en vez de hacerlo desde cero, reutilizaremos el trabajo que ya nos dan hecho en el módulo que hemos encontrado. Como vimos en el tutorial anterior, los módulos de Terraform pueden entenderse como librerías, las cuales podemos envolver unas dentro de otras, en una arquitectura de capas que nos abstraiga de los detalles a la hora de utilizarlos.

4. Organización de los módulos

Nos disponemos a crear nuestro módulo, pero… ¿cómo lo hacemos? La primera cuestión que debemos tener en cuenta es la naturaleza de los módulos. Como hemos dicho, pueden asimilarse a librerías y podemos compartirlos incluso entre diferentes aplicaciones. Esto ya debería darnos una pista: no debemos incluir nuestros módulos junto con el resto de nuestro código de infraestructura.

Pero, más importante todavía, es que quizás querramos cambiar en un futuro la implementación de nuestro módulo. Sería un desastre que, mientras estemos haciendo pruebas de esos cambios, alguien decida actualizar la infraestructura de alguna aplicación que lo utilice. Es muy importante que versionemos nuestro módulo, cosa que conseguiremos gracias a las tags de GIT.

Podemos crear un repositorio por cada módulo, por cada proveedor de nube o incluso para todos nuestros módulos. Dependiendo de cual sea el caso, tendremos que sumar o restar niveles a la siguiente estructura de directorios:

  • /proveedor_de_nube (aws, azure…)
    • /categoría (storage, database, compute, networking…)
      • /módulo

Si sólo tenemos un módulo por repositorio, entonces no hará falta ninguna estructura de directorios.

Recordando lo dicho en el tutorial anterior, un módulo es sólo un conjunto de ficheros de Terraform dentro del mismo directorio. No hay ninguna sintaxis ni nomenclatura especial. Podríamos llamarlos y organizarlos como quisiéramos. Sin embargo, en pos de evitar el caos, facilitar su legibilidad y mantenibilidad, vamos a seguir la siguiente estructura de ficheros:

  • locals.tf: Contiene valores que podemos reutilizar en otros ficheros del módulo, pero no fuera de él.
  • data.tf: Define data sources en caso de que necesitemos acceder a alguna propiedad de la infraestructura de nube.
  • vars.tf: Define las variables que serán usadas como inputs del módulo.
  • outputs.tf: Define los valores que el módulo ofrece como salida y que pueden ser consultados por otros módulos.
  • main.tf: Contiene el código que aprovisiona los recursos en la nube.

Una vez que tenemos claro todo esto, vamos a crear nuestro módulo.

5. Creación del módulo

Lo primero que hacemos es crear nuestro repositorio. En este caso, voy a optar por la opción de un único repositorio para todos los módulos. Lo llamaremos ‘my-terraform-modules’. Lo configuramos igual que el repositorio del tutorial anterior.

Una vez lo tenemos clonado en nuestro equipo, creamos la estructura de directorios siguiente:

  • /aws
    • /storage
      • /s3-bucket

En este último directorio es en el que vamos a crear nuestros ficheros de Terraform, tal como hemos descrito en el apartado anterior. Para simplificarlo, vamos a darle una interfaz de inputs y outputs más restringida, añadiendo los objetos a crear.

# inputs.tf

variable "bucket" {
    description = "(Optional, Forces new resource) The name of the bucket. If omitted, Terraform will assign a random, unique name."
    type = string
}

variable "acl" {
    description = "(Optional) The canned ACL to apply. Defaults to 'private'."
    type = string
    default = "private"
}

variable "tags" {
    description = "(Optional) A mapping of tags to assign to the bucket."
    type = map(string)
    default = {}
}

variable "versioning" {
    description = "Map containing versioning configuration."
    type = map(string)
    default = {}
}

variable "bucket_objects" {
    description = "A list of objects to create in the bucket."
    type = list(string)
    default = []
}
# outputs.tf

output "s3_bucket_arn" {
    description = "The ARN of the bucket. Will be of format arn:aws:s3:::bucketname."
    value = module.this.this_s3_bucket_arn
}

output "s3_bucket_bucket_domain_name" {
    description = "The bucket domain name. Will be of format bucketname.s3.amazonaws.com."
    value = module.this.this_s3_bucket_bucket_domain_name
}

output "s3_bucket_id" {
description = "The name of the bucket."
value = module.this.this_s3_bucket_id
}
# main.tf

module "this" {
  source = "terraform-aws-modules/s3-bucket/aws"

  bucket = var.bucket
  acl = var.acl
  versioning = var.versioning
tags = var.tags
}

resource "aws_s3_bucket_object" "bucket_object" {
count = length(var.bucket_objects)

 bucket = module.this.this_s3_bucket_id
key = var.bucket_objects[count.index]
}
  • Definimos como inputs un listado de keys para los objetos que queremos crear en el bucket.
  • En main.tf, asociamos objetos al bucket que creamos con el módulo del registro de Terraform, utilizando un bucle con la longitud de la lista que pasamos como parámetro.Consolidamos los cambios y los subimos al repositorio. Además, creamos una tag para versionar los módulos:
    git commit
    git push origin main
    git tag -a v1.0
    git push origin v1.0

Dejo aquí el repositorio de módulos que he creado para la ocasión.

6. Utilizar nuestro módulo

Ahora vamos a utilizar este módulo desde el repositorio que teníamos en el tutorial anterior, ‘my-modular-infrastructure’. La tag v1.0 contiene el código al final del tutorial anterior, mientras que la v2.0 contiene el código al finalizar este tutorial.

Creamos el fichero bucket.tf y utilizamos los inputs que hemos creado en nuestro módulo para configurar el bucket:

    # bucket.tf

    module "bucket" {
        source = "git@github.com:FJavierEstrada/my-terraform-modules.git//aws/storage/s3-bucket?ref=v1.0"

        bucket = "javier-estrada-tutorial-bucket"
        bucket_objects = ["img", "doc", "www"]
    }
  • El query param ‘ref’ permite elegir la versión del módulo que vamos a usar. En este caso, la misma tag que definimos antes.
  • Nótese que cuando el repositorio contiene varios módulos, es necesario especificar la ruta del módulo, separándolo de la URL del repositorio mediante dos barras (//).
  • El valor del parámetro bucket es global para todos los usuarios de AWS, de modo que es conveniente que sea bastante específico. Si no, dará error.

Ya sólo queda ejecutar Terraform para aprovisionar la infraestructura. Veremos cómo ahora también se detallan los recursos del bucket en el plan. Es necesario ejecutar de nuevo ‘init’ debido a que hemos introducido nuevos módulos y tendrá que descargarlos para utilizarlos.

        export AWS_PROFILE=my_profile
        terraform init
        terraform apply

Por último, después de comprobar que todo ha ido bien, destruimos la infraestructura para no consumir ningún recurso.

        terraform destroy

7. Conclusión

Los módulos de Terraform nos permiten crear la infraestructura de un modo más sencillo y rápido. Además, nos permiten reutilizar a lo largo de varios entornos o aplicaciones nuestro código. Sólo tenemos que cambiar los parámetros adecuados para obtener los resultados que deseamos.

Además, podemos envolver módulos ya existentes en otros con una interfaz más sencilla o que añadan una capa extra de configuración para la infraestructura. Lo único que necesitamos es colocarlos en un repositorio y versionarlos.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad