DEV Community

Alex Carter
Alex Carter

Posted on

Kubernetes: recibos para depurar alertas de email

Una alerta de Kubernetes puede decir Deployment degraded y aun así no responder la pregunta urgente de la guardia: ¿qué pasó con el correo que debía avisarnos? En un incidente reciente, el pod estaba sano, el proveedor de email también, pero nadie podía demostrar si la notificación había sido creada, enviada o rechazada. El sistema funcionaba; la evidencia no.

Desde entonces trato cada notificación importante como una pequeña transacción. No hace falta guardar el cuerpo completo del mensaje ni montar una plataforma enorme. Hace falta dejar un recibo corto, correlacionable y seguro. Así, una persona puede seguir el recorrido desde la alerta hasta el resultado sin revisar diez dashboards distintos.

El síntoma: una alerta que dice demasiado poco

El patrón típico tiene tres piezas separadas:

  1. Prometheus o el controlador detecta una condición.
  2. Un servicio interno decide enviar un correo.
  3. Un worker habla con el proveedor y actualiza el estado.

Cuando solo vemos el primer evento, cualquier fallo posterior parece igual. Puede ser un timeout, una credencial vencida, un límite del proveedor o un destinatario mal configurado. En la práctica, el mensaje email failed no ayuda mucho durante una guardia.

También conviene que la alerta no aparezca de golpe sin contexto visual. Las señales claras antes de tocar un flujo son útiles en interfaces, pero la misma idea aplica a operaciones: primero mostrar estado, después pedir una acción.

Qué debe contener un recibo

Mi recibo mínimo tiene estos campos:

  • event_id: identificador único de la alerta original.
  • notification_id: identificador del intento de email.
  • created_at y finished_at en UTC.
  • cluster, namespace y nombre del workload.
  • status: queued, sent, failed o suppressed.
  • provider_code: código normalizado, sin secretos ni contenido privado.
  • attempt: número de reintento.

El event_id evita mezclar dos alertas parecidas. El notification_id permite distinguir un reintento de un correo nuevo. Esa diferencia parece pequeña, pero es la que suele faltar cuando el equipo intenta explicar por qué alguien recibió dos avisos.

Nunca pondría un token, una dirección completa de un usuario o el contenido del email en una etiqueta de Kubernetes. Las labels tienen una vida y una visibilidad demasiado amplias. Para buscar un recibo, basta con un identificador opaco y un enlace interno al sistema que conserva los detalles con sus controles de acceso.

Un patrón sencillo en Kubernetes

El Deployment puede publicar métricas y logs estructurados, mientras un worker separado maneja el proveedor. El contrato podría verse así:

{
  "notification_id": "ntf_8f31",
  "event_id": "alert_20260913_041",
  "status": "failed",
  "attempt": 2,
  "provider_code": "rate_limited"
}
Enter fullscreen mode Exit fullscreen mode

El worker debe ser idempotente: si recibe dos veces el mismo notification_id, no crea dos envíos. Para reintentos temporales, usa backoff con un límite claro. Para errores permanentes, marca failed y deja una acción concreta en el runbook. Reintentar para siempre solo convierte un problema pequeño en ruido operativo.

En los logs, mantengo el mismo contexto en cada línea. Un ejemplo práctico sería buscar event_id=alert_20260913_041 y obtener la cola, el pod, el intento y la respuesta normalizada del proveedor. Esto es bastante mas rápido que copiar timestamps a mano entre herramientas.

Cómo investigar el fallo

Cuando llega una alerta sin correo, sigo esta secuencia:

  1. Confirmo que la condición original sigue activa o ya fue resuelta.
  2. Busco el event_id en el servicio que crea notificaciones.
  3. Compruebo si existe un notification_id y cuántos intentos tiene.
  4. Comparo el provider_code con el runbook: ¿es temporal o permanente?
  5. Reviso la salud del worker y su cola, no solo la del API.
  6. Verifico que el último recibo tenga una hora posterior al evento.

Si el último estado es queued durante demasiado tiempo, el problema no está en el envío sino en la cola. Si es sent pero nadie recibió nada, hay que mirar la respuesta del proveedor y la ruta del destinatario, sin asumir que el pod está culpable. Esa separación de capas ahorra bastante vueltas.

Para cambios de nodo o mantenimiento, las alertas que guían durante un drain muestran otro principio importante: cada transición operacional necesita una señal entendible y verificable.

Checklist para la guardia

Antes de dar por terminado el trabajo, compruebo:

  • ¿La alerta tiene un event_id único?
  • ¿Cada intento conserva el mismo notification_id?
  • ¿Los reintentos tienen un máximo y una causa visible?
  • ¿El proveedor devuelve códigos normalizados?
  • ¿Las métricas separan queued, sent y failed?
  • ¿El dashboard enlaza al recibo sin exponer secretos?
  • ¿El runbook explica qué hacer con cada error frecuente?

Si una de esas respuestas es “no se”, no significa que haya que rehacer toda la plataforma. Significa que encontraste el siguiente hueco de observabilidad. Incluso una tabla pequeña en PostgreSQL y logs consistentes suelen ser suficiente para la primera versión.

Preguntas rápidas

¿Necesito almacenar el email completo?

No. Guarda un identificador de destinatario protegido o un hash apropiado para correlación. El recibo debe probar el resultado, no convertirse en un archivo de datos personales.

¿Qué hago con un fallo temporal?

Clasifícalo, reintenta con backoff y registra cada intento. Si la cola supera el límite, genera una alerta diferente: ya no es un fallo de proveedor aislado, es un problema de capacidad o entrega.

¿Dónde entra una bandeja de prueba?

En entornos no productivos puedes usar un free temp email para comprobar el recorrido, siempre que los datos sean sintéticos y la política del equipo lo permita. En algunos apuntes aparece escrito fake e mail com, pero no lo usaría como criterio de seguridad ni como etiqueta de producción.

Cierre

Una alerta de email no termina cuando el worker acepta la tarea. Termina cuando existe un resultado trazable y alguien puede explicar qué ocurrió. Un recibo pequeño, una clave idempotente y estados honestos convierten una notificación vaga en una pista operativa. En la próxima guardia, esa diferencia puede ahorrar más tiempo que otro dashboard brillante.

Top comments (0)