Lab 5: Simulación de Incidente
Lab 5: Simulación de Incidente y Failover
En este laboratorio probaremos la conmutación de tráfico (failover) utilizando 3 métodos distintos de simulación, desde pruebas unitarias directas hasta la simulación real de caída de la instancia EC2.
Paso 1: Cargar variables de entorno
source ~/route53-arc-tf/global.env
# Outputs del Lab 3 (ARC)
cd ~/route53-arc-tf/03_arc
export PRIMARY_RC_ARN=$(terraform output -raw primary_rc_arn)
export SECONDARY_RC_ARN=$(terraform output -raw secondary_rc_arn)
CLUSTER_ENDPOINT=$(terraform output -json arc_cluster_endpoints | python3 -c "
import json, sys
eps = json.load(sys.stdin)
target = next((e for e in eps if e['region'] == 'us-east-1'), eps[0])
print(target['endpoint'])
")
ENDPOINT_REGION="us-east-1"
# Outputs del Lab 1 (EC2)
cd ~/route53-arc-tf/01_primary
export EC2_ID=$(terraform output -raw ec2_instance_id)
export PRIMARY_ALB_DNS=$(terraform output -raw alb_dns_name)
# Outputs del Lab 4 (Automation)
cd ~/route53-arc-tf/04_automation
export ALARM_NAME=$(terraform output -raw alarm_name)
export LAMBDA_NAME=$(terraform output -raw lambda_name)
echo "=== Estado Inicial ==="
echo "📌 ALB DNS: $PRIMARY_ALB_DNS"
echo "📌 EC2 ID: $EC2_ID"
echo "📌 Alarm Name: $ALARM_NAME"
echo "📌 Lambda Name: $LAMBDA_NAME"
echo "📌 Cluster Endpoint: $CLUSTER_ENDPOINT ($ENDPOINT_REGION)"
# Consultar estado actual de los Routing Controls
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 | xargs -I{} echo "🔹 Primario: {}"
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 | xargs -I{} echo "🔹 Secundario: {}"Método 1: Apagar Instancia EC2 / Detener Nginx (Simulación Real de Caída)
¿Qué prueba este método?
Simula un fallo físico o de aplicación real en el servidor web primario. Apagamos la instancia EC2 (o el servicio Nginx) para que el Health Check de Route 53 deje de recibir respuestas HTTP200 OK, la alarma de CloudWatch cambie aALARM, SNS dispare la función Lambda y ARC realice la conmutación al sitio de contingencia (Amplify).
Opción 1.A — Detener la Instancia EC2 desde la CLI:
echo "🛑 Apagando instancia EC2 primario ($EC2_ID)..."
aws ec2 stop-instances --instance-ids $EC2_ID --region $AWS_REGIONOpción 1.B — Detener el servicio Nginx vía SSM (sin apagar la EC2):
echo "🛑 Deteniendo servicio nginx en EC2 primario..."
aws ssm send-command \
--instance-ids $EC2_ID \
--document-name AWS-RunShellScript \
--parameters 'commands=["systemctl stop nginx"]' \
--region $AWS_REGIONOpción 1.C — Reiniciar Nginx vía SSM (para reponer el primario después de 1.B):
# Ejecutar SOLO cuando quieras restaurar nginx para el Lab 6
aws ssm send-command \
--instance-ids $EC2_ID \
--document-name AWS-RunShellScript \
--parameters 'commands=["systemctl start nginx"]' \
--region $AWS_REGIONConsejo
Para el Lab 6 (Failback): Antes de ejecutar el failback necesitás que el sitio primario vuelva a estar saludable.
- Si usaste Opción 1.A (apagaste la EC2):
aws ec2 start-instances --instance-ids $EC2_ID --region $AWS_REGION - Si usaste Opción 1.B (detuviste nginx): usá la Opción 1.C de arriba.
- Si usaste Método 2 o 3: el sitio primario nunca estuvo caído — podés ir directo al Lab 6.
Monitoreo del Failover Automático:
echo "⏳ Monitoreando respuesta del balanceador y cambio de estado en ARC (~2-3 min)..."
for i in $(seq 1 12); do
PRIMARY_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)
# En modo demo (sin dominio real), monitoreamos directo el ALB
if [ "${USE_DOMAIN:-false}" = "true" ]; then
HTTP=$(curl -k -s -o /dev/null -w "%{http_code}" \
--connect-timeout 3 --max-time 5 "https://$APP_SUBDOMAIN.$DOMAIN_NAME/" 2>/dev/null || echo "000")
else
HTTP=$(curl -s -o /dev/null -w "%{http_code}" \
--connect-timeout 3 --max-time 5 "http://$PRIMARY_ALB_DNS/" 2>/dev/null || echo "000")
fi
echo "[$(date '+%H:%M:%S')] HTTP Status: $HTTP | Primary RC: $PRIMARY_STATE"
if [ "$PRIMARY_STATE" = "Off" ]; then
echo "🎉 FAILOVER AUTOMÁTICO COMPLETADO"
break
fi
sleep 20
doneMétodo 2: Forzar Estado de Alarma en CloudWatch (Simulación Rápida)
¿Qué prueba este método?
Permite validar el circuito de automatización (CloudWatch → SNS → Lambda → ARC) de forma instantánea sin esperar el tiempo de evaluación de los Health Checks ni apagar los servidores web.
echo "=== SIMULACIÓN B: Forzando estado ALARM en CloudWatch ==="
aws cloudwatch set-alarm-state \
--alarm-name $ALARM_NAME \
--state-value ALARM \
--state-reason "Simulación de incidente - AWS Route 53 ARC Workshop" \
--region $AWS_REGION
echo "⏳ Esperando respuesta de Lambda (10 segundos)..."
sleep 10
# Verificar cambio de estado en Routing Controls
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 | xargs -I{} echo "🔹 Primario: {} (esperado: Off)"
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 | xargs -I{} echo "🔹 Secundario: {} (esperado: On)"Método 3: Invocación Directa de Lambda (Prueba Unitaria por CLI o Consola)
¿Qué prueba este método?
Valida la ejecución y lógica interna del script Python de la función Lambda (handler.py) probando su comportamiento en seco (dry-run) o forzando la lógica por evento.
Opción 3.A — Desde la CLI:
echo "=== SIMULACIÓN C: Invocación directa de Lambda vía CLI ==="
# Prueba en seco (Dry-run: estado OK no ejecuta failover)
aws lambda invoke \
--function-name $LAMBDA_NAME \
--payload '{"alarm_state":"OK"}' \
--cli-binary-format raw-in-base64-out \
/tmp/lambda-test.json --region $AWS_REGION
echo "Respuesta Lambda (Dry-run):"
cat /tmp/lambda-test.json; echo
# Prueba directa de conmutación
aws lambda invoke \
--function-name $LAMBDA_NAME \
--payload '{"alarm_state":"ALARM"}' \
--cli-binary-format raw-in-base64-out \
/tmp/lambda-failover.json --region $AWS_REGION
echo "Respuesta Lambda (Failover):"
cat /tmp/lambda-failover.json; echoOpción 3.B — Desde la Consola de AWS:
- Ingresá a la consola de AWS Lambda → seleccioá la función
route53-arc-failover-handler. - Pestaña Test → creá un nuevo evento de prueba con el siguiente JSON:
{ "alarm_state": "ALARM" } - Hacé clic en Test y verificá en la pestaña de resultados el log de ejecución y la respuesta
{"statusCode": 200, "body": "FAILOVER_EXECUTED"}.
✅ Verificación del Lab 5
echo "=== Verificación Final Lab 5 ==="
P=$(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)
S=$(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)
[ "$P" = "Off" ] && echo "✅ Primario: $P" || echo "⚠️ Primario: $P"
[ "$S" = "On" ] && echo "✅ Secundario: $S" || echo "⚠️ Secundario: $S"
echo "📬 Revisá tu casilla de correo para la notificación de alerta enviada por SNS."Siguiente paso → Lab 6: Restauración / Failback