Cómo desplegar múltiples entornos en tu proyecto Terraform sin duplicar código

El autor seleccionó el Fondo de Código Abierto y Gratuito para recibir una donación como parte del programa Escribir por Donaciones.

Introducción

Terraform ofrece características avanzadas que se vuelven cada vez más útiles a medida que tu proyecto crece en tamaño y complejidad. Es posible aliviar el costo de mantener definiciones de infraestructura complejas para múltiples entornos estructurando tu código para minimizar las repeticiones e introduciendo flujos de trabajo asistidos por herramientas para un más fácil prueba y despliegue.

Terraform asocia un estado con un backend, lo que determina dónde y cómo se almacena y recupera el estado. Cada estado tiene solo un backend y está vinculado a una configuración de infraestructura. Ciertos backends, como local o s3, pueden contener múltiples estados. En ese caso, la asociación de estado e infraestructura al backend describe un espacio de trabajo. Los espacios de trabajo te permiten desplegar múltiples instancias distinctas de la misma configuración de infraestructura sin almacenarlas en backends separados.

En este tutorial, primero desplegarás varias instancias de infraestructura utilizando diferentes áreas de trabajo. Luego, desplegarás un recurso con estado, que en este tutorial será un Volumen de DigitalOcean. Finalmente, harás referencia a módulos prehechos desde el Registro de Terraform, que puedes utilizar para complementar los tuyos.

Requisitos previos

Para completar este tutorial, necesitarás:

  • Un Token de Acceso Personal de DigitalOcean, que puedes crear a través del Panel de Control de DigitalOcean. Puedes encontrar instrucciones en la documentación del producto de DigitalOcean, Cómo crear un Token de Acceso Personal.
  • Terraform instalado en tu máquina local y un proyecto configurado con el proveedor DO. Completa Paso 1 y Paso 2 del tutorial Cómo utilizar Terraform con DigitalOcean, y asegúrate de nombrar la carpeta del proyecto terraform-advanced, en lugar de loadbalance. Durante Paso 2, no incluyas la variable pvt_key y el recurso de clave SSH.

Nota: Este tutorial ha sido específicamente probado con Terraform 1.0.2.

Desplegando múltiples instancias de infraestructura utilizando áreas de trabajo

Las múltiples áreas de trabajo son útiles cuando desea desplegar o probar una versión modificada de su infraestructura principal sin necesidad de crear un proyecto separado y configurar nuevamente las claves de autenticación. Una vez que ha desarrollado y probado una característica utilizando un estado separado, puede incorporar el nuevo código al área de trabajo principal y posiblemente eliminar el estado adicional. Cuando usted init un proyecto de Terraform, independientemente del backend, Terraform crea un área de trabajo llamada default. Esta siempre está presente y nunca puede eliminarla.

Sin embargo, las múltiples áreas de trabajo no son una solución adecuada para crear múltiples entornos, como los de staging y producción. Por lo tanto, las áreas de trabajo, que solo rastrean el estado, no almacenan el código ni sus modificaciones.

Como las áreas de trabajo no rastrean el código real, debería gestionar la separación del código entre múltiples áreas de trabajo a nivel de control de versiones (VCS) mediante la correspondencia con sus variantes de infraestructura. Cómo lograr esto depende de la herramienta VCS en sí; por ejemplo, en las ramas de Git sería una abstracción adecuada. Para facilitar la gestión del código para múltiples entornos, puede dividirlos en módulos reutilizables, de modo que evite repetir código similar para cada entorno.

Implementación de Recursos en Áreas de Trabajo

Ahora creará un proyecto que implemente una Droplet, que aplicará desde múltiples áreas de trabajo.

Almacenará la definición de la Droplet en un archivo llamado droplets.tf.

Asumiendo que está en el directorio terraform-advanced, cree y abra para edición ejecutando:

  1. nano droplets.tf

Agregue las siguientes líneas:

resource "digitalocean_droplet" "web" {
  image  = "ubuntu-18-04-x64"
  name   = "web-${terraform.workspace}"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

Esta definición creará una Droplet que ejecuta Ubuntu 18.04 con un núcleo de CPU y 1 GB de RAM en la región fra1. Su nombre contará con el nombre del área de trabajo actual desde el que se implementa. Cuando haya terminado, guarde y cierre el archivo.

Aplica el proyecto para Terraform para ejecutar sus acciones con:

  1. terraform apply -var "do_token=${DO_PAT}"

La salida se verá similar a esto:

Output
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.web será creado + resource "digitalocean_droplet" "web" { + backups = false + created_at = (known after apply) + disk = (known after apply) + id = (known after apply) + image = "ubuntu-18-04-x64" + ipv4_address = (known after apply) + ipv4_address_private = (known after apply) + ipv6 = false + ipv6_address = (known after apply) + ipv6_address_private = (known after apply) + locked = (known after apply) + memory = (known after apply) + monitoring = false + name = "web-default" + price_hourly = (known after apply) + price_monthly = (known after apply) + private_networking = (known after apply) + region = "fra1" + resize_disk = true + size = "s-1vcpu-1gb" + status = (known after apply) + urn = (known after apply) + vcpus = (known after apply) + volume_ids = (known after apply) + vpc_uuid = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy. ...

Ingresa yes cuando se te pida para desplegar el Droplet en el espacio de trabajo default.

El nombre del Droplet será web-default, porque el espacio de trabajo con el que empiezas se llama default. Puedes listar los espacios de trabajo para confirmar que es el único disponible:

  1. terraform workspace list

La salida se verá similar a esto:

Output
* default

La asterisco (*) indica que actualmente tienes ese espacio de trabajo seleccionado.

Crea y cambia a un nuevo espacio de trabajo llamado testing, que usarás para desplegar un Droplet diferente, ejecutando workspace new:

  1. terraform workspace new testing

La salida se verá similar a esto:

Output
Created and switched to workspace "testing"! You're now on a new, empty workspace. Workspaces isolate their state, so if you run "terraform plan" Terraform will not see any existing state for this configuration.

Planifica la implementación del Droplet nuevamente ejecutando:

  1. terraform plan -var "do_token=${DO_PAT}"

La salida será similar a la ejecución anterior:

Output
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.web será creado + resource "digitalocean_droplet" "web" { + backups = false + created_at = (known after apply) + disk = (known after apply) + id = (known after apply) + image = "ubuntu-18-04-x64" + ipv4_address = (known after apply) + ipv4_address_private = (known after apply) + ipv6 = false + ipv6_address = (known after apply) + ipv6_address_private = (known after apply) + locked = (known after apply) + memory = (known after apply) + monitoring = false + name = "web-testing" + price_hourly = (known after apply) + price_monthly = (known after apply) + private_networking = (known after apply) + region = "fra1" + resize_disk = true + size = "s-1vcpu-1gb" + status = (known after apply) + urn = (known after apply) + vcpus = (known after apply) + volume_ids = (known after apply) + vpc_uuid = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy. ...

Observa que Terraform planea desplegar un Droplet llamado web-testing, que ha nombrado diferente de web-default. Esto es porque los espacios de trabajo default y testing tienen estados separados y no tienen conocimiento de los recursos entre sí —aunque provienen del mismo código.

Para confirmar que estás en el espacio de trabajo testing, salida el actual en el que estás con workspace show:

  1. terraform workspace show

La salida será el nombre del espacio de trabajo actual:

Output
testing

Para eliminar un espacio de trabajo, primero necesitas destruir todas sus recursos implementados. Luego, si está activo, necesitas cambiar a otro usando workspace select. Como el espacio de trabajo testing aquí está vacío, puedes cambiar inmediatamente a default:

  1. terraform workspace select default

Recibirás la salida de Terraform confirmando el cambio:

Output
Switched to workspace "default".

Luego, puedes eliminarlo ejecutando workspace delete:

  1. terraform workspace delete testing

Terraform luego realizará la eliminación:

Output
Deleted workspace "testing"!

Puedes destruir el Droplet que has implementado en el espacio de trabajo default ejecutando:

  1. terraform destroy -var "do_token=${DO_PAT}"

Ingresa yes cuando se le pida para finalizar el proceso.

En esta sección, has trabajado en varios espacios de trabajo de Terraform. En la sección siguiente, implementarás un recurso con estado.

Implementación de Recursos con Estado

Los recursos sin estado no almacenan datos, por lo que puedes crear y reemplazarlos rápidamente porque no son únicos. Por otro lado, los recursos con estado contienen datos que son únicos o no se pueden recrear simplemente; por lo tanto, requieren un almacenamiento de datos persistente.

Como puedes terminar destruyendo tales recursos o varios recursos requieren de sus datos, es mejor almacenarlos en una entidad separada, como Volúmenes DigitalOcean.

Los volúmenes proporcionan espacio de almacenamiento adicional. Pueden adjuntarse a las Droplet (servidores), pero son independientes de ellos. En este paso, definirás el Volumen y lo conectarás a una Droplet en droplets.tf.

Abrelo para edición:

  1. nano droplets.tf

Añade las siguientes líneas:

resource "digitalocean_droplet" "web" {
  image  = "ubuntu-18-04-x64"
  name   = "web-${terraform.workspace}"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

resource "digitalocean_volume" "volume" {
  region                  = "fra1"
  name                    = "new-volume"
  size                    = 10
  initial_filesystem_type = "ext4"
  description             = "New Volume for Droplet"
}

resource "digitalocean_volume_attachment" "volume_attachment" {
  droplet_id = digitalocean_droplet.web.id
  volume_id  = digitalocean_volume.volume.id
}

Aquí definirás dos recursos nuevos, el propio Volumen y un acoplamiento de Volumen. El Volumen será de 10GB, formateado como ext4, llamado new-volume, y situado en la misma región que la Droplet. Como el Volumen y la Droplet son entidades separadas, necesitarás definir un objeto de acoplamiento de Volumen para conectarlas. volume_attachment toma los ID de Droplet y Volumen y instruye a la nube DigitalOcean para que haya un Volumen disponible para la Droplet como un dispositivo de disco.

Cuando hayas terminado, guarda y cierra el archivo.

Planifica esta configuración ejecutando:

  1. terraform plan -var "do_token=${DO_PAT}"

Las acciones que Terraform planificará serán las siguientes:

Output
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.web se creará + resource "digitalocean_droplet" "web" { + backups = false + created_at = (known after apply) + disk = (known after apply) + id = (known after apply) + image = "ubuntu-18-04-x64" + ipv4_address = (known after apply) + ipv4_address_private = (known after apply) + ipv6 = false + ipv6_address = (known after apply) + ipv6_address_private = (known after apply) + locked = (known after apply) + memory = (known after apply) + monitoring = false + name = "web-default" + price_hourly = (known after apply) + price_monthly = (known after apply) + private_networking = (known after apply) + region = "fra1" + resize_disk = true + size = "s-1vcpu-1gb" + status = (known after apply) + urn = (known after apply) + vcpus = (known after apply) + volume_ids = (known after apply) + vpc_uuid = (known after apply) } # digitalocean_volume.volume se creará + resource "digitalocean_volume" "volume" { + description = "New Volume for Droplet" + droplet_ids = (known after apply) + filesystem_label = (known after apply) + filesystem_type = (known after apply) + id = (known after apply) + initial_filesystem_type = "ext4" + name = "new-volume" + region = "fra1" + size = 10 + urn = (known after apply) } # digitalocean_volume_attachment.volume_attachment se creará + resource "digitalocean_volume_attachment" "volume_attachment" { + droplet_id = (known after apply) + id = (known after apply) + volume_id = (known after apply) } Plan: 3 to add, 0 to change, 0 to destroy. ...

Los detalles de salida que Terraform crearía un Droplet, un Volumen y un acoplamiento de Volumen, que conecta el Volumen con la Droplet.

Ahora has definido y conectado un Volumen (un recurso estado) a una Droplet. En la sección siguiente, revisarás módulos Terraform públicos y prediseñados que puedes incorporar en tu proyecto.

Referenciar módulos pre-hechos

Además de crear tus propios módulos personalizados para tus proyectos, también puedes usar módulos pre-hechos y proveedores de otros desarrolladores, que están disponibles públicamente en Registro de Terraform.

En la sección de módulos puedes buscar en la base de datos de módulos disponibles y ordenar por proveedor para encontrar el módulo con la funcionalidad necesaria. Una vez que lo hayas encontrado, puedes leer su descripción, que enumera las entradas y salidas que proporciona el módulo, así como sus dependencias externas de módulo y proveedor.

Ahora agregarás el módulo de clave SSH de DigitalOcean the tu proyecto. Guardarás el código separado de las definiciones existentes en un archivo llamado ssh-key.tf. Crea y abre para edición ejecutando:

  1. nano ssh-key.tf

Añade las siguientes líneas:

module "ssh-key" {
  source         = "clouddrove/ssh-key/digitalocean"
  key_path       = "~/.ssh/id_rsa.pub"
  key_name       = "new-ssh-key"
  enable_ssh_key = true
}

Este código define una instancia del módulo clouddrove/droplet/digitalocean del registro y establece algunos de los parámetros que ofrece. Debería agregar una clave pública SSH a su cuenta leyéndola desde ~/.ssh/id_rsa.pub.

Cuando haya terminado, guarde y cierre el archivo.

Antes de planear este código, debe descargar el módulo referenciado ejecutando:

  1. terraform init

Recibirá una salida similar a la siguiente:

Output
Initializing modules... Downloading clouddrove/ssh-key/digitalocean 0.13.0 for ssh-key... - ssh-key in .terraform/modules/ssh-key Initializing the backend... Initializing provider plugins... - Reusing previous version of digitalocean/digitalocean from the dependency lock file - Using previously-installed digitalocean/digitalocean v2.10.1 Terraform has been successfully initialized! ...

Ahora puede planear el código para los cambios:

  1. terraform plan -var "do_token=${DO_PAT}"

Recibirá una salida similar a esta:

Output
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: ... # module.ssh-key.digitalocean_ssh_key.default[0] will be created + resource "digitalocean_ssh_key" "default" { + fingerprint = (known after apply) + id = (known after apply) + name = "devops" + public_key = "ssh-rsa ... demo@clouddrove" } Plan: 4 to add, 0 to change, 0 to destroy. ...

La salida muestra que crearía la recurso de clave SSH, lo que significa que descargó e invocó el módulo de su código.

Conclusión

Los proyectos mayores pueden hacer uso de algunas características avanzadas que ofrece Terraform para reducir la complejidad y hacer más fácil el mantenimiento. Los workspaces le permiten probar nuevas adiciones a su código sin tocar las implementaciones principales estables. También puede combinar workspaces con un sistema de control de versiones para rastrear cambios en el código. El uso de módulos prefabricados también puede reducir el tiempo de desarrollo, pero puede incurrir gastos adicionales o tiempo en el futuro si el módulo se vuelve obsoleto.

Este tutorial es parte de la serie Cómo gestionar infraestructura con Terraform. La serie cubre varios temas de Terraform, desde instalar Terraform por primera vez hasta la gestión de proyectos complejos.

Source:
https://www.digitalocean.com/community/tutorials/how-to-deploy-multiple-environments-with-workspaces-in-your-terraform-project