Twaalf builds

Een monitoringsstack die je eigen vloot in de gaten houdt

Prometheus, exporters en Alertmanager op meerdere locaties, geschraapt via een privétunnel, met alarmen die afgaan voordat een schijf vol raakt in plaats van erna.

Wat dit bouwt

Een kleine instantie die iedere andere machine die je bezit scrapet via een privétunnel, en je mailt wanneer er iets op het punt staat te breken. Node-metrieken, blackbox-probes tussen locaties, alertregels met verstandige drempelwaarden, en een Alertmanager-configuratie die meldingen groepeert in plaats van je er om drie uur 's nachts vierhonderd te sturen.

Er is geen dashboard in deze build. Dashboards zijn prettig en ze zijn geen monitoring; een grafiek waar niemand naar kijkt heeft nog nooit iemand wakker gemaakt. Voeg er later een toe als je wilt, bovenop dezelfde data.

Voordat je begint

  • Een R-4 voor de monitor. Honderd nodes met intervallen van vijftien seconden is een paar honderdduizend samples per minuut, wat dit zonder problemen aankan.
  • Zet hem op een plek waar je fleet niet is. Elke monitor die een gebouw deelt met alles wat hij bewaakt, blijft bewonderenswaardig stil op precies de dag dat je wilt dat hij schreeuwt. Als je estate Europees is, is Toronto of Singapore de verstandige plek ervoor.
  • Een tunnel naar elke bewaakte node, vanuit de WireGuard-gids. Exporters leggen veel bloot over een machine en horen nergens in de buurt van een publieke interface te komen.

1. Op elke bewaakte node

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

Vervang het eigen tunneladres van elke node. Binden aan de tunnel in plaats van aan alles betekent dat de firewall een tweede verdedigingslinie is in plaats van de enige.

2. Op de monitor

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

Schrijf /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

Bestandsgebaseerde discovery in plaats van een statische lijst is de extra directory waard. Een node toevoegen wordt één bestand, en dat bestand kan geschreven worden door wat je machines ook provisiont. /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 }

Die labels zijn wat alerts later leesbaar maakt. Een alert die db in AMS-01 zegt is actiegericht; een die 10.7.0.12 zegt stuurt je naar een spreadsheet.

3. Regels die de moeite waard zijn

/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 is de regel die deze build de moeite waard maakt. Een drempelwaarde op vrije ruimte vertelt je dat een disk vol is; een zeshonderd uur durende trend geëxtrapoleerd naar de toekomst vertelt je dat hij rond vier uur vanmiddag vol zal zijn, wat een probleem is dat je nog rustig kunt oplossen. Disk-alerts op basis van een vast percentage zijn óf luidruchtig op kleine volumes óf nutteloos op grote.

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>"

De inhibit-regel is het verschil tussen één bericht en veertig. Wanneer een node uitvalt, wordt elke waarschuwing over die node onderdrukt, want je weet het al: de node is uit.

Groeperen op alertname en site betekent dat een hele locatie die stroom verliest één mail oplevert met elke machine erin, in plaats van één mail per machine. Die mailserver is die uit de mailgids, en het feit dat je alerting-pad afhangt van infrastructuur die je ook bewaakt is een bekend compromis; een tweede receiver die naar een webhook elders wijst is goedkope verzekering.

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

Retentie is het waard om bewust in te stellen. Negentig dagen van honderd nodes is een paar tientallen gigabytes:

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

Verifieer het

Eerst syntaxis, want een regelsbestand met een typfout faalt stil bij het laden en je komt erachter tijdens de incident:

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

Bevestig dan dat elke target wordt gescraped:

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

Elke target zou up moeten rapporteren. Een die down rapporteert is ofwel een firewallregel of een exporter die aan het verkeerde adres gebonden is.

Nu de enige test die bewijst dat de hele keten werkt, namelijk om expres iets te breken. Op elke bewaakte node:

systemctl stop prometheus-node-exporter

Drie minuten later zou de alert pending moeten zijn, en daarna firing. Kijk hoe hij beweegt:

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

Binnen ongeveer een minuut na firing komt de mail aan. Als de alert vuurt maar er komt geen mail, dan is het probleem de smarthost-referenties, en journalctl -u prometheus-alertmanager zal dat duidelijk zeggen. Start de exporter weer en bevestig dat je ook de resolved-melding ontvangt, want een alertingsysteem dat je nooit vertelt dat dingen beter gaan, traint je om het te negeren.

systemctl start prometheus-node-exporter

Achteraf

Voeg blackbox-probes toe tussen locaties, van elke locatie naar elke andere locatie, en je krijgt een latentiematrix van je eigen estate die veel nuttiger is tijdens een incident dan welke statuspagina dan ook. Onze staat op status, en de looking glass beantwoordt de andere helft van de vraag wanneer een route er verkeerd uitziet.

Klaar wanneer jij dat bent

Kies een stad. Kies een formaat. Betaal in munt.

Geen formulieren over wie je bent, geen wachten op een mens die je goedkeurt, geen telefoontje om iets te verifiëren. De factuur wordt betaald en de inloggegevens belanden in je inbox.