Introducción
Uno de los conceptos más importantes y a la vez más malentendidos de Terraform es el estado (state). Sin comprender cómo funciona el estado, es imposible trabajar de forma segura y eficiente con Terraform en entornos reales. En esta lección aprenderás qué es el estado, por qué existe, cómo se estructura y cómo interactuar con él de manera segura.
¿Qué es el Estado en Terraform?
El estado de Terraform es un archivo que actúa como la "memoria" de Terraform. Contiene un mapa detallado de todos los recursos que Terraform ha creado y gestionado, junto con sus atributos y metadatos actuales.
En términos simples:
- Terraform crea recursos en la nube (por ejemplo, una instancia EC2 en AWS).
- Terraform guarda la información de ese recurso en un archivo llamado
terraform.tfstate. - La próxima vez que ejecutes
terraform planoterraform apply, Terraform compara tu configuración actual con lo que hay en ese archivo de estado para determinar qué cambios son necesarios.
Sin el estado, Terraform no sabría:
- Qué recursos ya existen.
- Qué atributos tienen esos recursos.
- Cuál es la relación entre los recursos de tu código HCL y los recursos reales en la nube.
Por Qué Terraform Necesita el Estado
Terraform es una herramienta declarativa: tú describes el estado deseado de tu infraestructura, y Terraform se encarga de llegar a ese estado desde la situación actual. Para hacer esto, necesita saber cuál es el estado actual.
El problema que resuelve el estado
Imagina que tienes este código:
# main.tf
resource "aws_instance" "servidor_web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "ServidorWeb"
}
}La primera vez que ejecutas terraform apply, Terraform crea la instancia y guarda su ID (por ejemplo, i-0a1b2c3d4e5f67890) en el estado.
La segunda vez que ejecutas terraform plan, Terraform:
- Lee el archivo de estado y sabe que ya existe una instancia con ID
i-0a1b2c3d4e5f67890. - Consulta la API de AWS para obtener los atributos actuales de esa instancia.
- Compara lo que hay en la nube con lo que dice tu código HCL.
- Si no hay diferencias, informa "No changes. Infrastructure is up-to-date."
Sin el estado, Terraform intentaría crear una nueva instancia cada vez que ejecutaras apply, provocando duplicados y costos innecesarios.
Beneficios clave del estado
| Beneficio | Descripción |
|---|---|
| Mapeo de recursos | Asocia cada bloque resource en HCL con un recurso real en la nube |
| Rendimiento | Evita consultar la API del proveedor para cada atributo en cada ejecución |
| Seguimiento de dependencias | Registra las relaciones entre recursos para el orden de creación/destrucción |
| Metadatos | Almacena información que no está disponible en la API del proveedor |
Cómo Terraform Mapea Recursos Reales al Estado
Cada recurso en tu código HCL tiene una dirección (address) única. Por ejemplo:
La dirección de este recurso es: aws_instance.servidor_web
Cuando Terraform crea este recurso, almacena en el estado:
- La dirección lógica:
aws_instance.servidor_web - El ID del recurso real: por ejemplo,
i-0a1b2c3d4e5f67890 - Todos los atributos del recurso (tipo de instancia, AMI, IP pública, etc.)
Este mapeo es fundamental. Si borras un recurso del estado sin borrarlo de la nube, Terraform lo "olvidará" y ya no lo gestionará.
El Archivo terraform.tfstate: Estructura JSON Explicada
El archivo terraform.tfstate es un archivo JSON. Veamos un ejemplo simplificado:
{
"version": 4,
"terraform_version": "1.5.0",
"serial": 3,
"lineage": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"outputs": {
"ip_publica": {
"value": "54.123.45.67",
"type": "string"
}
},
"resources": [
{
"mode": "managed",
"type": "aws_instance",
"name": "servidor_web",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"ami": "ami-0c55b159cbfafe1f0",
"id": "i-0a1b2c3d4e5f67890",
"instance_type": "t2.micro",
"public_ip": "54.123.45.67",
"tags": {
"Name": "ServidorWeb"
}
}
}
]
}
]
}Explicación campo por campo
| Campo | Descripción |
|---|---|
version |
Versión del formato del archivo de estado (actualmente 4) |
terraform_version |
Versión de Terraform con la que se generó el estado |
serial |
Número que incrementa con cada modificación del estado; ayuda a detectar conflictos |
lineage |
UUID único generado al crear el estado por primera vez; identifica la "línea" del estado |
outputs |
Valores de salida declarados con output en tu código |
resources |
Lista de todos los recursos gestionados por Terraform |
mode |
managed para recursos gestionados; data para fuentes de datos |
type |
Tipo de recurso (por ejemplo, aws_instance) |
name |
Nombre lógico del recurso en tu código HCL |
provider |
Proveedor responsable de gestionar este recurso |
instances |
Lista de instancias del recurso (normalmente una, salvo con count o for_each) |
attributes |
Todos los atributos del recurso tal como los conoce Terraform |
Estado Local vs Estado Remoto
Por defecto, Terraform guarda el estado en un archivo local llamado terraform.tfstate en el directorio de trabajo.
Estado Local
mi-proyecto/ ├── main.tf ├── variables.tf ├── terraform.tfstate ← Estado local └── terraform.tfstate.backup ← Copia de seguridad del estado anterior
Ventajas del estado local:
- Simple, sin configuración adicional.
- Ideal para aprendizaje y proyectos personales.
Desventajas del estado local:
- No es apto para equipos (conflictos cuando varios desarrolladores trabajan al mismo tiempo).
- Sin locking nativo (riesgo de corrupción del estado).
- Si se pierde el archivo, se pierde el control sobre la infraestructura.
Estado Remoto
Para equipos y entornos de producción, el estado se guarda en un backend remoto (S3, Azure Blob Storage, Terraform Cloud, etc.).
# backend.tf
terraform {
backend "s3" {
bucket = "mi-terraform-state"
key = "produccion/terraform.tfstate"
region = "us-east-1"
}
}Ventajas del estado remoto:
- Compartido entre todo el equipo.
- Soporte para locking (bloqueo) para evitar escrituras concurrentes.
- Historial y versionado del estado.
- Separación del estado del código fuente.
Veremos los backends remotos en detalle en la lección 03-03-remote-state.md.
Operaciones que Modifican el Estado
No todas las operaciones de Terraform modifican el estado. Es importante saber cuáles sí lo hacen:
| Operación | ¿Modifica el estado? | Descripción |
|---|---|---|
terraform plan |
No | Solo calcula los cambios necesarios |
terraform apply |
Sí | Aplica cambios y actualiza el estado |
terraform destroy |
Sí | Destruye recursos y los elimina del estado |
terraform refresh |
Sí | Actualiza el estado con la realidad actual |
terraform state mv |
Sí | Mueve recursos dentro del estado |
terraform state rm |
Sí | Elimina recursos del estado (sin destruirlos) |
terraform import |
Sí | Añade recursos existentes al estado |
terraform init |
No | Configura el backend y descarga proveedores |
Comandos para Inspeccionar el Estado
terraform show
Muestra el estado actual de forma legible:
Salida de ejemplo:
# aws_instance.servidor_web:
resource "aws_instance" "servidor_web" {
ami = "ami-0c55b159cbfafe1f0"
id = "i-0a1b2c3d4e5f67890"
instance_type = "t2.micro"
public_ip = "54.123.45.67"
tags = {
"Name" = "ServidorWeb"
}
}También puedes usar -json para obtener la salida en formato JSON:
terraform state list
Lista todos los recursos gestionados por Terraform:
Salida de ejemplo:
Muy útil cuando tienes muchos recursos y necesitas encontrar rápidamente la dirección de uno.
terraform state show
Muestra los detalles de un recurso específico en el estado:
Salida de ejemplo:
# aws_instance.servidor_web:
resource "aws_instance" "servidor_web" {
ami = "ami-0c55b159cbfafe1f0"
availability_zone = "us-east-1a"
id = "i-0a1b2c3d4e5f67890"
instance_type = "t2.micro"
private_ip = "10.0.1.25"
public_ip = "54.123.45.67"
vpc_security_group_ids = [
"sg-0a1b2c3d",
]
tags = {
"Name" = "ServidorWeb"
}
}El Concepto de Drift (Desincronización)
El drift (o desincronización) ocurre cuando el estado real de la infraestructura difiere del estado que Terraform conoce. Esto puede ocurrir por varias razones:
- Alguien modificó un recurso manualmente a través de la consola de AWS/Azure/GCP.
- Un proceso automatizado externo cambió un atributo.
- Un recurso fue eliminado fuera de Terraform.
- Un recurso cambió su estado debido a un evento externo (por ejemplo, una instancia que se apagó).
Ejemplo de Drift
Imagina este escenario:
- Terraform creó una instancia EC2 de tipo
t2.micro. - Un administrador cambió manualmente el tipo a
t2.smallen la consola de AWS. - El estado de Terraform sigue diciendo
t2.micro.
Ahora hay un drift: la realidad (t2.small) difiere del estado conocido por Terraform (t2.micro).
¿Por qué es problemático el drift?
terraform planpuede mostrar cambios inesperados.- Si aplicas sin revisar, Terraform podría revertir cambios manuales.
- En entornos críticos, puede causar interrupciones del servicio.
terraform refresh y Cómo Detectar Drift
El comando terraform refresh (o terraform apply -refresh-only en versiones modernas) actualiza el archivo de estado para reflejar el estado real de los recursos sin aplicar ningún cambio de configuración.
# Forma moderna (recomendada en Terraform >= 0.15.4)
terraform apply -refresh-only
# Forma tradicional (deprecada en versiones recientes)
terraform refreshFlujo para detectar drift
# 1. Actualiza el estado con la realidad actual
terraform apply -refresh-only
# 2. Ahora ejecuta plan para ver qué Terraform querría cambiar
terraform planSi plan muestra cambios, significa que hay drift: la configuración en tu código HCL difiere de lo que existe realmente.
Ejemplo de salida con drift detectado
Terraform will perform the following actions:
# aws_instance.servidor_web will be updated in-place
~ resource "aws_instance" "servidor_web" {
id = "i-0a1b2c3d4e5f67890"
~ instance_type = "t2.small" -> "t2.micro"
# (otros atributos sin cambios)
}
Plan: 0 to add, 1 to change, 0 to destroy.El símbolo ~ indica una actualización. Terraform detectó que la instancia es actualmente t2.small (que fue cambiado manualmente) y quiere revertirla a t2.micro (que es lo que dice tu código).
Decisión después de detectar drift
Al detectar drift, tienes dos opciones:
- Aplicar el plan: Terraform revertirá los cambios manuales y volverá al estado declarado en el código.
- Actualizar el código: Si el cambio manual era intencionado, actualiza tu código HCL para reflejar el nuevo estado y ejecuta
terraform apply.
La segunda opción es generalmente la correcta en entornos maduros: el código HCL debe ser la fuente de verdad.
Ejercicio Práctico: Explorar el Estado Después de Aplicar una Configuración
Objetivo
Crear una configuración simple con el proveedor local (que no requiere credenciales de nube) y explorar el estado resultante.
Configuración de partida
Crea un directorio de trabajo y los siguientes archivos:
# main.tf
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
}
}
# Recurso 1: Un archivo de texto
resource "local_file" "archivo_bienvenida" {
content = "Hola, mundo! Este archivo fue creado por Terraform."
filename = "${path.module}/bienvenida.txt"
}
# Recurso 2: Otro archivo de texto con contenido diferente
resource "local_file" "archivo_configuracion" {
content = "ambiente=desarrollo\nversion=1.0"
filename = "${path.module}/config.txt"
}
# Output para mostrar las rutas de los archivos
output "ruta_bienvenida" {
value = local_file.archivo_bienvenida.filename
}
output "ruta_configuracion" {
value = local_file.archivo_configuracion.filename
}Pasos del ejercicio
Paso 1: Inicializar Terraform
Salida esperada:
Initializing the backend... Initializing provider plugins... - Finding hashicorp/local versions matching "~> 2.0"... - Installing hashicorp/local v2.4.0... Terraform has been successfully initialized!
Paso 2: Aplicar la configuración
Paso 3: Listar los recursos en el estado
Respuesta esperada:
Paso 4: Ver los detalles de un recurso específico
Paso 5: Ver el estado completo
Paso 6: Abrir el archivo terraform.tfstate directamente
Observa la estructura JSON. Identifica los campos serial, lineage, resources y attributes.
Paso 7: Simular un drift editando el archivo manualmente
# Modifica el contenido del archivo creado por Terraform (simulando un cambio manual)
echo "Contenido modificado manualmente" > bienvenida.txtPaso 8: Detectar el drift
Terraform detectará que el contenido del archivo difiere de lo que espera y propondrá restaurarlo.
Solución: Salida esperada del paso 8
Terraform used the selected providers to generate the following execution plan.
# local_file.archivo_bienvenida must be replaced
-/+ resource "local_file" "archivo_bienvenida" {
~ content = "Contenido modificado manualmente" -> "Hola, mundo! Este archivo fue creado por Terraform."
~ id = "abc123..." -> (known after apply)
# (otros atributos sin cambios)
}
Plan: 1 to add, 0 to change, 1 to destroy.El símbolo -/+ indica que el recurso será destruido y recreado (porque el proveedor local reemplaza los archivos en lugar de actualizarlos en lugar).
Errores Comunes Relacionados con el Estado
Error 1: "Error acquiring the state lock"
Error: Error acquiring the state lock Error message: ConditionalCheckFailedException: The conditional request failed Lock Info: ID: 12345678-abcd-efgh-ijkl-123456789012 Path: terraform.tfstate Operation: OperationTypePlan Who: usuario@maquina Version: 1.5.0 Created: 2024-01-15 10:30:00 +0000 UTC Info:
Causa: Otro proceso de Terraform está ejecutándose (o un proceso anterior no liberó el lock).
Solución: Espera a que el otro proceso termine o usa terraform force-unlock <ID> con precaución.
Error 2: Estado corrupto o inconsistente
Error: Invalid resource type A managed resource type "aws_instance.servidor_web" was declared, but no resource type with that name is registered in the "aws" provider.
Causa: El estado hace referencia a un tipo de recurso que ya no existe o cambió de nombre.
Solución: Revisa la versión del proveedor y usa terraform state mv para actualizar las referencias si es necesario.
Error 3: Recurso en el estado pero eliminado en la nube
Error: error reading EC2 Instance (i-0a1b2c3d4e5f67890): InvalidInstanceID.NotFound: The instance ID 'i-0a1b2c3d4e5f67890' does not exist
Causa: El recurso fue eliminado manualmente en la nube pero Terraform todavía lo tiene en el estado. Solución:
# Elimina el recurso del estado sin intentar destruirlo en la nube
terraform state rm aws_instance.servidor_webError 4: Archivo de estado no encontrado
Causa: No existe archivo de estado (primera ejecución o se eliminó accidentalmente).
Solución: Si es la primera ejecución, ejecuta terraform init. Si se eliminó accidentalmente y no hay backup, el estado está perdido y tendrás que usar terraform import para recuperar los recursos.
Consejo adicional: Nunca edites el estado manualmente
Editar el archivo terraform.tfstate directamente con un editor de texto es extremadamente peligroso. Puede corromper el estado y hacer que Terraform falle de formas impredecibles. Siempre usa los comandos oficiales de Terraform para manipular el estado.
Resumen
En esta lección has aprendido los conceptos fundamentales del estado de Terraform:
- El estado es la memoria de Terraform: mapea tus recursos HCL con los recursos reales en la nube.
- Sin estado, Terraform no puede determinar qué ya existe y qué necesita crear, modificar o destruir.
- El estado se almacena por defecto en
terraform.tfstate, un archivo JSON con campos comoversion,serial,lineage,resourcesyattributes. - Los comandos de inspección clave son:
terraform show: muestra el estado completo de forma legible.terraform state list: lista todos los recursos gestionados.terraform state show <recurso>: muestra los detalles de un recurso específico.
- El drift es la desincronización entre el estado de Terraform y la realidad. Se detecta con
terraform apply -refresh-onlyseguido deterraform plan. - El estado local es simple pero no apto para equipos; el estado remoto es la solución para entornos colaborativos.
En la siguiente lección (03-02-state-files.md) profundizaremos en la estructura del archivo de estado, aprenderemos a manipularlo con comandos como terraform state mv y terraform state rm, y veremos cómo importar infraestructura existente con terraform import.
Curso de Terraform
Módulo 1: Introducción a Terraform
- ¿Qué es Terraform?
- Instalando Terraform
- Conceptos Básicos de Terraform
- Primera Configuración de Terraform
Módulo 2: Lenguaje de Configuración de Terraform
Módulo 3: Gestión del Estado
Módulo 4: Módulos de Terraform
Módulo 5: Aprovisionamiento de Recursos
- Conceptos Básicos de Aprovisionamiento
- Aprovisionamiento de Recursos AWS
- Aprovisionamiento de Recursos Azure
- Aprovisionamiento de Recursos GCP
Módulo 6: Funcionalidades Avanzadas de Terraform
Módulo 7: Mejores Prácticas de Terraform
- Organización del Código
- Control de Versiones
- Pruebas del Código de Terraform
- Mejores Prácticas de Seguridad
Módulo 8: Terraform en CI/CD
- Integración de Terraform con CI/CD
- Automatización de Terraform con Jenkins
- Uso de Terraform con GitHub Actions
- Terraform Cloud y Enterprise
