Alerthub: tu “historial clínico” de alertas de Grafana para EKS

En un equipo MSP, las alertas no son un evento: son el pulso del día a día. Operamos entornos en AWS EKS con un stack clásico de observabilidad (Grafana, Prometheus, Loki y Tempo), y el trabajo cotidiano incluye revisar alertas, entender si son ruido o señal, y actuar rápido cuando algo se degrada.

El problema aparece después, cuando necesitas mirar hacia atrás —para armar un informe, auditar incidentes o encontrar patrones— te das cuenta de que el tiempo real no alcanza. Y si la única “historia” vive en capturas o exportaciones manuales, la trazabilidad se vuelve frágil:

  • 🤔 ¿Qué alertas estuvieron “firing” la semana pasada en el cluster X?
  • 🔁 ¿Qué patrón se repite cada lunes a las 9 AM?
  • 🔊 ¿Qué alertas son ruido y cuáles son señales reales?
  • 📑 ¿Cómo armar un informe mensual con evidencia sólida?

De esa necesidad real (muy típica en un equipo MSP) nace Alerthub: un servicio en Go que recibe webhooks de Grafana Alerting, los normaliza, calcula un fingerprint consistente, y persiste cada evento en PostgreSQL para que después puedas explotar esa data en Grafana (dashboards) o directamente en Excel (reporting).

¿Qué es Alerthub?

Alerthub es un hub para alertas que transforma eventos de Grafana Alerting en un dataset consultable. La idea es simple: si puedes consultar tu historial con SQL, puedes auditar, analizar y reportar sin depender de memoria o capturas.

El problema que resuelve

En Kubernetes, la observabilidad suele estar resuelta “en vivo”. Tienes métricas, logs y dashboards. Pero el historial de alertas, tal como lo necesita un equipo de operación, no siempre queda bien servido.

Lo vimos rápido: cuando queríamos responder “qué pasó la semana pasada”, terminabamos reconstruyendo la historia a mano. Las etiquetas no eran siempre consistentes, correlacionar repeticiones era difícil, y los reportes mensuales consumían tiempo que debería ir a mejorar el sistema, no a perseguir evidencias.

Alerthub parte de una decisión: tratar alertas como eventos y guardarlas con estructura suficiente para poder consultarlas después con fluidez.

Arquitectura de Alto Nivel

La arquitectura es intencionalmente simple.

Componentes principales

  1. Grafana Alerting:

    Envía eventos vía contact point tipo Alertmanager.
  2. Alerthub (API en Go)

    Expone endpoints compatibles:
    • /api/v1/alerts
    • /api/v2/alerts

      Acepta payloads estilo Alertmanager, ya que Grafana agrega automáticamente la ruta de ingesta /api/v1/alerts o en versiones más recientes agrega /api/v2/alerts por defecto al enviar el webhook.
  3. PostgreSQL

    Persiste:
    • alert_events: cada evento firing/resolved
    • alert_state: estado actual
    • alert_episodes: agrupación de repeticiones por regla/huella
  1. Grafana Dashboards / Excel

    Grafana consulta Postgres; Excel exporta desde la misma fuente.

¿Qué hace distinto a Alerthub?

Hasta acá, alguien podría pensar “ok, guarda alertas”. El diferencial aparece en el trabajo que hace antes de persistirlas:

Primero, Alerthub normaliza el evento: define el estado de forma consistente, robustecen identificadores de regla cuando llegan incompletos, completa cluster cuando no viene y deriva deployment desde pod cuando aplica. Esto parece un detalle, pero es lo que hace que después los filtros funcionen y las consultas no se rompan por inconsistencias.

Segundo, calcula un fingerprint determinístico. Ese fingerprint se vuelve el punto de apoyo para agrupar repeticiones, construir episodios y responder preguntas del estilo “cuál fue el último estado real de esta alerta”.

Si querés resumirlo en una línea: Alerthub no guarda JSON, guarda historial utilizable.

En la práctica habilita:

  • Último estado por fingerprint
  • Auditoría y reportes
  • Detección de patrones y alertas ruidosas

Modelo de datos pensado para dashboards

Una de las decisiones más importantes en Alerthub fue cómo guardar las alertas sin caer en dos extremos:

o bien almacenar todo como JSON y sufrir después para filtrar en dashboards, o bien “columnizar” cada label y terminar con una base rígida y llena de migraciones.

El enfoque que elegí es un punto medio pragmático.

Por un lado, Alerthub persiste labels y annotations tal como llegan desde Grafana en campos JSONB. Esto es clave porque en el mundo real los labels cambian: aparecen nuevos, algunos son específicos de un cliente, otros sólo existen durante una etapa, y no quieres perder esa información ni bloquearte cada vez que alguien agrega una etiqueta nueva.

Por otro lado, para lo que se consulta todo el tiempo en operación diaria, Alerthub expone columnas directas. Campos como cluster, namespace, pod, nodepool, deployment, queue, vhost o severity están materializados como columnas para que Grafana pueda filtrar rápido, construir variables y evitar consultas pesadas sobre JSON cada vez que refresca un panel.

El resultado es un modelo que se comporta bien en los dos escenarios típicos:

  • Cuando estás en modo “operación”, quieres filtros rápidos por campos comunes (y que los dashboards respondan sin latencia).
  • Cuando estás investigando algo puntual, puedes apoyarte en el JSONB y consultar cualquier label sin tocar el esquema.

En resumen, te queda lo mejor de ambos mundos: un núcleo optimizado para dashboards y un “escape hatch” flexible para exploración.

Qué habilita este diseño (en pocas líneas):

  • Filtros rápidos y simples en Grafana usando columnas frecuentes.
  • Consultas ad-hoc sobre labels nuevos usando labels->>’mi_label’ o labels @> … sin migraciones.

A continuación se ve un ejemplo de las tablas y cómo queda almacenada una alerta luego de pasar por Alerthub:

Seguridad: autenticación opcional (pensado para entornos reales)

Alerthub soporta autenticación opcional para la ingesta:

  • Basic Auth
  • Bearer Token

Y acepta la request si cumple con cualquiera de los dos cuando están ambos configurados. Esto es importante en AWS/EKS si expones Alerthub por Ingress/ALB y quieres evitar que cualquiera te publique alertas.

Panel de administración: cuando el “Resolved” no llega

En un mundo ideal, Grafana Alerting emite siempre el evento Resolved y el ciclo de vida de la alerta queda perfectamente trazado. En la práctica, hay casos (poco frecuentes, pero reales) donde Grafana no notifica el cierre, y eso genera un efecto colateral indeseado: Alerthub mantiene la alerta como firing. Esto conlleva a que los dashboards queden “bloqueados” mostrando incidentes activos que ya no existen. Por lo tanto, los conteos y métricas derivadas siguen reportando un estado incorrecto

Para resolver este edge case, Alerthub incluye un panel de administración accesible desde el endpoint:/admin

Este panel lista todas las alertas activas y permite marcarlas como resueltas manualmente cuando el webhook de Resolved nunca llegó.

Qué hace exactamente el “Resolve” manual

Cuando resuelves una alerta desde /admin, Alerthub:

  1. Genera el evento de cierre (equivalente a un resolved).
  2. Actualiza el estado actual en la base de datos para que deje de figurar como firing.
  3. Agrega una marca auditable en las annotations para trazabilidad, por ejemplo:
  • “manual_resolution”: “eliminacion manual”

De esta forma, no solo corriges el estado operativo, sino que además queda registro explícito de que el cierre fue manual.

Cómo cerrar una alerta manualmente

  1. Abre: http://<host>:<port>/admin
  2. Localiza la alerta que quedó abierta por su fingerprint.
  3. Presiona Resolve para que Alerthub:
    • genere el evento de cierre,
    • agregue el annotation,
    • y actualice el estado en la base.

Este flujo es especialmente útil para desbloquear dashboards cuando el evento Resolved no llega (un comportamiento que puede ocurrir en algunos canales/configuraciones de Grafana) y evitar que el histórico quede contaminado con incidentes “eternos”.

Deploy en Kubernetes con Helm: simple, pero flexible

El chart de Helm despliega:

  • ✅Deployment de Alerthub
  • ✅Service
  • ✅Ingress opcional (si lo necesitas)
  • ✅PostgreSQL opcional (StatefulSet embebido)
  • ✅Inicialización del schema vía SQL bootstrap

Tres flujos de credenciales

Dependiendo de la instalación puede usar diferentes configuraciones para hacer más sencillo el uso de credenciales:

  1. Credenciales autogeneradas + Postgres embebido

    Ideal para demos, entornos internos simples o pruebas.
  2. RDS-style (user/pass) desde un Secret externo

    Perfecto si usas Amazon RDS (o un Postgres gestionado) y tus credenciales viven en un secreto.
  3. DATABASE_URL inline

    Cuando ya tienes todo armado y solo quieres inyectar la cadena completa.

Integración con Grafana: dos piezas clave

1) Contact Point (Alertmanager) hacia Alerthub

  • En Grafana Alerting, creas un contact point tipo Alertmanager.
  • Apuntar la URL al Ingress/endpoint de Alerthub.
  • Si usas credenciales generadas por Helm, las sacás del Secret.

2) Datasource PostgreSQL para dashboards

  • Agregar un datasource Postgres apuntando al Service de la DB (o a RDS).
  • Ajustar SSL según tu topología (intra-cluster vs externo).

Dashboards listos para usar

El repo incluye dashboards reutilizables:

  1. Tables Inspector

    Para entender y explorar tablas y columnas.
  2. Full Alert History

    Historial total sin filtros: ideal para auditoría.
  3. Alert History sin “queue”

    Para excluir alertas de sistemas de colas y reducir ruido.
  4. Only “queue” alerts

    Para aislar incidentes de colas y verlos como “un mundo aparte”.

Conclusión: ¿Por qué es “MSP-Friendly”?

Alerthub nació de una necesidad operativa concreta: convertir alertas en evidencia. En un MSP, donde todo escala, tener historial consultable deja de ser “nice to have” y pasa a ser una pieza de operación.

Dejamos en el repositorio la documentación completa (deploy con Helm, ejemplos de Grafana, dashboards y guía de labels) para quienes quieran replicar el enfoque o tomar ideas.

👉 LINK AL REPO https://github.com/craftech-io/alerthub

Agenda una reunión con nosotros y descubre cómo podemos ayudarte.

Leave a Reply

Your email address will not be published. Required fields are marked *

Let's talk

Interested in working with us? Fill out the form below, and we'll get in touch with you shortly. Let's bring your project to life!