Doce construcciones

Una pila de monitorización que vigila tu propia flota

Prometheus, exporters y Alertmanager en varios sitios, recopilados a través de un túnel privado, con alertas que se disparan antes de que un disco se llene, no después.

Qué construye esto

Una instancia pequeña que inspecciona todas las demás máquinas que posees, a través de un túnel privado, y te envía un correo cuando algo está a punto de romperse. Métricas de nodo, sondas blackbox entre sitios, reglas de alerta con umbrales razonables y una configuración de Alertmanager que agrupa las notificaciones en lugar de enviarte cuatrocientas a las tres de la madrugada.

No hay panel de control en esta construcción. Los paneles son agradables y no son monitoreo; un gráfico que nadie mira nunca ha despertado a nadie. Añade uno más tarde si lo deseas, sobre los mismos datos.

Antes de empezar

  • Un R-4 para el monitor. Cien nodos a intervalos de quince segundos son unos cientos de miles de muestras por minuto, lo cual este maneja sin notarlo.
  • Colócalo en un lugar donde no esté tu flota. Cualquier monitor que comparta edificio con todo lo que observa permanece admirablemente silencioso precisamente el día que necesitas que grite. Si tu parque está en Europa, Toronto o Singapur es el lugar sensato para ello.
  • Un túnel a cada nodo monitoreado, desde la guía de WireGuard. Los exportadores exponen mucho sobre una máquina y no deben estar cerca de una interfaz pública.

1. En cada nodo monitoreado

apt update && apt install -y prometheus-node-exporter
mkdir -p /etc/systemd/system/prometheus-node-exporter.service.d
cat > /etc/systemd/system/prometheus-node-exporter.service.d/bind.conf <<EOF
[Service]
Environment=ARGS=--web.listen-address=10.7.0.11:9100 --collector.systemd --collector.processes
EOF
systemctl daemon-reload && systemctl restart prometheus-node-exporter
ss -ltn | grep 9100

Sustituye la dirección del túnel de cada nodo. Vincularse al túnel en lugar de a todo significa que el cortafuegos es una segunda línea de defensa en lugar de la única.

2. En el monitor

apt install -y prometheus prometheus-alertmanager prometheus-blackbox-exporter

Escribe /etc/prometheus/prometheus.yml:

global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    fleet: main

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['127.0.0.1:9093']

rule_files:
  - /etc/prometheus/rules/*.yml

scrape_configs:
  - job_name: nodes
    file_sd_configs:
      - files: ['/etc/prometheus/targets/*.yml']

  - job_name: probe_https
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
          - https://app.example.com/health
          - https://cloud.example.com/status.php
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 127.0.0.1:9115

El descubrimiento basado en archivos en lugar de una lista estática merece el directorio adicional. Añadir un nodo se convierte en un archivo, y el archivo puede ser escrito por lo que aprovisiona tus máquinas. /etc/prometheus/targets/ams.yml:

- targets: ['10.7.0.11:9100']
  labels: { site: AMS-01, role: web }
- targets: ['10.7.0.12:9100']
  labels: { site: AMS-01, role: db }

Esas etiquetas son lo que hace legibles las alertas más tarde. Una alerta que dice db in AMS-01 es accionable; una que dice 10.7.0.12 te envía a una hoja de cálculo.

3. Reglas que valen la pena

/etc/prometheus/rules/fleet.yml:

groups:
  - name: fleet
    rules:
      - alert: NodeDown
        expr: up{job="nodes"} == 0
        for: 3m
        labels: { severity: page }
        annotations:
          summary: "{{ $labels.instance }} in {{ $labels.site }} stopped answering"

      - alert: DiskFillingUp
        expr: predict_linear(node_filesystem_avail_bytes{fstype=~"ext4|xfs|zfs|btrfs"}[6h], 4*3600) < 0
        for: 30m
        labels: { severity: page }
        annotations:
          summary: "{{ $labels.instance }} fills {{ $labels.mountpoint }} within four hours"

      - alert: MemoryPressure
        expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes < 0.10
        for: 15m
        labels: { severity: warn }

      - alert: IOWaitHigh
        expr: avg by (instance) (rate(node_cpu_seconds_total{mode="iowait"}[5m])) > 0.25
        for: 20m
        labels: { severity: warn }

      - alert: CertificateExpiring
        expr: probe_ssl_earliest_cert_expiry - time() < 10*86400
        labels: { severity: warn }

      - alert: ProbeFailing
        expr: probe_success == 0
        for: 5m
        labels: { severity: page }

predict_linear es la regla que hace que esta construcción valga la pena. Un umbral de espacio libre te dice que un disco está lleno; una tendencia de seis horas extrapolada hacia adelante te dice que estará lleno alrededor de las cuatro de esta tarde, lo cual es un problema que aún puedes resolver con calma. Las alertas de disco basadas en un porcentaje fijo son ruidosas en volúmenes pequeños o inútiles en los grandes.

4. Alertmanager

route:
  receiver: mail
  group_by: [alertname, site]
  group_wait: 45s
  group_interval: 5m
  repeat_interval: 12h
  routes:
    - matchers: [severity="warn"]
      repeat_interval: 72h

inhibit_rules:
  - source_matchers: [alertname="NodeDown"]
    target_matchers: [severity="warn"]
    equal: [instance]

receivers:
  - name: mail
    email_configs:
      - to: [email protected]
        from: [email protected]
        smarthost: mail.example.com:587
        auth_username: [email protected]
        auth_password: "<the mailbox password>"

La regla de inhibición es la diferencia entre un mensaje y cuarenta. Cuando un nodo se cae, se suprimen todas las advertencias sobre ese nodo, porque ya lo sabes: el nodo está caído.

Agrupar por alertname y site significa que un sitio completo que pierde energía produce un correo que lista cada máquina, en lugar de un correo por máquina. Ese servidor de correo es el de la guía de correo, y tener tu ruta de alerta dependiendo de infraestructura que también monitoreas es una compensación conocida; un segundo receptor apuntando a un webhook en otro lugar es un seguro barato.

systemctl enable --now prometheus prometheus-alertmanager prometheus-blackbox-exporter

La retención merece establecerse deliberadamente. Noventa días de cien nodos son unas pocas decenas de gigabytes:

echo 'ARGS="--storage.tsdb.retention.time=90d --storage.tsdb.retention.size=40GB"' > /etc/default/prometheus
systemctl restart prometheus

Verifícalo

Sintaxis primero, porque un archivo de reglas con un error tipográfico falla silenciosamente al cargar y te enteras durante el incidente:

promtool check config /etc/prometheus/prometheus.yml
promtool check rules /etc/prometheus/rules/fleet.yml

Luego confirma que todos los objetivos se están inspeccionando:

curl -s http://127.0.0.1:9090/api/v1/targets | grep -o "\"health\":\"[a-z]*\"" | sort | uniq -c

Cada objetivo debe informar up. Uno que informe down es o una regla de cortafuegos o un exportador vinculado a la dirección equivocada.

Ahora la única prueba que demuestra que toda la cadena funciona, que es romper algo a propósito. En cualquier nodo monitoreado:

systemctl stop prometheus-node-exporter

Tres minutos después la alerta debe estar pendiente, luego disparada. Obsérvala moverse:

curl -s http://127.0.0.1:9090/api/v1/alerts | head -c 400
amtool --alertmanager.url=http://127.0.0.1:9093 alert query

Dentro de aproximadamente un minuto de que se dispare, llega el correo. Si la alerta se dispara pero no aparece el correo, el problema son las credenciales del smarthost, y journalctl -u prometheus-alertmanager lo dirá claramente. Inicia el exportador de nuevo y confirma que también recibes la notificación de resolución, ya que un sistema de alerta que nunca te dice que las cosas mejoran te entrena a ignorarlo.

systemctl start prometheus-node-exporter

Después

Añade sondas blackbox entre sitios, de cada sitio a cada otro sitio, y obtienes una matriz de latencia de tu propio parque que es mucho más útil durante un incidente que cualquier página de estado. La nuestra está en estado, y el looking glass responde la otra mitad de la pregunta cuando una ruta parece incorrecta.

Listo cuando tú lo estés

Elige una ciudad. Elige un tamaño. Paga con monedas.

Sin fórmulas sobre quién eres, sin esperar a que un humano te apruebe, sin llamada telefónica para verificar nada. La factura se liquida y las credenciales llegan a tu bandeja de entrada.