Módulo 9 · Despliegue y operaciones

Lección 44 — Infraestructura como código (Terraform)

La infraestructura se versiona, se revisa y se destruye sin llorar.

Publicada
En esta lección
  1. Ejercicio 1 — El inventario
  2. Ejercicio 2 — El módulo
  3. Ejercicio 3 — El state
  4. Ejercicio 4 — Secretos y destrucción
  5. Ejercicio 5 — El ADR y el drill
  6. Resumen del profesor

Ejercicio 1 — El inventario

  1. El inventario honesto del proyecto al llegar aquí: la BD del compose (en código: docker-compose.yml), el Redis (), el bucket simulado del export (: "lo creé en la consola del lab el 14 de marzo"), los secretos de la pasarela (en el.env local: en 27, fuera), el dominio/DNS de pruebas (: "no recuerdo el registro"). Los son el clickops pendiente: cada uno con su reconstrucción o su import.
  2. El drill: 12 min de reconstrucción (compose up + migrate + seed) PERO con 3 "recuerdos a mano": la variable del NAT del 42, el usuario de la BD del staging, y el token de la pasarela sandbox. Cada recuerdo = un.tf pendiente o un secret que va al gestor.
  3. La regla (extracto): "Todo recurso de nube vive en infra/. Recurso encontrado fuera: import al código en la semana o destroy justificado en el PR. El plan de Terraform es la única vía de cambio de la infra".

Ejercicio 2 — El módulo

  1. El diff staging vs prod (los cambios del mismo código):
~ google_sql_database_instance.pg.settings.tier          "db-f1-micro" → "db-custom-2-7680"
~ google_sql_database_instance.pg.settings.availability  "ZONAL" → "REGIONAL"     (el SLO del 46)
~ google_cloud_run_service.web.metadata.maxScale         "3" → "8"                 (el 43/39)
+ google_sql_database_instance.pg.settings.backup_configuration (prod: PITR 7 días)
  1. El replacement: el plan dice -/+ google_redis_instance.cache (forces replacement) — destruye el Redis (los datos de caché mueren: aceptable) pero la LECCIÓN es el método: cambiar el nombre de la BD de prod SERÍA un replacement con datos: la vía correcta es la del 11 aplicada a infra: recurso nuevo con nombre nuevo → migrar datos (dump/replica) → switch del app → destruir el viejo. El plan se lee SIEMPRE buscando -/+ sobre recursos con datos.

Ejercicio 3 — El state

  1. La evidencia del lock:
Terminal A: terraform apply  → Acquiring state lock. This may take a few moments... OK
Terminal B: terraform apply  → Error: Error acquiring the state lock
             → State lock info: ID=..., Who=buffy@laptop, Created=2027-09-28T18:22:01Z

El segundo apply FALLA (con el dueño y la hora del lock): sin lock, los dos applies escriben el state a la vez y la mitad de los recursos quedan "creados pero no en el state" — el desastre silencioso del IaC.

  1. El runbook del drift (4 pasos): (1) terraform plan mensual del 42 → el diff inesperado revela el clickops ("+ firewall_rule que nadie PR-eó"); (2) clasificar: ¿es legítimo? (el cambio de emergencia del 47: IMPORTARLO al código con PR — el hotfix existió, ahora es código); ¿es un error? (3) revertir el clickops (la consola lo devuelve al estado del código) o aceptar y PR; (4) anotar el hallazgo en el postmortem de proceso: el clickops repetido es un permiso que falta (¿alguien no puede esperar al pipeline?).
  1. El state en claro: state pull muestra los atributos sensibles (la connection string del PG, los secret defaults). La protección: bucket con IAM de proyecto-only + versionado del bucket (el state corrompido se restaura) + cifrado en reposo (el proveedor lo da). El documento: "el state es un secreto de clase alta: quien lee el state tiene las llaves del reino; el bucket del state no se comparte con nadie".

Ejercicio 4 — Secretos y destrucción

  1. El grep vacío: el.tf declara la EXISTENCIA del secret; el valor lo sube el pipeline (41) con la identidad del deployer. En el runtime, el app lo lee del gestor por su identidad de servicio (42) — la cadena sin secretos en ficheros ni en el state.
  1. La ceremonia:
$ terraform destroy -var="env=prod"
Error: Instance cannot be destroyed: resource google_sql_database_instance.pg
has lifecycle.prevent_destroy set. Remove it explicitly to allow destruction.

El destroy legítimo del efímero: la variable ephemeral distingue el entorno de datos (dev/staging: sin prevent_destroy en los recursos NO-datos; la BD de staging con datos de test: el prevent_destroy permanece en todo lo que podría ser confundido con prod). El principio: el guard tiene que estar en el camino del desastre, no en el camino del trabajo.

  1. El staging nocturno: ahorro ~25 €/mes (el 60% del costo del staging × 11 h/día apagado). Lo que rompe: los datos de staging mueren cada noche (aceptable si el staging se siembra del seed del 40, no de datos de prod — el 23 lo prohíbe igual) y el restore drill del 42 corre contra el staging vespertino (ajuste: el drill antes de las 21:00 o el drill contra el lab). El patrón vale si el staging es stateless de verdad.

Ejercicio 5 — El ADR y el drill

  1. El drill cronometrado:
terraform apply (desde cero): 8m40s   (el SQL provision: 6m — el paso lento, inevitable)
migrate + seed:               1m10s
smoke del 35:                 2m30s
TOTAL: 12m20s  ✓ (<30 min del objetivo)

La mitigación del SQL lento: no hay (el provision es del proveedor) — el DR real apunta a: la infra se reconstruye en ~12 min, los DATOS vienen del PITR del gestionado (42, ~10 min) → el RTO completo de TicketFlow ≈ 25 min. El número del ADR: "RTO de entorno completo: ~25 min (medido 2027-09-28)".

  1. El ADR (extracto): "La infra es código. Backend GCS con lock, state por entorno, plan en el PR y apply del plan guardado, secretos en Secret Manager (el.tf declara, el pipeline carga), image_digest como único input de despliegue, prevent_destroy en datos, RTO medido: 25 min. Revisión: cuando el número de recursos supere el triángulo (red+datos+app) o el segundo servicio del 53 llegue".
  1. El diagrama del README:
git commit → CI (41) → digest:sha256
                          │
                          ▼
             terraform plan (PR comment)  ← candado: nadie aplica sin plan
                          │ merge
                          ▼
             terraform apply tfplan       ← candados: state lock · prevent_destroy
                          │
                          ▼
             smoke (35) → [env dev|staging|prod]
                          │
                          ▼
             state remoto (GCS, por env)  ← candado: versionado + IAM

Resumen del profesor

  • El IaC convierte la infra en código revisado: el plan en el PR, el apply del plan guardado, y el -/+ leído como la bomba que es.
  • El state remoto con lock por entorno es la memoria y su candado; el drift del clickops se reconcilia o se destruye, nunca se ignora.
  • Secretos declarados pero nunca escritos en ficheros; prevent_destroy en los datos; el drill medido convierte el DR en un número del ADR.