Lab 5: Simulación de Incidente
Lab 5: Simulación de Incidente y Failover Automático
En este laboratorio provocamos la caída del sitio web primario para observar la secuencia completa de failover automático en tiempo real.
Caída Primario → Route 53 HC Falla → CW Alarm → SNS → Lambda Failover → Primario=OFF | Secundario=ONCargar variables de entorno
source ~/global.envRecuperar variables de sesiones anteriores
Si abriste una terminal nueva, recuperá los ARNs de los recursos ya desplegados:
# Fuente: CloudFormation (Opción A)
if aws cloudformation describe-stacks --stack-name route53-arc-routing --region $AWS_REGION > /dev/null 2>&1; then
export PRIMARY_RC_ARN=$(aws cloudformation describe-stacks \
--stack-name route53-arc-routing --region $AWS_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`PrimaryRoutingControlArn`].OutputValue' --output text)
export SECONDARY_RC_ARN=$(aws cloudformation describe-stacks \
--stack-name route53-arc-routing --region $AWS_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`SecondaryRoutingControlArn`].OutputValue' --output text)
export ARC_CLUSTER_ARN=$(aws cloudformation describe-stacks \
--stack-name route53-arc-routing --region $AWS_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`ARCClusterArn`].OutputValue' --output text)
# Dominio fallback desde Amplify o CloudFront
AMPLIFY_DOMAIN=$(aws cloudformation describe-stacks \
--stack-name route53-arc-secondary --region $AWS_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`AmplifyDefaultDomain`].OutputValue' \
--output text 2>/dev/null || echo "")
CF_DOMAIN=$(aws cloudformation describe-stacks \
--stack-name route53-arc-secondary --region $AWS_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`CloudFrontDomain`].OutputValue' \
--output text 2>/dev/null || echo "")
if [ -n "$AMPLIFY_DOMAIN" ] && [ "$AMPLIFY_DOMAIN" != "None" ]; then
export FALLBACK_DOMAIN="https://main.${AMPLIFY_DOMAIN}"
elif [ -n "$CF_DOMAIN" ] && [ "$CF_DOMAIN" != "None" ]; then
export FALLBACK_DOMAIN="https://${CF_DOMAIN}"
fi
# Fuente: Terraform (Opción B)
elif [ -f ~/route53-arc-tf/03_arc/terraform.tfstate ]; then
export PRIMARY_RC_ARN=$(cd ~/route53-arc-tf/03_arc && terraform output -raw primary_rc_arn 2>/dev/null)
export SECONDARY_RC_ARN=$(cd ~/route53-arc-tf/03_arc && terraform output -raw secondary_rc_arn 2>/dev/null)
export ARC_CLUSTER_ARN=$(cd ~/route53-arc-tf/03_arc && terraform output -raw arc_cluster_arn 2>/dev/null)
export FALLBACK_DOMAIN=$(cd ~/route53-arc-tf/02_secondary && terraform output -raw fallback_domain 2>/dev/null)
fi
# Obtener cluster endpoint
if [ -n "$ARC_CLUSTER_ARN" ]; then
read CLUSTER_ENDPOINT ENDPOINT_REGION <<< $(aws route53-recovery-control-config describe-cluster \
--cluster-arn $ARC_CLUSTER_ARN --region $AWS_REGION \
--query 'Cluster.ClusterEndpoints' --output json | python3 -c "
import json, sys
eps = json.load(sys.stdin)
target = next((e for e in eps if e.get('Region') == 'us-east-1'), eps[0])
print(target.get('Endpoint'), target.get('Region'))
")
fi
echo "PRIMARY_RC_ARN: ${PRIMARY_RC_ARN:-❌ no seteado}"
echo "SECONDARY_RC_ARN: ${SECONDARY_RC_ARN:-❌ no seteado}"
echo "CLUSTER_ENDPOINT: ${CLUSTER_ENDPOINT:-❌ no seteado}"
echo "FALLBACK_DOMAIN: ${FALLBACK_DOMAIN:-❌ no seteado}"Métodos para Simular el Incidente
Elegí uno de los 3 métodos siguientes para simular la caída:
Método 1: Detener Nginx en EC2 vía SSM Run Command (Recomendado)
Simula una falla real del servidor web sin apagar la VM. El Health Check detectará la caída en ~90 segundos y CloudWatch disparará la alarma tras 3 evaluaciones consecutivas (~3 minutos total).
# Obtener ID de la instancia EC2
if [ -f ~/route53-arc-tf/01_primary/terraform.tfstate ]; then
EC2_ID=$(cd ~/route53-arc-tf/01_primary && terraform output -raw ec2_instance_id 2>/dev/null)
else
EC2_ID=$(aws cloudformation describe-stacks \
--stack-name route53-arc-primary --region $AWS_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`EC2InstanceID`].OutputValue' --output text)
fi
echo "Deteniendo Nginx en EC2: $EC2_ID..."
aws ssm send-command \
--instance-ids $EC2_ID \
--document-name "AWS-RunShellScript" \
--parameters 'commands=["systemctl stop nginx"]' \
--region $AWS_REGION
echo "✅ Nginx detenido. El Health Check fallará en ~90s → CloudWatch Alarm en ~3 min → Failover Lambda."Consejo
Después de ejecutar el Método 1, bajá directamente a la sección “Monitoreo en Tiempo Real” y ejecutá el loop de seguimiento. El failover tardará ~3 minutos en completarse — el loop te mostrará el momento exacto en que los Routing Controls cambien a Primario: Off | Secundario: On.
Método 2: Forzar Estado ALARM en CloudWatch (más rápido)
Ideal para pruebas rápidas — el failover ocurre en segundos sin esperar el Health Check.
CW_ALARM_NAME="route53-arc-primary-unhealthy-with-sns"
aws cloudwatch set-alarm-state \
--alarm-name $CW_ALARM_NAME \
--state-value ALARM \
--state-reason "Simulación de incidente – roLearning Workshop" \
--region $AWS_REGION
echo "✅ Estado ALARM forzado. SNS y Lambda Failover se dispararán en segundos."Método 3: Invocación Directa de la Lambda
Simula el evento SNS invocando la función directamente, útil para aislar y testear la lógica Lambda.
aws lambda invoke \
--function-name route53-arc-failover-handler \
--payload '{"alarm_state":"ALARM"}' \
--cli-binary-format raw-in-base64-out \
/tmp/failover-result.json \
--region $AWS_REGION
cat /tmp/failover-result.json; echoMonitoreo en Tiempo Real del Failover
echo "=== Monitoreando Routing Controls ==="
if [ -z "$PRIMARY_RC_ARN" ] || [ -z "$CLUSTER_ENDPOINT" ]; then
echo "❌ Variables de entorno no seteadas. Ejecutá el bloque 'Recuperar variables' al inicio de este lab."
exit 1
fi
for i in {1..12}; do
P_STATE=$(aws route53-recovery-cluster get-routing-control-state \
--routing-control-arn $PRIMARY_RC_ARN \
--endpoint-url $CLUSTER_ENDPOINT --region $ENDPOINT_REGION \
--query 'RoutingControlState' --output text 2>/dev/null || echo "ERROR")
S_STATE=$(aws route53-recovery-cluster get-routing-control-state \
--routing-control-arn $SECONDARY_RC_ARN \
--endpoint-url $CLUSTER_ENDPOINT --region $ENDPOINT_REGION \
--query 'RoutingControlState' --output text 2>/dev/null || echo "ERROR")
echo "[$i/12] Primario: $P_STATE | Secundario: $S_STATE"
if [ "$P_STATE" = "Off" ] && [ "$S_STATE" = "On" ]; then
echo "🎉 FAILOVER EXITOSO — tráfico redirigido al sitio secundario."
break
fi
sleep 15
done✅ Verificación del Lab 5
echo "=== Verificación del Estado de Incidente ==="
echo "1. Revisá tu casilla de email ($NOTIFICATION_EMAIL)."
echo " Deberías haber recibido: '[FAILOVER ACTIVADO] Sitio primario caido'"
if [ -n "$FALLBACK_DOMAIN" ]; then
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $FALLBACK_DOMAIN 2>/dev/null)
[ "$STATUS" = "200" ] \
&& echo "✅ Sitio secundario responde: HTTP $STATUS" \
|| echo "⚠️ Sitio secundario HTTP: $STATUS"
else
echo "ℹ️ FALLBACK_DOMAIN no seteado — verificá manualmente en el navegador."
fiSiguiente paso → Lab 6: Failback