Índice
- Por qué Alertmanager no puede hacer sonar tu teléfono
- Qué necesitas
- Paso 1 — Crea un canal que te llame
- Paso 2 — Añade un receptor webhook
- Paso 3 — Entiende qué llega realmente
- Paso 4 — Envía las recuperaciones como push silencioso
- Paso 5 — Enruta por severidad, no por todo
- Paso 6 — La trampa del Watchdog
- Ajustes para que no sea el cuento del lobo
- Sonar solo fuera del horario laboral
- Cómo manejar el problema de commonLabels vacío
- Mantener pequeño el payload
- Compartir la alerta con tu equipo
- Lo que esta configuración no te da
- Resolución de problemas
- Preguntas frecuentes
- ¿Prometheus Alertmanager puede hacer una llamada de forma nativa?
- ¿La llamada sortea el modo No molestar?
- ¿Funciona con Alertmanager tras un cortafuegos o dentro de Kubernetes?
- ¿Cómo dejo de recibir llamadas cuando una alerta se resuelve?
- ¿Por qué mi teléfono suena cada cuatro horas por la misma alerta?
- ¿Pueden llamar a varias personas por la misma alerta?
- ¿Filtro la severidad en Alertmanager o en las condiciones de Echobell?
- Cierre
- Relacionado
Alertmanager no tiene receptor de voz. Para recibir una llamada cuando se dispara una alerta de Prometheus, añade un receptor webhook_configs que apunte a un canal de Echobell cuyo tipo de suscripción sea Llamada. Esta guía cubre el YAML exacto, la condición que evita que las alertas resueltas te llamen, el enrutado por severidad y la alerta Watchdog que, si no, hará sonar tu teléfono cada cuatro horas para siempre.
Prometheus es la pila de métricas por defecto de casi toda la infraestructura construida en la última década, y Alertmanager es realmente bueno en las partes difíciles: deduplicar alertas, agruparlas, silenciarlas durante el mantenimiento e inhibir el ruido aguas abajo cuando falla una dependencia aguas arriba.
Lo único que no hará es despertar a nadie.
Por qué Alertmanager no puede hacer sonar tu teléfono
Alertmanager incluye receptores para email, Slack, PagerDuty, OpsGenie, Discord, Telegram, Pushover, Webex, MS Teams y una docena más. Todos entregan un mensaje, y los mensajes están sujetos al interruptor de silencio, al modo No molestar y a los modos de Concentración de iOS. A las 03:00 eso significa que la alerta llega y no pasa nada.
No existe voice_configs. Las opciones a las que suele llegar la gente son:
- PagerDuty / OpsGenie / Splunk On-Call: sí llaman, y son plataformas completas de gestión de incidentes con precio por puesto a juego. La respuesta correcta si necesitas rotaciones y árboles de escalado; excesiva si solo quieres que suene un teléfono. (OpsGenie, además, está cerrando, y por eso tantos equipos están reevaluando esta capa ahora mismo.)
- Puentes SMS como Sachet: ejecutas otro servicio, pagas a una pasarela por mensaje y el SMS sigue llegando como un mensaje. En iOS un texto no rompe el modo Concentración salvo que el remitente esté en tu lista de permitidos.
- Pegamento sobre Twilio: escribes un pequeño receptor de webhooks, compras un número, pagas por llamada y ahora eres dueño de una pieza de infraestructura de producción cuyo único trabajo es hacer sonar un teléfono.
El receptor webhook genérico es la vía de escape. Publica un JSON documentado en cualquier URL, y eso es todo lo que necesitas.
Qué necesitas
- Un Prometheus + Alertmanager en marcha y acceso para editar
alertmanager.yml - Echobell instalado (App Store / Google Play)
- Diez minutos
Esta guía está escrita contra Alertmanager 0.31. El payload del webhook lleva años en version: "4", así que las versiones 0.2x se comportan igual.
Tu Alertmanager necesita HTTPS saliente hacia hook.echobell.one. No necesita ser accesible desde internet, así que un Alertmanager dentro de un clúster, de una VPC o de un homelab funciona perfectamente.
Paso 1 — Crea un canal que te llame
En Echobell, crea un canal llamado algo como Prometheus Critical. Pon su tipo de notificación de suscripción en Llamada. Este es el ajuste que importa: las alertas de tipo Llamada llegan como una pantalla de llamada entrante y suenan a través del modo Concentración y No molestar de iOS, cosa que una notificación push no hace.
Configura las plantillas para leer el payload de Alertmanager directamente:
Title: 🔴 {{commonLabels.alertname}} on {{commonLabels.instance}}
Body: {{commonAnnotations.summary}}
{{commonAnnotations.description}}
Y, en Ajustes avanzados, una plantilla de enlace para que el registro de la notificación salte directo a la gráfica:
{{alerts[0].generatorURL}}
Después copia la URL del webhook del canal:
https://hook.echobell.one/t/<channel-token>
Trata esa URL como un secreto: cualquiera que la tenga puede hacer sonar tu teléfono.
Paso 2 — Añade un receptor webhook
En alertmanager.yml:
route:
group_by: ["alertname", "cluster", "service"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: echobell-critical
receivers:
- name: echobell-critical
webhook_configs:
- url: "https://hook.echobell.one/t/<channel-token>"
send_resolved: false
Recarga con curl -X POST http://localhost:9093/-/reload o con SIGHUP.
Fíjate en send_resolved: false. El valor por defecto de un receptor webhook es true, a diferencia de la mayoría de receptores de Alertmanager, así que omitirlo significa que tu teléfono suena cuando el servicio se rompe y vuelve a sonar cuando se arregla solo. Esa segunda llamada es la que enseña a la gente a ignorar la primera. El paso 4 muestra cómo recuperar el aviso de recuperación sin el timbre.
Paso 3 — Entiende qué llega realmente
Alertmanager agrupa las alertas y luego hace un POST por grupo:
{
"version": "4",
"groupKey": "{}:{alertname=\"HighErrorRate\"}",
"truncatedAlerts": 0,
"status": "firing",
"receiver": "echobell-critical",
"groupLabels": { "alertname": "HighErrorRate" },
"commonLabels": { "alertname": "HighErrorRate", "severity": "critical" },
"commonAnnotations": { "summary": "Error rate above 5% for 10m" },
"externalURL": "http://alertmanager.internal:9093",
"alerts": [
{
"status": "firing",
"labels": { "alertname": "HighErrorRate", "instance": "api-7d9f:8080" },
"annotations": { "summary": "Error rate above 5% for 10m" },
"startsAt": "2026-09-04T02:41:07.351Z",
"endsAt": "0001-01-01T00:00:00Z",
"generatorURL": "http://prometheus:9090/graph?g0.expr=...",
"fingerprint": "a1b2c3d4e5f60718"
}
]
}
Echobell lee el cuerpo JSON tal cual, así que todos esos campos están disponibles en plantillas y condiciones. El acceso anidado funciona con cualquiera de las dos sintaxis: {{commonLabels.severity}} o {{alerts[0].labels["instance"]}}.
Dos propiedades de este payload gobiernan todo lo que viene después:
El status de nivel superior es firing si alguna alerta del grupo está activa. Solo pasa a resolved cuando todas las alertas del grupo se han resuelto. Eso lo convierte en algo limpio sobre lo que filtrar.
commonLabels contiene solo las etiquetas compartidas por todas las alertas del grupo. Esta es la sorpresa más común. Si group_by es lo bastante amplio como para que un webhook lleve HighErrorRate de tres instancias distintas, commonLabels.instance no existe y {{commonLabels.instance}} se renderiza como cadena vacía. Más abajo hay una sección sobre cómo manejarlo.
Paso 4 — Envía las recuperaciones como push silencioso
Sigues queriendo saber cuándo se recupera algo; simplemente no quieres que te llamen por ello. Añade un segundo canal de Echobell llamado Prometheus Recovered, ponlo en tipo Normal, dale estas plantillas:
Title: ✅ {{commonLabels.alertname}} resolved
Body: {{commonAnnotations.summary}}
y, en Ajustes avanzados, esta condición:
status == "resolved"
Las condiciones son expresiones que se evalúan antes de entregar nada. Si la expresión es falsa, Echobell acepta la petición y no envía nada.
Después apunta el mismo receptor a ambos canales: un receptor puede tener varios webhook_configs.
receivers:
- name: echobell-critical
webhook_configs:
# Hace sonar el teléfono. Solo cuando está activa.
- url: "https://hook.echobell.one/t/<calling-channel-token>"
send_resolved: false
# Push silencioso. La condición del canal descarta la mitad "firing".
- url: "https://hook.echobell.one/t/<recovery-channel-token>"
send_resolved: true
El canal de recuperación recibe payloads tanto de firing como de resolved y descarta los primeros. Resultado: la caída suena, la recuperación llega como un push que lees por la mañana.
Paso 5 — Enruta por severidad, no por todo
Una ruta que lo manda todo a un canal de llamada es una máquina de producir llamadas ignoradas. Divide por severidad en Alertmanager, que es donde pertenece el árbol de enrutado:
route:
group_by: ["alertname", "cluster", "service"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: echobell-warning
routes:
# Watchdog nunca llega a un humano. Ver Paso 6.
- matchers:
- alertname = "Watchdog"
receiver: "null"
- matchers:
- severity = "critical"
receiver: echobell-critical
group_wait: 10s
repeat_interval: 1h
receivers:
- name: "null"
- name: echobell-critical
webhook_configs:
- url: "https://hook.echobell.one/t/<calling-channel-token>"
send_resolved: false
- name: echobell-warning
webhook_configs:
- url: "https://hook.echobell.one/t/<normal-channel-token>"
send_resolved: true
Las rutas se evalúan de arriba abajo y gana la primera coincidencia: continue es false por defecto. Por eso el orden importa: la ruta de Watchdog tiene que ir por encima de cualquier cosa que pudiera tragársela.
Si prefieres quedarte con un solo canal y filtrar del lado de Echobell, la condición equivalente es:
status == "firing" && commonLabels.severity == "critical"
Normalmente es mejor hacerlo en Alertmanager, porque así severity también gobierna group_wait y repeat_interval. Hacerlo en Echobell es mejor cuando hoy no puedes mergear un cambio de configuración.
Paso 6 — La trampa del Watchdog
Si usas kube-prometheus-stack, tienes una alerta llamada Watchdog cuya expresión es vector(1). Está diseñada para dispararse siempre: existe para que un sistema externo pueda notar que Prometheus se ha parado. La configuración por defecto la enruta a un receptor null.
Apunta una ruta catch-all a un canal de llamada sin excluirla y Watchdog llamará a tu teléfono cada repeat_interval, para siempre, empezando de inmediato. Esta es la razón número uno por la que la gente concluye que las alertas telefónicas "no funcionan".
Mantén la ruta null del paso 5. Y luego, opcionalmente, haz con ella algo útil: convierte Watchdog en un verdadero dead man's switch.
- matchers:
- alertname = "Watchdog"
receiver: deadmansswitch
group_wait: 0s
group_interval: 1m
repeat_interval: 50s
receivers:
- name: deadmansswitch
webhook_configs:
- url: "https://hc-ping.com/<your-check-uuid>"
send_resolved: false
Echobell no puede ser el dead man's switch: alerta cuando llega una petición, no cuando dejan de llegar. Así que envía el ping del Watchdog a un servicio hecho para detectar silencios (Healthchecks.io, Cronitor, Dead Man's Snitch), y luego apunta el webhook de "check caído" de ese servicio a tu canal de llamada de Echobell. Ahora una llamada significa "la monitorización está muerta", que es la alerta por la que más quieres que te despierten y la que nadie configura.
Ajustes para que no sea el cuento del lobo
Tres ajustes de Alertmanager hacen casi todo el trabajo, más uno de Prometheus:
| Ajuste | Dónde | Qué hace |
|---|---|---|
for: | Regla de alerta | Cuánto debe mantenerse la condición antes de dispararse. Tu primera defensa frente a un parpadeo de dos segundos. |
group_wait | Ruta | Cuánto esperar a más alertas antes de la primera notificación. 30s por defecto; bájalo a 10s para crítico. |
group_interval | Ruta | Intervalo mínimo antes de notificar sobre alertas nuevas de un grupo existente. 5m por defecto. |
repeat_interval | Ruta | Cada cuánto se vuelve a notificar una alerta sin resolver. 4h por defecto, así que una caída nocturna te llama a las 03:00 y otra vez a las 07:00. |
repeat_interval es el que merece reflexión. Cuatro horas es mucho tiempo para dejar algo roto; veinte minutos es una máquina para que acabes desactivando el canal. Una hora en crítico es un buen punto de partida.
Si quieres que una llamada no atendida se reintente de inmediato en lugar de esperar al siguiente repeat_interval, activa Reintentar llamada fallida en los ajustes de la app de Echobell.
Sonar solo fuera del horario laboral
Durante la jornada probablemente ya estés mirando un panel. Las variables de tiempo del sistema de Echobell (todas en UTC) permiten que un canal se comporte distinto según la hora, sin una segunda ruta en Alertmanager:
status == "firing" && (hour >= 17 || hour < 9)
Eso te llama solo fuera de 09:00–17:00 UTC. Apunta un segundo canal, de tipo Normal, a la franja inversa para los push diurnos:
status == "firing" && hour >= 9 && hour < 17
Añade dayOfWeek >= 1 && dayOfWeek <= 5 para tratar también el fin de semana como fuera de horario. Recuerda que siempre se calculan en UTC: compensa según tu zona horaria. Hay un tratamiento más completo en notificaciones por ventana de tiempo con condiciones UTC.
Cómo manejar el problema de commonLabels vacío
Cuando un grupo contiene alertas de varias instancias, commonLabels.instance desaparece y el título de tu notificación queda como 🔴 HighErrorRate on .
Tres salidas, por orden de preferencia:
- Mete la etiqueta en
group_by. Sigroup_byincluyeinstance, todas las alertas de un grupo la comparten ycommonLabels.instanceestá siempre presente. El coste son más notificaciones: una por instancia en lugar de una por nombre de alerta. - Lee la primera alerta.
{{alerts[0].labels.instance}}siempre tiene valor. Es solo una de posiblemente muchas, así que acompáñala de un recuento:{{alerts[0].labels.instance}} (+{{alerts.length}} alertas). - Diseña la etiqueta para que se lea bien vacía. Echobell no tiene operador de valor por defecto —
{{a || "unknown"}}renderiza el texto literaltrue, no un fallback—, así que escribeInstance: {{commonLabels.instance}}en su propia línea, donde un valor vacío se ve obviamente vacío en vez de romper una frase.
Mantener pequeño el payload
Un grupo que cubra cien pods produce un cuerpo JSON grande, y Echobell rechaza cuerpos de más de 1 MiB con HTTP 413. Limítalo en Alertmanager:
- url: "https://hook.echobell.one/t/<channel-token>"
send_resolved: false
max_alerts: 20
Alertmanager enviará entonces como mucho veinte alertas y pondrá en truncatedAlerts el número que descartó, que puedes mostrar en el cuerpo:
Body: {{commonAnnotations.summary}}
Alerts: {{alerts.length}} (+{{truncatedAlerts}} truncadas)
Compartir la alerta con tu equipo
Un canal de Echobell se puede compartir mediante un enlace de suscripción, y cada suscriptor elige su propio tipo de notificación. Así, la misma ruta puede hacer sonar el teléfono del ingeniero de guardia y llegar como push normal para el resto, sin precio por puesto y sin reglas de enrutado extra en Alertmanager.
También encaja con la razón por la que muchos equipos autoalojan Prometheus: tus métricas y reglas de alerta se quedan en tu infraestructura, y Echobell guarda el contenido y el historial de notificaciones en el dispositivo, no en sus servidores.
Lo que esta configuración no te da
Ser honesto sobre el límite te ahorra una mala migración más adelante. Echobell es una capa de entrega, no una plataforma de gestión de incidentes. No tiene:
- Calendarios de guardia ni relevos follow-the-sun
- Árboles de escalado que avisen a una segunda persona si la primera no responde
- Líneas temporales de incidentes, seguimiento de reconocimiento ni herramientas de postmortem
Si tu equipo necesita eso, necesitas PagerDuty, Grafana Cloud IRM o similar. Lo que esto cubre es el hueco concreto que deja Alertmanager: convertir una alerta activa en un teléfono que suena de verdad. Para operadores en solitario, equipos pequeños y homelabs, eso suele ser todo el requisito.
Resolución de problemas
No llega absolutamente nada. Mira primero los logs del propio Alertmanager (level=error component=dispatcher) y luego confirma que la ruta resuelve a tu receptor: amtool config routes test severity=critical alertname=HighErrorRate te dice en qué receptor caería una alerta sin esperar a que se dispare una.
Echobell devuelve HTTP 404. El token del canal es incorrecto o el canal fue eliminado. Un token desconocido es un 404, no un éxito silencioso.
Echobell devuelve 200 con "notificationTriggered": false. Tu condición evaluó a falso. El cuerpo de la respuesta también lleva "conditionsMet": false, que es la forma más rápida de distinguir "mi condición está mal" de "mi webhook nunca llegó". Comprueba status == "firing" contra lo que Alertmanager envió realmente: el status de nivel superior, no alerts[0].status.
HTTP 413. El payload superó 1 MiB. Configura max_alerts como arriba.
HTTP 405. El canal tiene POST Only activado y algo envió un GET. Alertmanager hace POST, así que esto suele significar que probaste la URL en un navegador.
El título tiene un hueco vacío. commonLabels no contenía esa etiqueta para ese grupo. Ver la sección anterior.
No suena, pero la notificación llega. El tipo de notificación de la suscripción es Normal o Urgente, no Llamada. El tipo se elige por suscriptor, así que revísalo en el dispositivo que no suena.
Probar sin romper producción. Añade una regla con expr: vector(1), un alertname distintivo y severity: critical, deja que se dispare una vez y bórrala. O lanza una a mano:
curl -X POST http://localhost:9093/api/v2/alerts -H 'Content-Type: application/json' -d '[
{"labels":{"alertname":"EchobellTest","severity":"critical"},
"annotations":{"summary":"Testing the phone call path"}}
]'
Preguntas frecuentes
¿Prometheus Alertmanager puede hacer una llamada de forma nativa?
No. Alertmanager tiene receptores para email, Slack, PagerDuty, OpsGenie y muchos más, pero no hay receptor de voz ni de SMS. Las llamadas requieren enrutar el receptor webhook genérico a un servicio que pueda hacerlas, como Echobell, o pagar una plataforma de gestión de incidentes.
¿La llamada sortea el modo No molestar?
Sí. El tipo de notificación Llamada de Echobell se presenta como una llamada entrante, que suena a través del modo Concentración y No molestar de iOS. Los detalles y ajustes están en cómo superar iOS Focus Mode para alertas críticas.
¿Funciona con Alertmanager tras un cortafuegos o dentro de Kubernetes?
Sí. El webhook es una petición HTTPS saliente desde Alertmanager, así que solo necesita alcanzar hook.echobell.one. Tu Alertmanager no necesita dirección pública ni ingress.
¿Cómo dejo de recibir llamadas cuando una alerta se resuelve?
Pon send_resolved: false en la config del webhook que apunta a tu canal de llamada. El receptor webhook usa true por defecto, a diferencia de la mayoría de receptores de Alertmanager, así que es opt-out y no opt-in. Para seguir recibiendo recuperaciones en silencio, añade un segundo canal con la condición status == "resolved".
¿Por qué mi teléfono suena cada cuatro horas por la misma alerta?
Es repeat_interval, que por defecto vale 4h. Alertmanager vuelve a notificar una alerta aún activa con esa cadencia. Ajústalo por ruta: 1h en crítico es una elección habitual. Si las llamadas empezaron justo tras añadir una ruta catch-all, lo más probable es que el culpable sea la alerta Watchdog, siempre activa; ver el paso 6.
¿Pueden llamar a varias personas por la misma alerta?
Sí. Comparte el canal con tus compañeros y cada suscriptor elige su tipo de notificación. Todos los suscritos al canal de llamada reciben el timbre, sin coste por puesto.
¿Filtro la severidad en Alertmanager o en las condiciones de Echobell?
Mejor en Alertmanager: enrutar allí también te permite ajustar group_wait y repeat_interval por severidad, y el árbol de rutas queda en control de versiones con el resto de la configuración. Usa condiciones de Echobell cuando no puedas cambiar la config de Alertmanager, o para filtros que Alertmanager no contempla, como la hora del día.
Cierre
La configuración es un receptor, un send_resolved: false y un árbol de rutas que mantiene todo lo que no sea severity: critical lejos del canal de llamada. Deja tus reglas de alerta, agrupaciones, silencios e inhibiciones exactamente como están, y cierra el hueco entre "Prometheus se dio cuenta" y "una persona se dio cuenta".
Descarga Echobell para iPhone o consíguelo en Google Play, y lanza la alerta EchobellTest de arriba antes de confiar en este camino para algo real.