En los artículos anteriores vimos cómo Terraform permite definir infraestructura como código.
También vimos que, después de ejecutar Terraform, aparece un archivo llamado:
terraform.tfstate
¿Qué es exactamente?
¿Por qué Terraform necesita guardar información sobre los recursos que creó?
Y quizás la pregunta más importante: ¿Por qué no alcanza con mirar nuestra configuración .tf?
La respuesta está en uno de los conceptos fundamentales de Terraform: el State.
Supongamos que tenemos:
resource "local_file" "hello" {
filename = "hello.txt"
content = "Hola!"
}
Ejecutamos:
terraform apply
Terraform crea:
hello.txt
Hasta acá todo parece sencillo.
Pero imaginemos que mañana ejecutamos nuevamente:
terraform apply
Terraform tiene que decidir: "¿Tengo que crear el archivo otra vez?"
La respuesta es no.
Terraform necesita saber que ese recurso ya existe y está siendo administrado.
Ahí aparece el State.
El State es información que Terraform mantiene sobre la infraestructura que administra.
Por defecto se almacena en:
terraform.tfstate
Podemos pensar que Terraform tiene tres fuentes de información:
- La configuración describe lo que queremos.
- La infraestructura representa lo que existe realmente.
- El State ayuda a Terraform a saber qué recursos está administrando y cómo se relacionan con la configuración.
Podríamos pensar: "Entonces terraform.tfstate es simplemente otra versión de main.tf."
No.
Son cosas diferentes.
Nuestro código podría decir:
resource "local_file" "hello" {
filename = "hello.txt"
content = "Hola!"
}
Mientras que el State contiene información sobre el recurso que Terraform está administrando.
Por ejemplo, puede almacenar:
- el tipo de recurso;
- su identificador;
- atributos conocidos;
- información del provider;
- relaciones entre recursos;
- valores que Terraform necesita para gestionar ese recurso.
El State funciona como una especie de mapa entre nuestra configuración y la infraestructura real.
Podemos crear un ejemplo pequeño:
terraform {
required_providers {
local = {
source = "hashicorp/local"
}
}
}
provider "local" {}
resource "local_file" "hello" {
filename = "hello.txt"
content = "Hola Terraform!"
}
Inicializamos:
terraform init
Y aplicamos:
terraform apply
Ahora tendremos:
hello.txt
terraform.tfstate
Podemos consultar el State mediante:
terraform show
Terraform nos muestra información sobre los recursos que administra.
También podemos listar los recursos que forman parte del State:
terraform state list
Obtendremos algo parecido a:
local_file.hello
Esto nos dice que Terraform está administrando ese recurso.
¿Qué pasa si ejecutamos apply otra vez?
Terraform no debería intentar crear otro archivo.
En lugar de eso veremos algo similar a:
No changes. Your infrastructure matches the configuration.
¿Por qué?
Porque Terraform sabe que:
- nuestra configuración declara local_file.hello;
- ese recurso ya está registrado en el State;
- el recurso existe;
- no hay cambios que aplicar.
Por eso Terraform es idempotente en este sentido:
apply
↓
crear recurso
apply nuevamente
↓
no hay cambios
¿Y si modificamos la configuración?
Supongamos que cambiamos:
content = "Hola Terraform!"
por:
content = "Hola mundo!"
Ahora ejecutamos:
terraform plan
Terraform detecta que nuestra configuración cambió.
Podríamos ver algo parecido a:
~ local_file.hello
content: "Hola Terraform!" -> "Hola mundo!"
El símbolo: ~ indica que Terraform planea modificar un recurso existente.
Después:
terraform apply
Terraform actualiza el recurso.
¿De dónde sabe Terraform qué cambió?
Esta es justamente una de las razones por las que existe el State.
Terraform puede comparar diferentes piezas de información:
configuración
│
▼
Terraform
│
┌─────┴─────┐
▼ ▼
State infraestructura
A partir de esa información Terraform puede determinar qué acciones necesita realizar.
Por ejemplo:
crear
modificar
destruir
no hacer nada
Esto se conoce como planificación de cambios.
Ahora viene una situación muy interesante.
Supongamos que Terraform creó una infraestructura y todo está funcionando correctamente.
Pero alguien entra directamente a la consola del proveedor cloud y modifica algo.
Por ejemplo:
Terraform:
instance_type = "small"
Pero alguien entra manualmente y cambia la máquina a:
instance_type = "large"
Ahora tenemos una diferencia: La infraestructura real ya no coincide con lo que Terraform espera.
A esto normalmente se lo llama drift.
Es decir: La infraestructura se alejó del estado que Terraform espera administrar.
¿Qué puede hacer Terraform?
Cuando ejecutamos:
terraform plan
Terraform consulta información del provider y puede detectar diferencias entre lo que conoce y lo que existe.
Por ejemplo, podría mostrarnos que una configuración cambió.
Entonces Terraform puede proponer una corrección.
La idea es volver a:
Configuración
│
▼
Terraform
│
▼
Infraestructura deseada
En otras palabras: Terraform puede utilizarse para mantener la infraestructura alineada con una configuración declarativa.
¿Terraform detecta absolutamente todo?
No. Esto es importante.
Terraform depende de lo que el provider pueda consultar y representar.
Además, no todos los cambios externos necesariamente tienen el mismo comportamiento.
Por eso no deberíamos pensar: "Terraform mágicamente sabe todo lo que ocurrió."
Terraform trabaja con la información que obtiene de los providers y con el State que mantiene.
¿Qué ocurre si eliminamos terraform.tfstate? Esta es una prueba interesante.
Supongamos que tenemos:
terraform.tfstate
hello.txt
Si eliminamos:
terraform.tfstate
pero dejamos:
hello.txt
la infraestructura sigue existiendo.
Pero Terraform perdió su información sobre ese recurso.
Si volvemos a ejecutar:
terraform plan
Terraform puede considerar que el recurso declarado en la configuración no está registrado en el State.
Es decir, tenemos:
Configuración
│
▼
local_file.hello
State
│
▼
vacío
Infraestructura
│
▼
hello.txt
Esto muestra algo importante: El State no es la infraestructura.
Si borramos el State, no necesariamente borramos la infraestructura.
Hemos perdido la información que Terraform utilizaba para administrarla.
Entonces, ¿podemos borrar el State?
No deberíamos hacerlo arbitrariamente.
En un proyecto real, perder el State puede ser un problema serio.
Por eso es habitual:
- almacenarlo de forma segura;
- realizar backups;
- restringir el acceso;
- utilizar un backend apropiado;
- evitar modificarlo manualmente.
Y esto nos lleva a otro problema.
¿Qué pasa cuando trabajamos en equipo?
Supongamos que tenemos:
Emanuel
│
└── terraform apply
Juan
│
└── terraform apply
Si ambos tienen una copia local de:
terraform.tfstate
tenemos un problema.
Cada uno podría tener un State diferente.
Por ejemplo:
Emanuel
terraform.tfstate
│
└── versión A
Juan
terraform.tfstate
│
└── versión B
¿Cuál es el correcto?
Por eso, en equipos, normalmente no queremos guardar el State únicamente en el disco local de cada desarrollador.
Necesitamos un backend remoto.
Terraform permite almacenar el State en diferentes backends.
Por ejemplo:
Terraform
│
▼
Backend remoto
│
├── State
└── Locking
Algunos proveedores cloud ofrecen almacenamiento adecuado para esto.
Por ejemplo, un equipo que trabaja con AWS puede utilizar un backend basado en S3.
La configuración puede tener una forma similar a:
terraform {
backend "s3" {
bucket = "terraform-state"
key = "production/terraform.tfstate"
region = "us-east-1"
}
}
La configuración exacta depende de la versión de Terraform y del backend que utilicemos, pero la idea fundamental es: El State deja de estar únicamente en la máquina de un desarrollador y pasa a estar almacenado en un lugar compartido.
¿Y si dos personas ejecutan Terraform al mismo tiempo?
Este problema es todavía más interesante.
Imaginemos:
Emanuel
│
├── terraform apply
│
▼
State
Juan
│
├── terraform apply
│
▼
State
Si ambos intentan modificar la infraestructura simultáneamente, podemos terminar con operaciones que interfieren entre sí.
Por eso aparece otro concepto importante: State locking
Algunos backends permiten bloquear el State mientras una operación está en curso.
Conceptualmente:
Emanuel
│
└── apply
│
▼
LOCK 🔒
│
▼
State
Juan
│
└── apply
│
▼
espera/rechazo
De esta manera evitamos que dos operaciones modifiquen simultáneamente el mismo State.
¿Podemos guardar terraform.tfstate en Git?
En general, no es una buena práctica para proyectos reales.
Hay varias razones.
La primera es que el State puede contener información sensible.
Por ejemplo:
- identificadores;
- atributos de infraestructura;
- información de configuración;
- y, dependiendo del provider y de los recursos, valores que no queremos distribuir libremente.
Además, Git no es un backend diseñado para coordinar el acceso concurrente al State.
Por eso normalmente tenemos:
Código Terraform
│
▼
Git
pero:
Terraform State
│
▼
Backend remoto
Son responsabilidades diferentes.
Después de conocer el State, podemos entender mejor qué ocurre cuando ejecutamos:
terraform plan
No es simplemente: "Leé los `.tf` y ejecutá los comandos."
Terraform tiene que construir un plan considerando:
Configuración
│
▼
Terraform
│
┌────────┴────────┐
▼ ▼
State infraestructura
│ │
└────────┬────────┘
▼
Plan
│
▼
cambios necesarios
Por ejemplo:
+ crear
~ modificar
- destruir
Y recién después:
terraform apply
se aplican esos cambios.
Podemos resumir todo esto con una frase: La configuración dice lo que queremos, la infraestructura dice lo que existe y el State permite a Terraform relacionar ambas cosas.
Por eso el State es tan importante.
No es un simple archivo temporal.
Es una parte fundamental del funcionamiento de Terraform.

No hay comentarios.:
Publicar un comentario