Skip to main content
Toda la configuración de Better Stack — páginas de estado, monitores, heartbeats, labels de logs, dashboards y alertas — se declara como código bajo infra/betterstack/. La UI nunca es la fuente de verdad; Terraform lo es.

Por qué infraestructura como código

Configurar docenas de monitores, secciones y alertas a mano no escala y deriva silenciosamente entre entornos. Terraform nos da:

Cómo piensa Terraform

Terraform reconcilia continuamente tres imágenes del mundo. Entender esto es la clave para todo lo demás en esta página:
  • Config declarada — lo que los archivos .tf y los manifiestos de adopción dicen que debería existir.
  • Estado rastreado (terraform.tfstate) — el inventario de Terraform de lo que ya gestiona, incluyendo el id de Better Stack de cada recurso.
  • Mundo real — lo que la API de Better Stack devuelve en este momento.

plan vs apply — la distinción central

Este es el concepto que cada operador debe internalizar. La analogía más simple: plan es el diff, apply es el commit.

terraform plan — dry run, solo lectura

Refresca el estado desde la API de Better Stack, lo compara con la config declarada, e imprime las acciones que tomaría: + create, ~ update, - destroy. No cambia nada. Un plan que muestra 0 to add, 0 to change, 0 to destroy prueba que no hay drift.

terraform apply — ejecuta el cambio

Toma ese mismo diff y ejecuta las llamadas reales a la API (POST / PATCH / DELETE), luego escribe los ids resultantes de vuelta en el tfstate. Esta es la única operación que muta la infraestructura.
Nunca haces apply sin leer primero el plan. En CI el plan se imprime en el log del job y apply requiere adicionalmente escribir APPLY — consulta CI/CD para el monitoreo.

Un tercer verbo: import (adopción)

Cuando un recurso ya existe en Better Stack (creado a mano antes de que Terraform lo gestionara), import lo adjunta al estado sin recrearlo. Así es como se adoptaron los monitores existentes: el primer apply en development importó 68 recursos, y el plan de seguimiento reportó 0 cambios.

Idempotencia — por qué reejecutar es seguro

Terraform es declarativo: aplicar la misma config dos veces no duplica nada, siempre que el estado se preserve.
Los duplicados solo ocurren si el estado se pierde o se omite — por ejemplo, aplicando contra un estado local vacío mientras los objetos ya existen en la UI, o borrando terraform.tfstate. Esto es exactamente por lo que CI se niega a ejecutarse sin un backend remoto, y por lo que los recursos existentes se importan antes del primer apply.

Layout del repositorio

Providers

Manifiestos de adopción

Cada entorno converge al mismo catálogo — 31 monitores (12 API, incluyendo el journey transversal Digital Contract, + 9 integraciones + 10 plataformas), 4 secciones y 3 heartbeats — cada uno apuntando a sus propios hosts. El manifiesto adopted/<env>.json es el estado deseado; después de la adopción lo editas vía PR. El generador sintetiza entradas que aún no existen (con monitor_id = null) para que Terraform las cree en el apply en lugar de importarlas. Regenera solo para auditar el drift, y revisa siempre el diff antes de hacer commit:

Estado por entorno (workspaces)

El estado se aísla por entorno usando workspaces de Terraform: el nombre del workspace es igual al nombre del entorno, así que development, certification y production mantienen cada uno un estado independiente bajo el prefijo env:/ del backend.
El estado local está en gitignore e incrusta el valor de x-health-token. Perderlo causa creaciones duplicadas en el próximo apply. Antes de cualquier uso por el equipo o CI, migra a un backend remoto compatible con S3 compartido.
El mismo bloque se almacena en el secret de GitHub TF_BACKEND_OVERRIDE para que el workflow lo escriba antes de terraform init.

Ejecutarlo localmente

terraform-apply.sh envuelve init + selección de workspace + plan/apply, y carga los tokens automáticamente desde backend/horizon-api/.env.<env> (mapeando BETTERSTACK_UPTIME_API_TOKEN al BETTERUPTIME_API_TOKEN del provider).
destroy está deliberadamente protegido: requiere CONFIRM_DESTROY=<env> para que nunca pueda ejecutarse por accidente.

Outputs

Después del apply, Terraform expone:
  • status_page_resources_json — el mapa scope de componente → id de recurso de la página de estado usado para llenar BETTERSTACK_STATUS_PAGE_RESOURCES.
  • uptime_heartbeat_ids — los tres ids de heartbeat de cron.

Código relacionado

  • Análisis profundo de IaC: docs/initiatives/betterstack/06-terraform-iac.md
  • README del módulo: infra/betterstack/README.md
  • Script del runner: scripts/status-monitoring/terraform-apply.sh