Este documento describe la estrategia de recuperación ante desastres (DR), el Objetivo de Tiempo de Recuperación (RTO) y el Objetivo de Punto de Recuperación (RPO) para la infraestructura EKB AWS/EKS. Cubre las capacidades HA integradas, los sistemas de respaldo activos, los procedimientos de recuperación y las brechas conocidas.
Resumen de Arquitectura y Alta Disponibilidad
Componentes de Infraestructura
| Componente | Implementación | Modelo HA |
|---|
| Cómputo | EKS (Kubernetes 1.33) + Karpenter | Nodos multi-AZ, Spot + bajo demanda |
| Autoescalado de pods | KEDA | Basado en CPU/Memoria, mínimo 2 réplicas |
| Ingreso / SSL | ALB + ACM | Multi-AZ, enrutamiento por health-check |
| Caché | ElastiCache Redis (condicional) | Multi-AZ con failover automático |
| Cola de mensajes | Amazon MQ / RabbitMQ (condicional) | Instancia individual o activo/en espera |
| Base de datos (autoalojado) | Clúster HA CloudNativePG + PgBouncer | Primario + réplicas, failover automático |
| Base de datos (nube) | Supabase Cloud | Administrado, multi-región por el proveedor |
| Observabilidad | SigNoz + k8s-infra (condicional) | Dentro del clúster, sin punto único de falla |
| Estado IaC | S3 (versionado) + DynamoDB lock | Cifrado, versionado |
| Volúmenes persistentes | EBS (vía EBS CSI Driver) | Snapshots vía AWS Data Lifecycle Manager |
Capacidades HA Actuales
| Capacidad | Tiempo de Recuperación | Pérdida de Datos | Estado |
|---|
| Fallo de AZ (pods) | 0–5 min | Ninguna | Activo |
| Fallo / crash de pod | 0–2 min | Ninguna | Activo |
| Re-enrutamiento por health-check ALB | 0–1 min | Ninguna | Activo |
| Failover Multi-AZ de Redis | < 1 min | Ninguna | Activo (cuando está habilitado) |
| Sustitución de nodos Karpenter | 0–10 min | Ninguna | Activo |
| Restauración de snapshot EBS | 15–30 min | Hasta 24 h | Activo |
| Restauración PITR de CloudNativePG | 15–60 min | Hasta el retraso WAL | Activo (cuando está habilitado) |
| Recreación completa de infraestructura | 30–60 min | Ninguna (IaC) | Vía Terragrunt |
Objetivos RTO / RPO
| Escenario | Objetivo RTO | Objetivo RPO | Capacidad Actual |
|---|
| Fallo de un solo pod | < 2 min | 0 | Cumplido (réplicas mínimas KEDA) |
| Fallo de un solo nodo | < 10 min | 0 | Cumplido (sustitución Karpenter) |
| Fallo de AZ | < 5 min | 0 | Cumplido (distribución multi-AZ) |
| Fallo de Redis | < 1 min | 0 | Cumplido (failover multi-AZ) |
| Fallo del primario de Postgres | < 5 min | 0–segundos de retraso WAL | Cumplido (failover automático CNPG) |
| Pérdida de volumen EBS | 15–30 min | < 24 h | Parcial — snapshots DLM diarios |
| Fallo de región completa | > 60 min | Depende de la frecuencia de respaldo | No automatizado actualmente |
Sistemas de Respaldo
Qué se respalda: Todo el estado de infraestructura (EKS, red, IAM, releases de Helm).
Implementación:
- Bucket S3 por entorno:
ekb-terraform-state-<env-name> (inicializado vía terragrunt/environments/<env-name>/state/)
- Versionado habilitado — cualquier versión anterior del estado puede ser restaurada
- Cifrado del lado del servidor (AES-256)
- Tabla DynamoDB para bloqueo de estado
Recuperación: Revertir a cualquier versión anterior del estado en S3, luego volver a ejecutar terragrunt apply.
RPO: Cada commit de terragrunt apply — continuo.
2. Volúmenes Persistentes EBS — AWS Data Lifecycle Manager
Qué se respalda: Volúmenes EBS adjuntos a pods (PostgreSQL de Automator, MinIO de Supabase, cualquier carga de trabajo con estado).
Implementación: Política de AWS Data Lifecycle Manager (DLM) dirigida a etiquetas de entorno.
# Etiquete los volúmenes EBS con el nombre de su entorno, luego cree una política DLM:
# - Recurso: Volúmenes EBS
# - Etiqueta objetivo: Environment=<your-env-name>
# - Horario: Diario a las 02:00 UTC
# - Retención: 7 snapshots
Recuperación:
# 1. Identificar el snapshot a restaurar
aws ec2 describe-snapshots --filters "Name=tag:Environment,Values=<your-env-name>"
# 2. Crear un volumen a partir del snapshot
aws ec2 create-volume \
--snapshot-id snap-xxxxxxxxxxxxxxxxx \
--availability-zone <your-az> \
--volume-type gp3
# 3. Actualizar el PersistentVolume en Kubernetes para referenciar el nuevo ID de volumen
kubectl patch pv <pv-name> -p '{"spec":{"awsElasticBlockStore":{"volumeID":"<new-vol-id>"}}}'
RPO: Hasta 24 horas (snapshots diarios). Reducir aumentando la frecuencia del horario DLM.
3. CloudNativePG (DB HA de Supabase) — Respaldos Barman Cloud
Aplica a: Entornos con ENABLE_CNPG=true y ENABLE_HA_SUPABASE_DB=true.
Qué se respalda: El clúster Postgres de CloudNativePG (ha-supabase-db), incluyendo streaming continuo de WAL (Write-Ahead Log) a S3 o MinIO, y respaldos base completos programados vía el CRD ScheduledBackup de CNPG.
Implementación (configurado en values/ha-supabase-db.yaml):
postgres:
backup:
enabled: true # activar respaldos barman-cloud
# barmanObjectStore apunta al bucket S3 o endpoint MinIO
# IRSA / service account debe tener s3:PutObject, s3:GetObject, s3:ListBucket
retentionPolicy: "30d" # mantener respaldos por 30 días
compression: gzip
Verificar estado del respaldo:
# Listar todos los respaldos del clúster
kubectl get backup -n ha-supabase-db
# Verificar un respaldo específico
kubectl describe backup <backup-name> -n ha-supabase-db
# Activar un respaldo bajo demanda
kubectl cnpg backup ha-supabase-db -n ha-supabase-db
Recuperación a punto en el tiempo (PITR):
# Crear un nuevo CNPG Cluster restaurando desde un respaldo
# (en un nuevo namespace o después de eliminar el original)
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: ha-supabase-db-restored
namespace: ha-supabase-db-restore
spec:
instances: 3
bootstrap:
recovery:
source: ha-supabase-db
recoveryTarget:
targetTime: "2026-03-19T03:00:00.000000+00:00" # punto en el tiempo objetivo
externalClusters:
- name: ha-supabase-db
barmanObjectStore:
# misma configuración S3/MinIO que el clúster fuente
serverName: ha-supabase-db
RPO: Casi cero para clústeres con WAL habilitado (segundos de retraso, limitados por el intervalo de carga WAL).
4. ElastiCache Redis — Replicación Multi-AZ
Aplica a: Entornos con ENABLE_AWS_SERVICES=true.
Redis no es un almacén de datos primario — almacena caché transitoria y datos de sesión. El enfoque DR está en un failover rápido en lugar de respaldo/restauración.
Implementación:
- Multi-AZ habilitado con failover automático
- Cifrado en reposo y en tránsito
- Un fallo del nodo primario promueve una réplica automáticamente (< 1 min)
RPO: Los datos de Redis son efímeros por diseño. Las fallas de caché después del failover son esperadas; la aplicación repuebla desde la base de datos.
5. Amazon MQ (RabbitMQ — Cola de Mensajes
Aplica a: Entornos con ENABLE_AWS_SERVICES=true.
Implementación:
- Despliegue de instancia individual (predeterminado) o activo/en espera
- Los mensajes en tránsito pueden perderse durante un reinicio del broker; diseñar consumidores idempotentes
- UI de gestión disponible en el puerto 15671 (SSL)
RPO: Instancia individual — los mensajes en tránsito al momento del fallo pueden perderse. Usar el modo de despliegue activo/en espera para reducir este riesgo.
Mecanismos de Auto-recuperación
Karpenter — Provisionamiento y Recuperación de Nodos
- Consolidación:
WhenEmptyOrUnderutilized — los nodos inactivos se terminan automáticamente
- Manejo de interrupciones Spot: Escucha eventos de interrupción SQS; drena y sustituye nodos Spot antes de la terminación
- Deriva de nodos: Los nodos que usan AMIs o configuraciones obsoletas se reemplazan automáticamente cuando
enable_drift = true
- Tiempo de recuperación: Nuevo nodo provisionado en 0–10 minutos
KEDA — Autoescalado de Pods
- Réplicas mínimas: 2 para todos los servicios (Web, API, Celery, Automator) — previene punto único de falla
- Umbral de CPU: 60–70% activa la escala ascendente
- Umbral de memoria: 80% activa la escala ascendente
- Estabilización de escala descendente: 30 segundos — evita fluctuaciones
- Tiempo de recuperación: Pods fallidos reprogramados dentro de 0–2 minutos
Anti-afinidad de Pods de Kubernetes
Todos los servicios sin estado usan anti-afinidad preferredDuringSchedulingIgnoredDuringExecution en kubernetes.io/hostname para distribuir pods entre nodos y AZs.
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values: ["web", "fastapi-backend", "celery-worker", "automator"]
topologyKey: kubernetes.io/hostname
Procedimientos de Recuperación
Escenario 1: Fallo de AZ
Comportamiento esperado: Karpenter provisiona nodos de reemplazo en las AZs restantes; KEDA reprograma pods; ALB deja de enrutar a objetivos no saludables.
Verificación:
kubectl get nodes -o wide # confirmar que los nodos están en AZs saludables
kubectl get pods -A -o wide # confirmar que los pods se están ejecutando
kubectl get ingress # confirmar que ALB está enrutando correctamente
No se requiere intervención manual bajo circunstancias normales.
Escenario 2: Fallo del Nodo Primario de Postgres (CloudNativePG)
CloudNativePG promueve automáticamente una réplica a primario.
# Monitorear el failover
kubectl get cluster ha-supabase-db -n ha-supabase-db -w
# Confirmar el nuevo primario
kubectl cnpg status ha-supabase-db -n ha-supabase-db
# Verificar que el pooler PgBouncer apunta al nuevo primario
kubectl get svc -n ha-supabase-db | grep pooler
Las aplicaciones se reconectan vía PgBouncer — no se necesita cambiar la cadena de conexión.
Escenario 3: Restaurar Volumen EBS desde Snapshot
# 1. Buscar snapshots del entorno
aws ec2 describe-snapshots \
--filters "Name=tag:Environment,Values=<your-env-name>" \
--query 'Snapshots[*].[SnapshotId,StartTime,VolumeSize]' \
--output table
# 2. Crear un nuevo volumen a partir del snapshot elegido
aws ec2 create-volume \
--snapshot-id snap-xxxxxxxxxxxxxxxxx \
--availability-zone <target-az> \
--volume-type gp3 \
--tag-specifications 'ResourceType=volume,Tags=[{Key=Environment,Value=<your-env-name>}]'
# 3. Reducir las réplicas de la carga de trabajo afectada
kubectl scale deployment <workload> --replicas=0
# 4. Actualizar el PV para referenciar el nuevo volumen EBS, luego restaurar las réplicas
kubectl patch pv <pv-name> -p '{"spec":{"csi":{"volumeHandle":"<new-volume-id>"}}}'
kubectl scale deployment <workload> --replicas=2
Escenario 4: Recreación Completa de Infraestructura
Usado después de un fallo catastrófico o al reconstruir una región.
# 1. Inicializar el bucket de estado (si no existe)
cd terragrunt/environments/<your-env-name>/state
terragrunt apply
# 2. Recrear el cluster EKS y la infraestructura central
cd terragrunt/environments/<your-env-name>
terragrunt apply
# 3. Desplegar servicios en orden (ver Guía de Despliegue con Terragrunt § Fase 6)
ENABLE_CNPG=true terragrunt apply --target='helm_release.local["cloudnative-pg"]'
ENABLE_HA_SUPABASE_DB=true terragrunt apply --target='helm_release.local["ha-supabase-db"]'
ENABLE_SUPABASE=true terragrunt apply --target='helm_release.local["supabase"]'
RTO estimado: 30–60 minutos para el clúster completo; 60–120 minutos si se deben restaurar datos de EBS/CNPG.
Escenario 5: Reversión de Estado de Terragrunt
# Listar versiones de estado en S3
aws s3api list-object-versions \
--bucket ekb-terraform-state-<your-env-name> \
--prefix <state-key>
# Restaurar una versión específica
aws s3api get-object \
--bucket ekb-terraform-state-<your-env-name> \
--key <state-key> \
--version-id <version-id> \
terraform.tfstate
# Re-importar o aplicar con el estado restaurado
Observabilidad y Alertas (SigNoz)
Cuando ENABLE_SIGNOZ=true, SigNoz se despliega en el namespace monitoring y proporciona:
- Traza distribuida para todos los servicios de EKB
- Métricas del clúster vía el agente DaemonSet k8s-infra (CPU, memoria, estado de pods)
- Agregación de logs de todos los pods
- Alertas — configure reglas de alerta en SigNoz para notificar sobre bucles de crash de pods, altas tasas de error o presión de nodos
Para fines de DR, los paneles de SigNoz son la herramienta principal para diagnosticar y confirmar la recuperación después de un incidente. Los datos de SigNoz se almacenan en volúmenes EBS PV y están cubiertos por la política de snapshots EBS.
Brechas y Recomendaciones
| Brecha | Riesgo | Recomendación |
|---|
| Sin replicación multi-región | Fallo de región completa = RTO extendido | Considerar réplica de lectura multi-región RDS o replicación multi-región S3 para respaldos CNPG |
| Snapshots EBS son diarios | Hasta 24 h de pérdida de datos para cargas de trabajo con EBS | Aumentar la frecuencia DLM a horaria para volúmenes críticos |
| RabbitMQ de instancia individual (predeterminado) | Mensajes en tránsito perdidos en fallo del broker | Cambiar a modo de despliegue ACTIVE_STANDBY_MULTI_AZ para producción |
| Sin simulacro DR automatizado | Procedimientos de recuperación sin probar hasta que se necesiten | Programar simulacros trimestrales; probar restauración PITR de CNPG en un entorno de staging |
| SigNoz en el mismo clúster | Observabilidad perdida durante fallo del clúster | Considerar un endpoint de monitoreo ligero separado o alertas de respaldo de CloudWatch |