Grafana Alerting evalúa consultas sobre tus fuentes de datos a intervalos regulares y envía una notificación cuando el resultado cruza un umbral. En este tutorial configurarás el envío de correo de Grafana, crearás puntos de contacto para email y Slack, definirás políticas de notificación que envían las alertas críticas a un canal distinto de los avisos, y crearás dos reglas sobre métricas de Prometheus: un servidor que deja de responder y un disco casi lleno. Primero lo harás desde la interfaz y después verás cómo definir lo mismo en archivos YAML versionables.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con Grafana 11 o posterior instalado desde el repositorio oficial de Grafana (paquete grafana, servicio grafana-server).
  • Un usuario no root con privilegios sudo y acceso a Grafana con una cuenta de rol Admin.
  • Una fuente de datos Prometheus configurada en Grafana, y node_exporter enviando métricas a ese Prometheus.
  • Para el email, una cuenta SMTP (servidor, puerto, usuario y contraseña). Para Slack, una URL de webhook entrante.

Cómo funciona Grafana Alerting

Una alerta recorre cuatro piezas:

PiezaFunción
Regla de alertaConsulta, condición y tiempo de espera. Se guarda en una carpeta y un grupo de evaluación que fija cada cuánto se evalúa
EtiquetasPares clave-valor en la regla (por ejemplo severity=critical) que deciden a dónde va la notificación
Política de notificaciónÁrbol de reglas de enrutamiento: según las etiquetas, elige un punto de contacto y cómo agrupar y repetir los avisos
Punto de contactoEl destino final: email, Slack, PagerDuty, webhook, Telegram, etc.

Cada regla pasa por estos estados: Normal (la condición no se cumple), Pending (se cumple, pero aún no ha pasado el tiempo de espera), Alerting o Firing (se cumple durante todo ese tiempo y se notifica), No Data (la consulta no devuelve datos) y Error (la consulta falla).

Paso 1: Configurar el envío de correo

Grafana no envía correo hasta que configuras un servidor SMTP. Abre su configuración:

sudo nano /etc/grafana/grafana.ini

Busca la sección [smtp], que viene comentada, y déjala así, sustituyendo los valores por los de tu proveedor:

[smtp]
enabled = true
host = smtp.your_domain:587
user = alertas@your_domain
password = """your_smtp_password"""
from_address = alertas@your_domain
from_name = Grafana
startTLS_policy = MandatoryStartTLS

Las comillas triples en password evitan que Grafana interprete como comentario un # o un ; dentro de la contraseña. Con el puerto 587, MandatoryStartTLS obliga a cifrar la conexión.

Reinicia Grafana y comprueba que arranca sin errores:

sudo systemctl restart grafana-server
sudo systemctl status grafana-server --no-pager
● grafana-server.service - Grafana instance
     Loaded: loaded (/usr/lib/systemd/system/grafana-server.service; enabled; preset: enabled)
     Active: active (running) since ...

Paso 2: Crear los puntos de contacto

Crearás dos: uno de email para los avisos normales y uno de Slack para lo crítico.

  1. En Grafana, ve a Alerting > Contact points y pulsa + Add contact point.
  2. En Name, escribe equipo-email.
  3. En Integration, elige Email y en Addresses escribe ops@your_domain (puedes poner varias direcciones separadas por ;).
  4. Pulsa Test y después Send test notification. Debe llegarte un correo de prueba en menos de un minuto.
  5. Pulsa Save contact point.

Repite el proceso para Slack:

  1. + Add contact point, con el nombre guardia-slack.
  2. En Integration, elige Slack y pega la URL del webhook en Webhook URL.
  3. Pulsa Test para comprobar que el mensaje aparece en el canal, y guarda.

Si la prueba de email falla, el motivo exacto está en el log de Grafana:

sudo grep -i smtp /var/log/grafana/grafana.log | tail -5

Paso 3: Definir las políticas de notificación

La política por defecto recibe todas las alertas que no coincidan con ninguna política anidada. Ve a Alerting > Notification policies:

  1. En Default policy, pulsa More > Edit, elige equipo-email como punto de contacto y guarda.
  2. Pulsa + New child policy (o New nested policy) bajo la política por defecto.
  3. En el emparejador (matcher) escribe severity = critical.
  4. Elige guardia-slack como punto de contacto.
  5. Activa Override general timings y pon Repeat interval a 1h, para que una alerta crítica que siga activa se recuerde cada hora en lugar de cada 4 horas.
  6. Guarda la política.

Tres tiempos controlan el ruido de las notificaciones:

  • Group wait (30 s por defecto): cuánto espera Grafana antes de enviar el primer aviso de un grupo nuevo, para juntar alertas que saltan a la vez.
  • Group interval (5 min): cada cuánto se envía un aviso si cambian las alertas de un grupo ya notificado.
  • Repeat interval (4 h): cada cuánto se repite el aviso si nada ha cambiado y la alerta sigue activa.

Paso 4: Crear la regla "Target caído"

Esta regla usa la métrica up que Prometheus genera para cada destino: vale 1 si el último scrape funcionó y 0 si no.

  1. Ve a Alerting > Alert rules y pulsa + New alert rule.
  2. En Enter alert rule name, escribe Target caído.
  3. En Define query and alert condition, elige tu fuente de datos Prometheus, cambia el editor a Code y escribe la consulta:
up
  1. En la condición de alerta (Alert condition), indica que se dispare cuando la consulta esté por debajo de 1 (IS BELOW 1). Pulsa Preview o Run queries: verás una fila por cada destino con su estado actual, que debería ser Normal.
  2. En Add folder and labels, crea la carpeta Alertas y añade la etiqueta severity con valor critical.
  3. En Set evaluation behavior, crea un grupo de evaluación llamado infraestructura con intervalo 1m y fija el periodo pendiente (Pending period) en 2m. La regla solo notificará si el destino lleva caído dos evaluaciones seguidas.
  4. En Configure notifications, deja la opción de usar las políticas de notificación, de modo que la etiqueta severity=critical la envíe a Slack.
  5. En Configure notification message, escribe en Summary:
{{ $labels.instance }} ({{ $labels.job }}) no responde
  1. Pulsa Save rule and exit.

La regla genera una instancia de alerta por cada serie que devuelve la consulta. Si tienes diez destinos, cada uno tiene su propio estado y su propia notificación, con la etiqueta instance que lo identifica.

Paso 5: Crear la regla "Disco casi lleno"

Crea una segunda regla con el mismo procedimiento y estos valores:

  • Nombre: Disco casi lleno.
  • Consulta (calcula el porcentaje libre de cada sistema de archivos, ignorando los temporales):
100 * node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}
  • Condición: IS BELOW 10.
  • Carpeta Alertas, etiqueta severity con valor warning (irá al email mediante la política por defecto).
  • Grupo infraestructura y periodo pendiente de 10m. Un disco no se llena en segundos, así que no hace falta reaccionar a picos breves.
  • Summary: Queda menos del 10 % de espacio en {{ $labels.mountpoint }} de {{ $labels.instance }}.

En Configure no data and error handling, cambia Alert state if no data a Normal (u OK). Si un servidor deja de enviar métricas ya te avisará la regla Target caído, y así evitas un segundo aviso por lo mismo.

Paso 6: Probar las alertas y silenciarlas

La forma más fiable de probar el circuito completo es provocar una alerta real en un servidor de pruebas. Detén node_exporter (si lo instalaste desde el paquete de Ubuntu, el servicio se llama prometheus-node-exporter):

sudo systemctl stop prometheus-node-exporter

En Alerting > Alert rules, la regla Target caído pasará a Pending en la siguiente evaluación y a Firing unos dos minutos después. Deberías recibir el mensaje en Slack. Vuelve a arrancar el servicio:

sudo systemctl start prometheus-node-exporter

En la siguiente evaluación, la alerta vuelve a Normal y Grafana envía una notificación de resolución (RESOLVED).

Para un mantenimiento programado, en lugar de pausar reglas crea un silencio: ve a Alerting > Silences, pulsa + New silence, añade un matcher como instance = your_server_ip:9100, elige la duración y guarda. Las alertas que coincidan se siguen evaluando, pero no se notifican hasta que el silencio caduque.

Paso 7: Gestionar las alertas como código

Configurar alertas a mano no escala ni deja historial de cambios. Grafana puede cargar puntos de contacto, políticas y reglas desde archivos YAML en /etc/grafana/provisioning/alerting/ al arrancar. Así puedes guardarlos en Git y desplegarlos igual en todos los entornos.

Necesitas el UID de tu fuente de datos Prometheus. Ve a Connections > Data sources, abre la fuente Prometheus y cópialo de la URL, que tiene la forma /connections/datasources/edit/<uid>.

Crea el directorio si no existe y el archivo de puntos de contacto:

sudo mkdir -p /etc/grafana/provisioning/alerting
sudo nano /etc/grafana/provisioning/alerting/contact-points.yaml
apiVersion: 1
contactPoints:
  - orgId: 1
    name: equipo-email
    receivers:
      - uid: equipo-email
        type: email
        settings:
          addresses: ops@your_domain
          singleEmail: true
  - orgId: 1
    name: guardia-slack
    receivers:
      - uid: guardia-slack
        type: slack
        settings:
          url: https://hooks.slack.com/services/your_webhook_path

Crea el de políticas:

sudo nano /etc/grafana/provisioning/alerting/policies.yaml
apiVersion: 1
policies:
  - orgId: 1
    receiver: equipo-email
    group_by: ["grafana_folder", "alertname"]
    group_wait: 30s
    group_interval: 5m
    repeat_interval: 4h
    routes:
      - receiver: guardia-slack
        object_matchers:
          - ["severity", "=", "critical"]
        repeat_interval: 1h

Y el de reglas, sustituyendo your_prometheus_uid por el UID que copiaste:

sudo nano /etc/grafana/provisioning/alerting/rules.yaml
apiVersion: 1
groups:
  - orgId: 1
    name: infraestructura
    folder: Alertas
    interval: 1m
    rules:
      - uid: target-caido
        title: Target caído
        condition: C
        data:
          - refId: A
            relativeTimeRange:
              from: 300
              to: 0
            datasourceUid: your_prometheus_uid
            model:
              refId: A
              expr: up
          - refId: B
            datasourceUid: __expr__
            model:
              refId: B
              type: reduce
              expression: A
              reducer: last
              settings:
                mode: dropNN
          - refId: C
            datasourceUid: __expr__
            model:
              refId: C
              type: threshold
              expression: B
              conditions:
                - evaluator:
                    type: lt
                    params: [1]
        for: 2m
        noDataState: NoData
        execErrState: Error
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.instance }} ({{ $labels.job }}) no responde"

      - uid: disco-casi-lleno
        title: Disco casi lleno
        condition: C
        data:
          - refId: A
            relativeTimeRange:
              from: 300
              to: 0
            datasourceUid: your_prometheus_uid
            model:
              refId: A
              expr: 100 * node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}
          - refId: B
            datasourceUid: __expr__
            model:
              refId: B
              type: reduce
              expression: A
              reducer: last
              settings:
                mode: dropNN
          - refId: C
            datasourceUid: __expr__
            model:
              refId: C
              type: threshold
              expression: B
              conditions:
                - evaluator:
                    type: lt
                    params: [10]
        for: 10m
        noDataState: OK
        execErrState: Error
        labels:
          severity: warning
        annotations:
          summary: "Queda menos del 10 % de espacio en {{ $labels.mountpoint }} de {{ $labels.instance }}"
          description: 'Espacio libre actual: {{ printf "%.1f" $values.B.Value }} %.'

Cada regla tiene tres pasos encadenados: A es la consulta a Prometheus sobre los últimos 5 minutos (relativeTimeRange en segundos), B reduce cada serie a su último valor descartando los no numéricos (dropNN), y C compara ese valor con el umbral. condition: C indica qué paso decide si la regla se dispara. En las anotaciones, $values.B.Value da acceso al valor calculado en el paso B.

El archivo de contactos contiene la URL secreta del webhook, así que restringe los permisos para que solo root y el usuario grafana puedan leerlos:

sudo chown root:grafana /etc/grafana/provisioning/alerting/*.yaml
sudo chmod 640 /etc/grafana/provisioning/alerting/*.yaml

Reinicia Grafana para cargar los archivos y busca errores de provisioning en el log:

sudo systemctl restart grafana-server
sudo grep -i provisioning /var/log/grafana/grafana.log | tail -10

Si hay un error de formato, el log indica el archivo y el motivo, y Grafana no aplica ese archivo. Si todo es correcto, en Alerting > Alert rules verás las dos reglas en la carpeta Alertas con la marca Provisioned.

Solución de problemas

La regla está en estado No Data. La consulta no devuelve series. Ejecútala en Explore con la misma fuente de datos; lo habitual es un error en el nombre de la métrica o en un filtro de etiquetas. Si la ausencia de datos es normal para esa regla, cambia su estado de No Data a Normal.

La regla está en estado Error. La consulta falla: Prometheus no responde o el UID de la fuente de datos es incorrecto. El detalle aparece al abrir la regla, en la pestaña de historial de estados.

La regla está en Firing, pero no llega la notificación. Abre Alerting > Notification policies y comprueba a qué política llega una alerta con esas etiquetas. Si el problema es el punto de contacto, usa su botón Test y revisa /var/log/grafana/grafana.log.

Los correos no llegan (dial tcp ... i/o timeout). Muchos proveedores de cloud bloquean la salida por el puerto 25. Usa el puerto de envío 587 con STARTTLS o el 465 con TLS de tu proveedor de correo.

Se reciben avisos repetidos de lo mismo. Revisa el group_by de la política: agrupar por alertname y grafana_folder junta todas las instancias de una regla en un único mensaje. Sube también el Repeat interval si las repeticiones son demasiado frecuentes.

Conclusión

Tienes Grafana Alerting enviando alertas por email y Slack según su gravedad, con dos reglas sobre Prometheus que cubren caídas de servidores y discos llenos, silencios para los mantenimientos y la misma configuración definida en archivos YAML versionables. Como siguientes pasos, puedes añadir reglas sobre otros exportadores (bases de datos, Blackbox Exporter), crear plantillas de notificación para dar formato a los mensajes o enlazar cada regla con el panel correspondiente de un dashboard para abrir el contexto directamente desde el aviso.