Saltar al contenido
Gontzal Bilbao
← blog

Alarmas de CloudWatch para EC2, probadas con carga real

Creo alarmas de CPU y salud para EC2 con CloudWatch y SNS, por consola y CLI, y compruebo con carga real que el aviso llega.

serie · Alertas en AWS como código
Alarmas de CloudWatch para EC2, probadas con carga real

El problema

Creé tres alarmas para una instancia EC2, por consola y por CLI, y le metí carga hasta que llegó el email. Por el camino tuve que cambiar el periodo de las alarmas, porque la instancia publicaba la CPU cada 5 minutos.

Crear una alarma es fácil. Lo que no se ve hasta probarla es si salta: un umbral mal calibrado o un canal sin confirmar la dejan muda.

Las severidades y el naming salen de Alertas preventivas en AWS como código con Terraform. La versión en código está en Alarmas de infraestructura con Terraform. Lo probé en una cuenta de laboratorio, con nombres e IDs de ejemplo.

idea clave

Una alarma sin prueba real es configuración, no observabilidad.

El canal, por consola

Empiezo por el canal, porque sin él una alarma que salta no avisa a nadie. En Amazon SNS:

  1. Creo un topic Standard llamado demo-infra-alerts.
  2. Le añado una suscripción Email.
  3. Confirmo la suscripción desde el correo que llega.
  4. Lanzo un Publish message de prueba y compruebo que lo recibo.

Solo email al principio. Slack o Chatbot se añaden cuando el flujo ya funciona.

La primera alarma, por consola

La primera la creo en CloudWatch > Alarms, para ver cómo evalúa CloudWatch la métrica sobre la gráfica.

  • Métrica: AWS/EC2 > CPUUtilization, estadística Average.
  • Umbral: mayor que 75.
  • Periodo y evaluación: 300 s y 1 de 1 (ver abajo por qué).
  • Datos ausentes: notBreaching, que la consola muestra como «Correctos (dentro del límite)».
  • Acción: el topic demo-infra-alerts.
  • Nombre: demo-ec2-jumpbox-cpu-warning.

Mi primera versión era 60 s y 5 de 5. No saltaba nunca: la instancia usaba Basic Monitoring y solo publicaba la CPU cada 5 minutos.

MonitorizaciónDato de CPUwarning (5 min)critical (10 min)
Detailedcada minuto60 s, 5 de 560 s, 10 de 10
Basiccada 5 minutos300 s, 1 de 1300 s, 2 de 2

Con 300 s el objetivo es el mismo: si la media de un bloque de 5 minutos pasa de 75 %, salta. No hace falta pagar Detailed Monitoring para validar el flujo.

ojo

Con un periodo más corto que el dato, la alarma nunca reúne los puntos que pide. Y con notBreaching, cada hueco cuenta como «todo bien».

El resto, por CLI

Por terminal el comando exacto queda escrito y se repite igual en otro entorno. Primero declaro las variables una vez:

# terminal con la AWS CLI configurada
REGION="eu-central-1"
ACCOUNT_ID="123456789012"
INSTANCE_ID="i-xxxxxxxxxxxxxxxxx"
SNS_TOPIC_ARN="arn:aws:sns:eu-central-1:123456789012:demo-infra-alerts"

La warning de CPU, igual que la de consola:

# terminal: CPU > 75 % durante un bloque de 5 min
aws cloudwatch put-metric-alarm \
  --region "$REGION" \
  --alarm-name "demo-ec2-jumpbox-cpu-warning" \
  --alarm-description "CPU > 75 % durante 5 min (basic monitoring)" \
  --namespace "AWS/EC2" \
  --metric-name "CPUUtilization" \
  --dimensions Name=InstanceId,Value="$INSTANCE_ID" \
  --statistic Average \
  --period 300 \
  --evaluation-periods 1 \
  --datapoints-to-alarm 1 \
  --threshold 75 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching \
  --alarm-actions "$SNS_TOPIC_ARN"

La critical pide dos bloques de 5 minutos seguidos por encima de 85 %:

# terminal: CPU > 85 % durante dos bloques de 5 min
aws cloudwatch put-metric-alarm \
  --region "$REGION" \
  --alarm-name "demo-ec2-jumpbox-cpu-critical" \
  --alarm-description "CPU > 85 % durante 10 min (basic monitoring)" \
  --namespace "AWS/EC2" \
  --metric-name "CPUUtilization" \
  --dimensions Name=InstanceId,Value="$INSTANCE_ID" \
  --statistic Average \
  --period 300 \
  --evaluation-periods 2 \
  --datapoints-to-alarm 2 \
  --threshold 85 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching \
  --alarm-actions "$SNS_TOPIC_ARN"

Y la de salud de la instancia, que salta con un solo fallo:

# terminal: StatusCheckFailed > 0 en 1 min
aws cloudwatch put-metric-alarm \
  --region "$REGION" \
  --alarm-name "demo-ec2-jumpbox-statuscheckfailed-critical" \
  --alarm-description "StatusCheckFailed > 0" \
  --namespace "AWS/EC2" \
  --metric-name "StatusCheckFailed" \
  --dimensions Name=InstanceId,Value="$INSTANCE_ID" \
  --statistic Maximum \
  --period 60 \
  --evaluation-periods 1 \
  --datapoints-to-alarm 1 \
  --threshold 0 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching \
  --alarm-actions "$SNS_TOPIC_ARN"

Etiquetar y verificar

Las etiquetas las pongo después, con tag-resource. Uso las cinco piezas del naming:

# terminal
ALARM_NAME="demo-ec2-jumpbox-cpu-critical"
ALARM_ARN="arn:aws:cloudwatch:${REGION}:${ACCOUNT_ID}:alarm:${ALARM_NAME}"

aws cloudwatch tag-resource \
  --region "$REGION" \
  --resource-arn "$ALARM_ARN" \
  --tags Key=Environment,Value=demo Key=Service,Value=ec2 \
    Key=Resource,Value=jumpbox Key=Metric,Value=CPUUtilization \
    Key=Severity,Value=critical

Antes de meter carga compruebo que la alarma existe y, sobre todo, que tiene la acción SNS:

# terminal
aws cloudwatch describe-alarms \
  --region "$REGION" \
  --alarm-names "$ALARM_NAME" \
  --query "MetricAlarms[0].{Name:AlarmName,State:StateValue,Actions:AlarmActions,Period:Period,Eval:EvaluationPeriods,Datapoints:DatapointsToAlarm,Threshold:Threshold}"

aws cloudwatch list-tags-for-resource --region "$REGION" --resource-arn "$ALARM_ARN"

La prueba de carga

Para generar CPU no instalé nada: cada proceso yes ocupa un núcleo entero. En una instancia de 4 vCPU, tres procesos dejan la media alrededor del 75 %.

# terminal de la instancia
for i in $(seq 1 3); do yes > /dev/null & done

# si la gráfica se queda justo en el umbral, un cuarto proceso
yes > /dev/null &

# para parar la carga
pkill yes

Mientras dura la carga, sigo el estado de las dos alarmas desde mi terminal:

# terminal
aws cloudwatch describe-alarms \
  --region "$REGION" \
  --alarm-names "demo-ec2-jumpbox-cpu-critical" "demo-ec2-jumpbox-cpu-warning" \
  --query "MetricAlarms[].{Name:AlarmName,State:StateValue,Updated:StateUpdatedTimestamp}" \
  --output table

Tras el primer bloque de 5 minutos, la warning ya ha saltado y la critical sigue esperando el segundo:

# salida de ejemplo
+---------------------------------+---------+------------------------------------+
|               Name              |  State  |              Updated               |
+---------------------------------+---------+------------------------------------+
|  demo-ec2-jumpbox-cpu-critical  |  OK     |  2026-01-15T10:00:00.000000+00:00  |
|  demo-ec2-jumpbox-cpu-warning   |  ALARM  |  2026-01-15T10:20:00.000000+00:00  |
+---------------------------------+---------+------------------------------------+

Doy la prueba por buena cuando llega el email de SNS y, al parar la carga, la alarma vuelve a OK. Apunto tres horas: inicio de la carga, disparo y vuelta a OK. Con eso la prueba se repite igual en otro entorno.

ojo

Si la gráfica se queda en 75, puede que no salte. GreaterThanThreshold es «mayor que», y 75,0 no es mayor que 75.

StatusCheckFailed, sin romper la instancia

Forzar un fallo real de la instancia no compensa en algo que quiero mantener estable. En su lugar, cambio el estado de la alarma a mano:

# terminal
aws cloudwatch set-alarm-state \
  --region "$REGION" \
  --alarm-name "demo-ec2-jumpbox-statuscheckfailed-critical" \
  --state-value ALARM \
  --state-reason "Prueba sintética del canal de aviso"

No simula un fallo de EC2, pero valida lo que importa aquí: el cambio de estado, la acción SNS y la llegada del aviso. En la siguiente evaluación, la alarma vuelve sola a su estado real.

Lo que aprendí

Con Basic Monitoring, una alarma de 60 s y 5 de 5 no salta nunca: tuve que pasarla a 300 s y 1 de 1. Y una CPU clavada en 75,0 no supera un umbral de «mayor que 75».

¿Te ha servido?

Si tienes dudas o lo estás montando tú, cuéntamelo.

Escríbeme Compartir en LinkedIn

sigue leyendo

Alarmas de infraestructura con Terraform

Un módulo Terraform con el topic SNS, la suscripción por email y alarmas de CloudWatch para una instancia fija y para un Auto Scaling Group.

24 feb · 3 miniac

Alertas preventivas en AWS como código con Terraform

Cómo diseño alertas preventivas en AWS como código: pocas alarmas calibradas, naming por entorno, módulo dedicado y rollout dev → staging → prod.

24 feb · 4 miniac