Cerramos el capítulo de HCL con las herramientas que hacen tu código inteligente y eficiente: los condicionales (tomar decisiones) y los bucles (crear muchos recursos sin repetirte). Sin ellos, tendrías que copiar y pegar el mismo bloque una y otra vez. Con ellos, escribes una vez y Terraform genera lo que haga falta.

El problema: no repetirse

Imagina que necesitas tres servidores idénticos. Sin bucles, escribirías tres bloques resource casi iguales. Si necesitaras cambiar algo, tendrías que cambiarlo en los tres. Eso es tedioso y propenso a errores.

Los bucles resuelven esto: declaras el recurso una vez e indicas «créalo N veces». Veamos las herramientas.

count: crear N copias

El argumento count crea varias copias de un recurso. Le das un número y Terraform crea esa cantidad.

resource "aws_instance" "web" {
  count         = 3                  # ← crea 3 instancias
  ami           = "ami-0c1234567890abcde"
  instance_type = "t3.micro"
  tags = {
    Name = "web-${count.index}"      # web-0, web-1, web-2
  }
}
  • count = 3 crea tres instancias.
  • count.index es el número de cada copia (0, 1, 2), útil para darles nombres distintos.

Analogía: count es como decirle a una fotocopiadora «hazme 3 copias de este documento». Todas iguales, numeradas.

count también sirve para condicionales (crear o no un recurso):

resource "aws_instance" "bastion" {
  count = var.crear_bastion ? 1 : 0   # 1 si true, 0 si false
  # ...
}

Si var.crear_bastion es true, crea 1; si es false, crea 0 (es decir, ninguno). Esto es un truco muy común para hacer un recurso «opcional».

for_each: crear copias a partir de una colección

El argumento for_each crea una copia por cada elemento de un map o un set. A diferencia de count (que usa números), for_each usa claves con significado.

resource "aws_instance" "servidor" {
  for_each      = {
    web = "t3.micro"
    api = "t3.small"
    db  = "m5.large"
  }
  ami           = "ami-0c1234567890abcde"
  instance_type = each.value           # el valor: t3.micro, t3.small, m5.large
  tags = {
    Name = each.key                    # la clave: web, api, db
  }
}
  • Crea una instancia por cada entrada del map.
  • each.key es la clave (web, api, db).
  • each.value es el valor (t3.micro, etc.).

Analogía: for_each es como tener una lista de pedidos personalizados: «para web, una t3.micro; para api, una t3.small; para db, una m5.large». Cada uno con sus características.

count vs for_each: ¿cuál uso?

Esta es una decisión importante y una fuente típica de confusión:

count for_each
Se basa en Un número Un map o un set
Identifica cada copia por Posición (0, 1, 2…) Clave con significado
Bueno para Copias idénticas o recursos opcionales Recursos con identidad propia
Problema al borrar uno del medio Reordena y puede recrear otros No afecta a los demás

Regla práctica:

  • Usa count para crear N copias idénticas o para hacer un recurso opcional (count = condición ? 1 : 0).
  • Usa for_each cuando cada recurso tiene una identidad propia (nombres distintos, configuraciones distintas). Es más seguro al añadir o quitar elementos.

Por qué for_each suele ser preferible: con count, si borras el elemento del medio de una lista, los siguientes «se desplazan» y Terraform puede destruir y recrear recursos innecesariamente. Con for_each, cada recurso está ligado a su clave, así que quitar uno no afecta a los demás. Por eso muchos profesionales prefieren for_each salvo para casos simples.

La expresión for: transformar colecciones

No confundas el bucle for_each (que crea recursos) con la expresión for (que transforma datos). La expresión for genera una nueva lista o map a partir de otro, parecido a una fórmula.

locals {
  nombres        = ["web", "api", "db"]
  nombres_mayus  = [for n in local.nombres : upper(n)]
  # resultado: ["WEB", "API", "DB"]
}

Lee así: «para cada n en la lista nombres, devuelve upper(n)». Es una forma compacta de transformar todos los elementos de una colección.

Ejemplo útil: convertir una lista de nombres en un map, o filtrar elementos que cumplan una condición. Es una herramienta avanzada que verás en código real, pero al principio basta con reconocerla.

Condicionales: el operador ternario

Para tomar decisiones dentro de una expresión, Terraform usa el operador ternario (el mismo de muchos lenguajes):

condición ? valor_si_verdadero : valor_si_falso

Ejemplos:

instance_type = var.entorno == "prod" ? "m5.large" : "t3.micro"
# Si el entorno es "prod", usa m5.large; si no, t3.micro

count = var.alta_disponibilidad ? 2 : 1
# Si quieres alta disponibilidad, crea 2; si no, 1

Analogía: es como decir «¿es producción? Entonces el servidor grande; si no, el pequeño». Una decisión rápida en una sola línea.

Un ejemplo realista

variable "entorno" {
  type    = string
  default = "dev"
}

variable "subredes" {
  type = map(string)
  default = {
    publica-a  = "10.0.1.0/24"
    publica-b  = "10.0.2.0/24"
  }
}

resource "aws_subnet" "esta" {
  for_each   = var.subredes              # una subred por cada entrada
  vpc_id     = aws_vpc.principal.id
  cidr_block = each.value                # el rango de cada subred
  tags = {
    Name = each.key                      # publica-a, publica-b
    Tipo = var.entorno == "prod" ? "produccion" : "desarrollo"  # condicional
  }
}

Este código crea una subred por cada entrada del map subredes (bucle for_each), y etiqueta cada una según el entorno (condicional ternario). Escribiste un bloque y Terraform genera tantas subredes como definas, sin repetir código.

Lo que debes recordar

  • count: crea N copias de un recurso (count = 3) o lo hace opcional (count = condición ? 1 : 0). Identifica copias por posición (count.index).
  • for_each: crea una copia por cada elemento de un map o set, con identidad propia (each.key, each.value). Más seguro al añadir/quitar elementos.
  • Regla: count para copias idénticas u opcionales; for_each cuando cada recurso es distinto (suele ser preferible).
  • La expresión for transforma colecciones (no confundir con el bucle for_each).
  • El operador ternario condición ? a : b toma decisiones en una línea (ideal para diferenciar entornos).

Con esto cierras el Capítulo 10 y ya sabes leer y escribir HCL. En el Capítulo 11 veremos dos piezas fundamentales para que Terraform funcione: los providers (cómo habla con AWS) y el estado (cómo recuerda lo que ha creado).

Cloud, AWS & Terraform — De cero a experto

Capítulo 1 · Qué es el cloud computing

Capítulo 2 · El mercado cloud y los grandes proveedores

Capítulo 3 · Regiones, zonas de disponibilidad y edge

Capítulo 4 · Cómputo: EC2

Capítulo 5 · Almacenamiento: S3

Capítulo 6 · Redes: VPC

Capítulo 7 · Identidad y acceso: IAM

Capítulo 8 · Bases de datos gestionadas

Capítulo 9 · Por qué Infraestructura como Código

Capítulo 10 · HCL: el lenguaje de Terraform

Capítulo 11 · Providers y estado

Capítulo 12 · Tu primera infraestructura real en Terraform

Capítulo 13 · Balanceo de carga y autoescalado

Capítulo 14 · Serverless con Lambda

Capítulo 15 · Mensajería y eventos

Capítulo 16 · Entrega de contenido y DNS

Capítulo 17 · Contenedores en AWS

Capítulo 18 · Módulos: reutilización y composición

Capítulo 19 · Workspaces y gestión de entornos

Capítulo 20 · Backends remotos y locking

Capítulo 21 · Testing de infraestructura

Capítulo 22 · Terraform en CI/CD

Capítulo 23 · Seguridad en profundidad

Capítulo 24 · Observabilidad: logs, métricas y trazas

Capítulo 25 · Optimización de costes

Capítulo 26 · Alta disponibilidad y disaster recovery

Capítulo 27 · Well-Architected Framework de AWS

Capítulo 28 · Arquitecturas serverless a escala

Capítulo 29 · Plataformas de datos en AWS

Capítulo 30 · Multi-cuenta y landing zones

Capítulo 31 · Platform Engineering e Internal Developer Platform

Capítulo 32 · Certificaciones AWS relevantes

Capítulo 33 · Proyectos para consolidar lo aprendido

Capítulo 34 · Recursos y comunidad

© Copyright 2024. Todos los derechos reservados