Como profesional del software que maneja Infraestructura como Código (IaC), es probable que trabajes mucho con Terraform. Al ayudar a nuevos clientes a utilizar IaC, es común simplificar las cosas, pero gestionar un archivo de estado de Terraform es el primer desafío que enfrentas. Esencialmente, el estado de Terraform contiene información sensible, que no debería almacenarse en el control de versiones, pero, al mismo tiempo, no se escalará si tienes múltiples usuarios trabajando en el mismo estado de Terraform. ¿La solución a eso? Backends.
Es importante señalar que podrías almacenar ese archivo de estado en un bucket de S3 y utilizar DynamoDB para gestionar el estado de bloqueo. Sin embargo, este enfoque te obligará a crear recursos adicionales, lo que lo convierte en una opción complicada, especialmente si el cliente está utilizando GitLab. Recientemente, GitLab redujo la barrera de entrada para integrar Terraform al proporcionar una forma de almacenar y gestionar el estado de Terraform, así como una manera fácil de configurar un CI alrededor de él.
En este artículo, explicaremos qué es un archivo de estado de Terraform, cómo migrarlo a GitLab y cómo configurar un pipeline de CI para ello. Puedes visitar nuestro repositorio aquí.
Tabla de Contenidos
- ¿Qué es el Estado de Terraform?
- Cómo hacer que GitLab maneje el estado de Terraform
- Cómo hacer que GitLab ejecute tu IaC a través de un pipeline de CI
- Consejo Extra: Infracost
- Conclusión
¿Qué es el Estado de Terraform?
Terraform registra cualquier información sobre la infraestructura definida en tu código a través de un archivo de estado. Escrito en JSON, básicamente registra una asignación del código de Terraform a los recursos reales creados. A continuación, se muestra un ejemplo de cómo se vería un terraform.tfstate
. Principalmente, cada vez que ejecutas Terraform, obtendrá el estado más reciente para su instancia de EC2 y lo comparará con tu configuración de Terraform para determinar qué cambios deben aplicarse:
{
"version": 4,
"terraform_version": "0.12.0",
"serial": 1,
"lineage": "1f2087f9-4b3c-1b66-65db-8b78faafc6fb",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "aws_instance",
"name": "example",
"provider": "provider.aws",
"instances": [
{
"schema_version": 1,
"attributes": {
"ami": "ami-0c55b159cbfafe1f0",
"availability_zone": "us-west-2a",
"id": "i-00a123a0accffffff",
"instance_state": "running",
"instance_type": "t2.micro",
"(...)": "(truncated)"
}
}
]
}
]
}
Por defecto, este terraform.tfstate
se almacena localmente donde tienes tus archivos de Terraform, planeas y aplicas tus cambios. Para un proyecto personal donde solo estás ejecutando algunas pruebas; está bien, pero no es la forma recomendada, aquí está el porqué:
- Almacenado en una ubicación compartida: si estuvieras alojando este archivo de estado en tu estación de trabajo local y tuvieras que trabajar con otro ingeniero, las cosas se complicarían. Ambos tendrían que asegurarse de usar la versión más reciente del estado y podrías encontrarte con condiciones de carrera si ejecuto un plan de Terraform o aplico al mismo tiempo.
- Proteger información sensible: Un archivo de estado generado puede contener claves de cifrado e infraestructura contraseñas. Sin embargo, los archivos de estado no están cifrados de forma predeterminada, y almacenar información sensible en texto plano es una mala idea.
- Bloqueo: La mayoría de los sistemas de control de versiones no admiten ningún tipo de bloqueo, lo que evita que dos miembros del equipo ejecuten Terraform apply simultáneamente en el mismo archivo de estado. Esta es otra razón por la que no veremos un archivo de estado gestionado por el control de origen.
Cómo hacer que GitLab gestione el estado de Terraform
Considerando que Terraform es el estándar en la provisión de infraestructura en la nube, ha pasado un año aproximadamente desde que GitLab comenzó a ofrecer una forma de almacenar y gestionar el estado de Terraform. Por esta razón, queríamos compartir el proceso de migración contigo, ya que recientemente comenzamos a utilizar GitLab para gestionar nuestra IaC.
Para este artículo, suponemos que estás utilizando un estado local y que tienes tu estado gestionado con un Bucket S3 de AWS o con otra solución de backend.
En primer lugar, deberás cambiar tu backend.tf
para que use HTTP:
terraform {
backend "http" {}
}
A continuación, deberás configurar cuatro variables en tu terminal:
1. PROJECT_ID
: Puedes encontrarlo fácilmente navegando a tu repositorio en la página de “Información General del Proyecto”.
2. TF_USERNAME
: El nombre de usuario de GitLab que tiene acceso al repositorio en el que estás trabajando.
3. TF_PASSWORD
: Token de acceso generado desde tu usuario de GitLab.
4. TF_ADDRESS
: URL del backend de estado remoto.
PROJECT_ID="28450092"
TF_USERNAME="florianpialoux"
TF_PASSWORD="123456789"
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/aws-buckets"
Ahora puedes ejecutar el comando de migración que moverá tu estado de Terraform de su ubicación anterior a GitLab con el siguiente comando:
terraform init \
-migrate-state \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
Tendrás que proporcionar una confirmación con un “sí” para que GitLab pueda comenzar a gestionar tu archivo de estado. Aquí tienes un ejemplo de un estado local a GitLab:
Ejemplo de S3 a GitLab:

I noticed for some of the state files I had from S3 will be blank even after using the migrate-state
command ran previously. In this case, you can run this:
terraform state pull > aws-buckets.json
Copia y pega el contenido del estado de S3 y ejecuta un push:
terraform state push -lock=true aws-buckets.json
GitLab admite el control de versiones para el archivo de estado de Terraform, pero ver/restaurar versiones anteriores a través de la interfaz de usuario web requerirá que estés utilizando un plan Premium de GitLab. De no ser así, necesitarás realizar una solicitud a la API de GraphQL request.
Cómo hacer que GitLab ejecute tu IaC a través de un pipeline de CI
GitLab proporciona una imagen de Docker que contiene GitLab-Terraform, que es un script envolvente del binario oficial de Terraform. Alternativamente, podrías usar la imagen de Docker oficial de Hashicorp. Puedes encontrar más información sobre la Imagen de Terraform de GitLab aquí.
Una vez que se ejecute el trabajo de aplicar Terraform, podrás ver cuándo se utilizó el estado y con qué pipeline.
gitlab-ci.yml
looks like here. Below, are the variables that will need to be defined on the project level.Consejo adicional: Infracost
Como habrás notado, en nuestro gitlab-ci.yaml
agregamos Infracost, que nos permite tener mayor control sobre nuestra facturación en la nube ya que proporciona una estimación de costo cada vez que defines un nuevo recurso en tu IaC.
Conclusión
Tener tu estado de Terraform y tu CI funcionando en GitLab es una excelente manera de seguir las mejores prácticas de GitOps. Ambos forman una gran combinación para desarrollar y desplegar IaC. Dado que muchos de ustedes probablemente ya estén utilizando GitLab para sus repositorios, se vuelve mucho más sencillo tener su IaC bajo un mismo techo y dejar que GitLab maneje su estado de Terraform al respaldar la encriptación en tránsito y en reposo, así como la versión, bloqueo y desbloqueo del estado.
Source:
https://dzone.com/articles/how-to-migrate-terraform-state-to-gitlab-cicd