Health Checks en Auto Scaling Groups: Cuándo cambiar de EC2 a ELB y por qué tu ASG termina instancias sanas

Tu Auto Scaling Group está terminando instancias que aparentemente funcionan bien — el proceso corre, el sistema operativo responde, pero el ASG las reemplaza de todas formas. Antes de cambiar el tipo de health check de 'EC2' a 'ELB', necesitas entender exactamente qué evalúa cada modo y qué consecuencias tiene ese cambio en producción.

TL;DR — Resumen rápido

AspectoHealth Check EC2Health Check ELB
¿Qué evalúa?Estado del hipervisor / instancia EC2Respuesta HTTP/TCP de la aplicación
Fuente de verdadAWS EC2 status checksTarget Group health del Load Balancer
Instancia 'running' pero app caídaConsidera la instancia sanaConsidera la instancia no sana
Riesgo principalTráfico dirigido a instancias sin appTerminaciones en cascada si el LB tiene mala configuración
Cuándo usarloWorkloads sin LB, workers, batchAplicaciones web detrás de ALB/NLB

Cómo funcionan los health checks en Auto Scaling Groups

El ASG necesita decidir si una instancia debe seguir en el grupo o ser reemplazada. Para eso consulta una fuente de estado — y esa fuente cambia completamente dependiendo del tipo configurado.

Con el tipo EC2, el ASG consulta los EC2 instance status checks del hipervisor. Una instancia está 'unhealthy' solo si el hardware subyacente falla, la instancia entra en estado stopped, terminated, o los system/instance checks reportan fallo. Si tu aplicación crashea pero el sistema operativo sigue corriendo, el ASG no lo sabe — la instancia aparece como sana.

Con el tipo ELB, el ASG delega la evaluación al Target Group asociado al Load Balancer. El ALB o NLB ejecuta sus propios health checks contra el endpoint configurado (por ejemplo, GET /health). Si la instancia falla esos checks, el Target Group la marca como unhealthy, y el ASG actúa sobre esa señal para terminarla y lanzar un reemplazo.

graph TD ASG["Auto Scaling Group"] subgraph EC2Path["Tipo: EC2"] HV["Hipervisor AWS"] EC2Check["EC2 Status Checks
(system + instance)"] end subgraph ELBPath["Tipo: ELB"] ALB["Application Load Balancer"] TG["Target Group"] AppEndpoint["App: GET /health"] end ASG -->|"consulta estado"| HV HV --> EC2Check EC2Check -->|"running = sana"| ASG ASG -->|"consulta estado"| TG ALB -->|"health check periódico"| AppEndpoint AppEndpoint -->|"200 OK / fallo"| TG TG -->|"healthy / unhealthy"| ASG ASG -->|"unhealthy → terminar"| Terminate["Terminar instancia"]
  1. EC2 Health Check path: El ASG consulta directamente el estado del hipervisor EC2. Solo detecta fallos de infraestructura, no de aplicación.
  2. ELB Health Check path: El ALB ejecuta peticiones periódicas al endpoint de salud. Si falla el umbral configurado, el Target Group marca la instancia como unhealthy y el ASG recibe esa señal.
  3. Grace period: Durante el periodo de gracia, el ASG ignora los resultados del health check para dar tiempo al bootstrap de la instancia. Un grace period insuficiente es la causa más común de terminaciones prematuras.

Por qué el ASG termina instancias que parecen sanas — diagnóstico por capas

Antes de cambiar el tipo de health check, hay que confirmar en qué capa está fallando la evaluación. Cambiar de EC2 a ELB sin revisar la configuración del Target Group puede empeorar el problema.

Paso 1: Confirmar el estado real de la instancia en el ASG

El primer lugar donde mirar es la actividad del ASG. Los eventos de scaling muestran exactamente qué razón registró el sistema al terminar cada instancia — sin esto, cualquier hipótesis es especulación.

aws autoscaling describe-scaling-activities \
  --auto-scaling-group-name nombre-de-tu-asg \
  --region us-east-1 \
  --query 'Activities[?StatusCode==`Failed` || contains(Description, `Terminating`)].[ActivityId,Description,Cause,StatusMessage]' \
  --output table

Busca en el campo Cause si dice 'Instance failed ELB health checks' o 'Instance failed EC2 health checks'. Eso confirma qué capa está disparando la terminación.

Paso 2: Revisar el health check grace period

El grace period es el tiempo que el ASG espera después del lanzamiento antes de evaluar el estado de la instancia. Si tu aplicación tarda 3 minutos en arrancar y el grace period es 60 segundos, el ASG va a terminar instancias perfectamente funcionales durante el bootstrap — esto es el error más frecuente y el más silencioso.

aws autoscaling describe-auto-scaling-groups \
  --auto-scaling-group-names nombre-de-tu-asg \
  --region us-east-1 \
  --query 'AutoScalingGroups[0].{HealthCheckType:HealthCheckType,GracePeriod:HealthCheckGracePeriod}' \
  --output json

Si el grace period es menor que el tiempo real de arranque de tu aplicación, ese es el problema — no el tipo de health check. Ajústalo antes de cualquier otro cambio:

aws autoscaling update-auto-scaling-group \
  --auto-scaling-group-name nombre-de-tu-asg \
  --health-check-grace-period 300 \
  --region us-east-1

Paso 3: Verificar el estado de las instancias en el Target Group

Si ya tienes configurado el tipo ELB, o estás evaluando si cambiarlo, necesitas ver exactamente qué estado reporta el Target Group para cada instancia. Una instancia puede estar running en EC2 y unhealthy en el Target Group simultáneamente.

aws elbv2 describe-target-health \
  --target-group-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/mi-target-group/1234567890abcdef \
  --region us-east-1 \
  --query 'TargetHealthDescriptions[*].{Instance:Target.Id,Port:Target.Port,State:TargetHealth.State,Reason:TargetHealth.Reason,Description:TargetHealth.Description}' \
  --output table

Los valores de Reason más relevantes para diagnosticar son Target.FailedHealthChecks (la app no responde al health check), Target.NotRegistered (la instancia no está en el Target Group), y Target.Timeout (el endpoint responde demasiado lento).

Paso 4: Validar la configuración del health check en el Target Group

Un health check mal configurado en el Target Group es funcionalmente equivalente a no tener health check — o peor, puede marcar instancias sanas como fallidas. Verifica que el path, el puerto, y los umbrales sean correctos para tu aplicación.

aws elbv2 describe-target-groups \
  --target-group-arns arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/mi-target-group/1234567890abcdef \
  --region us-east-1 \
  --query 'TargetGroups[0].{Path:HealthCheckPath,Port:HealthCheckPort,Protocol:HealthCheckProtocol,Interval:HealthCheckIntervalSeconds,Timeout:HealthCheckTimeoutSeconds,HealthyThreshold:HealthyThresholdCount,UnhealthyThreshold:UnhealthyThresholdCount}' \
  --output json

Presta atención especial al UnhealthyThresholdCount: si está en 2 con un intervalo de 30 segundos, una instancia puede ser marcada como unhealthy en apenas 60 segundos después de un fallo transitorio.

Paso 5: Cambiar el tipo de health check del ASG

Solo ejecuta este paso si confirmaste que el problema es que el ASG no detecta fallos de aplicación (tipo EC2 activo, app caída, instancia no terminada). Si el problema era el grace period o la configuración del Target Group, este cambio no es necesario todavía.

aws autoscaling update-auto-scaling-group \
  --auto-scaling-group-name nombre-de-tu-asg \
  --health-check-type ELB \
  --health-check-grace-period 300 \
  --region us-east-1

Nota: este comando actualiza ambos parámetros simultáneamente. Cambiar a ELB sin ajustar el grace period al mismo tiempo es un error operacional común — las instancias nuevas serán evaluadas antes de que la app esté lista.

flowchart TD Start(["ASG termina instancias inesperadamente"]) Q1{"¿Cuál es el Cause
en scaling activities?"} Q2{"¿Grace period mayor
que tiempo de bootstrap?"} Q3{"¿Target Group reporta
instancias unhealthy?"} Q4{"¿Health check path
y puerto son correctos?"} FixGrace["Aumentar health-check-grace-period"] FixTG["Corregir configuración
del Target Group"] ChangeType["Cambiar ASG a tipo ELB
+ ajustar grace period"] Done(["Verificar con set-instance-health"]) Start --> Q1 Q1 -->|"EC2 health checks"| Q2 Q1 -->|"ELB health checks"| Q3 Q2 -->|"No"| FixGrace Q2 -->|"Sí — app cae sin detección"| ChangeType Q3 -->|"Sí"| Q4 Q3 -->|"No — revisar SuspendedProcesses"| Done Q4 -->|"No"| FixTG Q4 -->|"Sí — problema en la app"| Done FixGrace --> Done FixTG --> Done ChangeType --> Done

El error clásico: cambiar a ELB y disparar terminaciones en cascada

Aquí está el patrón que se repite en producción: el equipo cambia el tipo de health check a ELB para detectar fallos de aplicación. Inmediatamente, el ASG empieza a terminar instancias que antes parecían sanas. El pánico lleva a revertir el cambio, y el problema real nunca se resuelve.

Lo que realmente pasó: el health check del Target Group estaba apuntando a / en lugar de /health, y la aplicación devolvía un redirect 301 en ese path. El ALB interpretaba el 301 como fallo (el health check esperaba un 200). Con el tipo EC2, ese fallo era invisible. Al cambiar a ELB, el ASG finalmente vio lo que el Load Balancer ya sabía desde hace tiempo: ninguna instancia pasaba el health check.

La solución no era revertir a EC2 — era corregir el path del health check en el Target Group.

Cambiar el tipo de health check del ASG no modifica cómo el Load Balancer evalúa las instancias. Solo cambia si el ASG escucha esa evaluación para tomar decisiones de terminación.

Marcar manualmente una instancia como unhealthy para pruebas

Antes de confiar en que el nuevo tipo de health check funciona, conviene verificarlo de forma controlada. Puedes forzar el estado unhealthy en una instancia específica y confirmar que el ASG la termina y reemplaza correctamente.

aws autoscaling set-instance-health \
  --instance-id i-1234567890abcdef0 \
  --health-status Unhealthy \
  --region us-east-1

El ASG debería terminar esa instancia y lanzar un reemplazo. Si no lo hace en un tiempo razonable, revisa si hay políticas de suspensión activas en el grupo:

aws autoscaling describe-auto-scaling-groups \
  --auto-scaling-group-names nombre-de-tu-asg \
  --region us-east-1 \
  --query 'AutoScalingGroups[0].SuspendedProcesses' \
  --output json

Si el proceso HealthCheck o Terminate aparece suspendido, el ASG no actuará sobre los estados unhealthy hasta que se reanuden:

aws autoscaling resume-processes \
  --auto-scaling-group-name nombre-de-tu-asg \
  --scaling-processes HealthCheck Terminate \
  --region us-east-1

IAM mínimo necesario para ejecutar estos diagnósticos

🔽 Ver política IAM de diagnóstico (solo lectura + set-instance-health)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ASGDiagnosticReadOnly",
      "Effect": "Allow",
      "Action": [
        "autoscaling:DescribeAutoScalingGroups",
        "autoscaling:DescribeScalingActivities",
        "autoscaling:DescribeAutoScalingInstances"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ELBTargetHealthRead",
      "Effect": "Allow",
      "Action": [
        "elasticloadbalancing:DescribeTargetHealth",
        "elasticloadbalancing:DescribeTargetGroups"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ASGHealthCheckWrite",
      "Effect": "Allow",
      "Action": [
        "autoscaling:SetInstanceHealth",
        "autoscaling:UpdateAutoScalingGroup",
        "autoscaling:ResumeProcesses"
      ],
      "Resource": "arn:aws:autoscaling:us-east-1:123456789012:autoScalingGroup:*:autoScalingGroupName/nombre-de-tu-asg"
    }
  ]
}

Las acciones Describe de AutoScaling y ELB requieren "Resource": "*" — no admiten restricción por ARN específico según la Service Authorization Reference de AWS.

Auto Scaling Group Health Checks: cuándo usar cada tipo

La decisión no es binaria entre 'EC2 es malo' y 'ELB es mejor'. Depende de la arquitectura real del workload.

EscenarioTipo recomendadoRazón
Aplicación web detrás de ALB/NLBELBEl LB ya evalúa la salud de la app — el ASG debe escuchar esa señal
Workers / procesadores de colas SQSEC2No hay LB; la salud se mide por el proceso, no por HTTP
Instancias batch o de procesamientoEC2No exponen endpoints HTTP; ELB no aplica
Microservicios con health endpoint propioELBEl endpoint /health refleja dependencias internas (DB, cache)
ASG sin Target Group asociadoEC2ELB requiere que el ASG esté asociado a un Target Group activo

Próximos pasos y recursos

Si después de seguir este diagnóstico el ASG sigue terminando instancias de forma inesperada, el siguiente vector a investigar son las políticas de scaling reactivo — una alarma de CloudWatch mal calibrada puede estar disparando scale-in y terminando instancias independientemente del health check. Revisa también si tienes Instance Refresh activo, ya que ese proceso termina instancias de forma intencional como parte de una actualización de configuración.

Glosario de términos clave

TérminoDefinición operacional
Health Check Grace PeriodTiempo en segundos que el ASG espera tras lanzar una instancia antes de evaluar su estado. Debe ser mayor que el tiempo de bootstrap de la aplicación.
EC2 Health CheckEvaluación basada en los status checks del hipervisor EC2. Solo detecta fallos de infraestructura, no de aplicación.
ELB Health Check (en ASG)El ASG usa el estado reportado por el Target Group del Load Balancer para determinar si una instancia debe ser reemplazada.
Target Group HealthEstado de cada instancia registrada en un Target Group, determinado por las peticiones periódicas del ALB/NLB al endpoint configurado.
SuspendedProcessesProcesos del ASG (como HealthCheck o Terminate) que han sido pausados manualmente o por operaciones como Instance Refresh, impidiendo acciones automáticas.

Related Posts

Comentarios

Entradas populares de este blog

EC2 sin acceso a Internet en VPC personalizada: Internet Gateway y Route Table

Actualizar Contenido en CloudFront: Cómo Crear una Invalidación para Limpiar el Caché del Edge

Aumentar el Timeout de Lambda: Configuración, Límites y Diagnóstico en Producción