Terraform, la navaja suiza para dominar todos los IaaS

Hoy en día nos encontramos con grandes retos que afrontar en el mundo Cloud, como el escalado de las aplicaciones y la definición de una arquitectura válida para el servicio que pretendemos desplegar. Para ello y para otro tipo de problemas, nos encontramos con herramientas como Terraform, capaz de facilitarnos la codificación de una infraestructura dependiendo de nuestras necesidades, los servicios que tengamos que prestar y con una gran variedad de proveedores donde depositar nuestra infraestructura.

terraform1

¿Qué soluciones ofrece Terraform?

Cuanto más grande se vuelve un servicio, más complicado se hace la administración y la operación del mismo de manera manual. También puede suceder que exista un servicio particular que sea necesario para nuestra aplicación y que tenga que apoyarse en otro servicio existente en un proveedor de cloud distinto de donde estamos desplegando la aplicación, por tanto nos hace enfrentarnos a distintas consolas de administración o CLI diferentes para el aprovisionamiento, configuración y administración del servicio.

Si además pretendemos crear y destruir entornos bajo demanda en distintos clouds para una misma aplicación, puede convertirse en una tarea tediosa y corremos el peligro de no hacerlo de una forma predictiva.

La solución a todos estos problemas pasaría por disponer de una herramienta que nos permita modelar nuestra infraestructura como código, pero que sea agnóstica al entorno cloud donde se ejecute. Encontramos soluciones como CloudFormation de AWS o Heat de Openstack, pero estas herramientas están ligadas al cloud donde se desea desplegar. Sin embargo, Terraform nos permite codificar nuestra infraestructura atendiendo a las necesidades de nuestro servicio y ofreciendo un amplio abanico de proveedores donde desembarcar nuestra infraestructura.

Presentación1

 

Mediante ficheros de configuración que generamos en formato Json o en la sintaxis propuesta por Terraform (muy cercana al lenguaje natural), modelamos las necesidades de nuestra aplicación. Normalmente usaremos un fichero para definir nuestra arquitectura, una serie de variables para poder parametrizar nuestro despliegue y algunas variables de salida para obtener los datos más importantes nuestra infraestructura una vez desplegada (por ejemplo la IP de un ELB de AWS o el endpoint de RDS).

Una vez codificada nuestra infraestructura podemos hacer uso del comando terraform apply y comenzará el despliegue de nuestra infraestructura.

A continuación vamos a mostrar un ejemplo muy sencillo usando como proveedor Docker generando un fichero llamado main.tf:

#Config Docker provider

provider "docker" {
  host = "unix:///var/run/docker.sock"
}

resource "docker_container" "jenkins" {
    image = "${docker_image.jenkins.latest}"
    name = "terraform-demo"
    ports = {
       internal = 8080
       external = 8080
       internal = 5000
       external = 5000
       }
}

resource "docker_image" "jenkins" {
    name = "jenkins:latest"
}

Ejecutamos el comando terraform apply y observaremos como Terraform se encarga de generar los recursos definidos en nuestro fichero hasta llegar al estado objetivo:

>terraform apply
docker_image.jenkins: Refreshing state... (ID: sha256:d5c0410b1b443d3ed805078d498526590ae76fc42a1369bc814eb197f5ee102bjenkins:latest)
docker_container.jenkins: Refreshing state... (ID: 0904115a38630b0f8c7871da9eba9971c3a4ad67acb20d694ef20adc53225d5b)
docker_container.jenkins: Creating...
  bridge:                   "" => "<computed>"
  gateway:                  "" => "<computed>"
  image:                    "" => "sha256:d5c0410b1b443d3ed805078d498526590ae76fc42a1369bc814eb197f5ee102b"
  ip_address:               "" => "<computed>"
  ip_prefix_length:         "" => "<computed>"
  log_driver:               "" => "json-file"
  must_run:                 "" => "true"
  name:                     "" => "terraform-demo"
  ports.#:                  "" => "1"
  ports.376939551.external: "" => "5000"
  ports.376939551.internal: "" => "5000"
  ports.376939551.ip:       "" => ""
  ports.376939551.protocol: "" => "tcp"
  restart:                  "" => "no"
docker_container.jenkins: Creation complete

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

Tras la ejecución del comando hemos obtenido como resultado un contenedor con una imagen de jenkins y un fichero llamado terraform.tfstate. Dicho fichero almacena el estado actual de la infraestructura y es consultado por Terraform para obtener la información antes de aplicar nuevos cambios sobre la misma. Si borramos el fichero y volvemos a aplicar el plan, obtendremos un mensaje de error indicando que no puede aplicar los cambios:

Error applying plan:

1 error(s) occurred:

* docker_container.jenkins: Unable to create container: container already exists

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

Es por ello que para evitar problemas a la hora de lanzar cambios contra la infraestructura que:

  • O se incluya el fichero terraform.tfstate dentro del sistema de control de versiones.
  • Que los cambios se lleven a cabo desde un único punto o máquina para evitar que dos o más personas lancen cambios desde sitios distintos y con ficheros de state distinto.

Si en cualquier caso sucede que el fichero terraform.state contiene información que no se encuentra sincronizada con lo que se encuentra en la infraestructura, siempre podrá utilizarse el comando terraform refresh para reconciliar los datos del fichero terraform.state.

Otra herramienta que ofrece terraform es mostrar un diagrama con el plan de ejecución de la infraestructura. Para ello utilizamos el comando terraform graph:

digraph {
	compound = "true"
	newrank = "true"
	subgraph "root" {
		"[root] docker_container.jenkins" [label = "docker_container.jenkins", shape = "box"]
		"[root] docker_image.jenkins" [label = "docker_image.jenkins", shape = "box"]
		"[root] provider.docker" [label = "provider.docker", shape = "diamond"]
		"[root] docker_container.jenkins" -> "[root] docker_image.jenkins"
		"[root] docker_image.jenkins" -> "[root] provider.docker"
	}
}


Haciendo uso de dot de GraphViz podemos exportar nuestro diagrama en formato png usando el siguiente comando:

terraform graph | dot -Tpng > jenkinsDocker.png

terraform

Otra interesante funcionalidad es poder definir un provisionador asociado a otro recurso. De tal forma que podemos desplegar una máquina en un cloud y lanzar comandos para que se realice la instalación de los componentes software que pudiéramos llegar a necesitar en la misma. Puede, por ejemplo, ejecutarse una serie de comandos sobre el recurso recién creado para lanzar un playbook de ansible desplegado en otro repositorio de código para finalizar la instalación de la máquina.

Conclusión

En definitiva, Terraform es una herramienta muy interesante para poder llevar a cabo nuestros despliegues completos de un servicio sea cual sea su magnitud y complejidad. El hecho de poder tracerar los cambios de nuestra infraestructura en un sistema de control de versiones, hace que sea más sencillo observar la evolución de nuestro servicio, poder controlar los cambios que hayan hecho mejorar o empeorar el rendimiento del mismo e incluso poder trasladar una solución arquitectónica de un servicio completo para otro proyecto de similares características.

También reduce costes y tiempo derivados de la operación y mantenimiento del servicio, ya que se necesita menos esfuerzo para controlar una infraestructura compleja.

Por último, Terraform es un gran aliado para construir nuestros pipelines de integración y despliegue continuo, ya que podemos automatizar todos los procesos de generación y destrucción de entornos, tanto efímeros como persistentes, para pruebas o para llevar hasta producción los cambios realizados en nuestras infraestructuras.

Ingeniero de Sistemas en Paradigma. Tengo más de seis años de experiencia como administrador de sistemas, pasando desde la operación de servicios hasta modelado de arquitecturas. He participado en todo tipo de proyectos de virtualización, cloud, aplicaciones de patrón reactivo como Node.js y Vert.x y como administrador certificado de MongoDB. Apasionado por las nuevas tecnologías actuales y las que están por venir. No soy un 'devops' al uso, me siento más a gusto con el término 'sysdev'.

Ver toda la actividad de Ernesto Valero Marcelo

Recibe más artículos como este

Recibirás un email por cada nuevo artículo.. Acepto los términos legales

Posts relacionados

Escribe un comentario