Terraform Associate
Deep Dive
Los recursos son el elemento central de Terraform: definen la infraestructura que quieres gestionar. Las data sources permiten leer infraestructura existente. Entender dependencias y el bloque lifecycle es clave para el examen.
Contenido
El bloque resource tiene dos etiquetas obligatorias: el tipo (determinado por el provider) y el nombre local (identificador dentro de Terraform).
# resource "<TIPO>" "<NOMBRE_LOCAL>" { ... }
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = "web-server"
}
}
# Dirección del recurso: aws_instance.web
# Atributo: aws_instance.web.id
# Atributo: aws_instance.web.public_ip
# Módulo raíz: aws_instance.web
# Módulo hijo: module.app.aws_instance.web
# Módulo anidado: module.app.module.compute.aws_instance.web| Concepto | Descripción | Ejemplo |
|---|---|---|
| Tipo | Define qué API se llama (determinado por el provider) | aws_instance, azurerm_virtual_machine |
| Nombre local | Identificador único dentro del módulo (no en la nube) | web, database, main — solo letras, números, _ |
| Dirección | Tipo + nombre = dirección completa del recurso | aws_instance.web |
| Argumentos | Parámetros que configuran el recurso (definidos por el provider) | ami, instance_type, tags |
| Atributos | Valores calculados tras la creación (export values) | .id, .arn, .public_ip |
Las data sources permiten consultar información de infraestructura existente (creada por otro módulo, otra herramienta, o manualmente) sin que Terraform la gestione.
# data "<TIPO>" "<NOMBRE_LOCAL>" { ... }
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-*-22.04-amd64-server-*"]
}
}
# Usar el resultado de la data source
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id # data.<tipo>.<nombre>.<attr>
instance_type = "t3.micro"
}
# Otros ejemplos de data sources
data "aws_vpc" "existing" {
id = "vpc-12345678" # buscar por ID exacto
}
data "aws_availability_zones" "available" {
state = "available" # todas las AZs disponibles
}💡 Data sources se leen en terraform plan
Las data sources se consultan durante el terraform plan (o al inicio del apply). Si la infraestructura consultada no existe, el plan fallará con un error. A diferencia de los recursos, Terraform no crea ni destruye nada al usar data sources.
| Característica | resource {} | data {} |
|---|---|---|
| ¿Crea infra? | ✅ Sí — Terraform crea/gestiona el recurso | ❌ No — solo lee infra existente |
| ¿Aparece en state? | ✅ Sí — trackea su estado en tfstate | ❌ No — no guarda estado (relee en cada plan) |
| ¿Terraform puede destruirlo? | ✅ Sí — con destroy | ❌ No — nunca lo destruye |
| Prefijo en referencias | tipo.nombre.atrib (sin prefijo) | data.tipo.nombre.atrib |
| Cuándo usarlo | Cuando Terraform debe ser el dueño del recurso | Cuando la infra ya existe y solo necesitas sus atributos |
| Sintaxis | resource "aws_vpc" "main" {} | data "aws_vpc" "existing" {} |
Terraform construye automáticamente un grafo de dependencias basado en las referencias entre recursos. También puedes declarar dependencias explícitas con depends_on.
# DEPENDENCIA IMPLÍCITA (recomendada)
# Terraform detecta que aws_subnet.main depende de aws_vpc.main
# porque referencia su atributo .id
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "main" {
vpc_id = aws_vpc.main.id # <-- crea dependencia implícita
cidr_block = "10.0.1.0/24"
}
# DEPENDENCIA EXPLÍCITA (usar solo cuando no hay referencia directa)
# Por ejemplo: la app depende de que la DB exista, pero no referencia ningún attr
resource "aws_db_instance" "main" {
# ... configuración de la DB
}
resource "aws_instance" "app" {
ami = "ami-abc123"
instance_type = "t3.micro"
depends_on = [aws_db_instance.main] # espera a que DB esté lista
}💡 Cuándo usar depends_on
Usa depends_on solo cuando hay una dependencia real que Terraform no puede detectar automáticamente (por ejemplo, cuando un recurso necesita que otro esté listo, pero no usa ningún atributo suyo). El uso innecesario de depends_on puede hacer el plan más lento al añadir dependencias que Terraform podría paralelizar.
El bloque lifecycle dentro de un recurso controla cómo Terraform gestiona el ciclo de vida del recurso: creación, actualización y destrucción.
resource "aws_db_instance" "prod" {
identifier = "prod-db"
# ... otros argumentos
lifecycle {
# Evita que Terraform destruya este recurso (error si intenta hacerlo)
prevent_destroy = true
# Crea el nuevo recurso ANTES de destruir el viejo (zero downtime)
create_before_destroy = true
# Ignora cambios en estos argumentos (no genera diff en plan)
ignore_changes = [
engine_version, # la DB puede auto-actualizarse sin que Terraform lo revierta
tags["LastModified"],
]
# Terraform destruye y recrea el recurso si este otro recurso cambia
replace_triggered_by = [
aws_launch_template.app.id,
]
}
}| Argumento | Tipo | Efecto |
|---|---|---|
| prevent_destroy | bool | Si true, cualquier plan que destruya el recurso generará un error. Protege recursos críticos. |
| create_before_destroy | bool | Si true, crea el reemplazo antes de destruir el actual. Requiere que el proveedor lo soporte. |
| ignore_changes | list(attr) | Ignora cambios en los atributos listados. Usar "all" para ignorar todos (caso extremo). |
| replace_triggered_by | list(ref) | Fuerza el reemplazo de este recurso cuando cambian los recursos/atributos referenciados. |
⚠️ prevent_destroy no protege contra terraform destroy
prevent_destroy = true impide que Terraform destruya el recurso como parte de un cambio de configuración (ej: cambiar el nombre de una DB que requiere reemplazo). Sin embargo, si alguien elimina el bloque resource del código y ejecuta apply, el recurso se destruirá igualmente porque ya no existe la regla prevent_destroy.
¿Entendiste este tema?
Pon a prueba lo que acabas de aprender
Un equipo tiene una base de datos de producción definida con resource 'aws_db_instance' 'prod'. Quieren que si alguien cambia el parámetro engine_version, Terraform NO lo revierta (la DB gestiona sus propias actualizaciones de motor). ¿Qué configuración lifecycle es correcta?