十二个构建

一个监控自身机群的监控栈

Prometheus、导出器和 Alertmanager 分布在多个站点,通过专用隧道抓取,并在磁盘满之前而非之后发出告警。

构建内容

一个小型实例,通过私有隧道抓取你拥有的其他每台机器,并在有问题即将发生时向你发送邮件。节点指标、站点间的黑盒探测、带合理阈值的安全规则,以及一个将通知分组而不是在凌晨三点向你发送四百封邮件的 Alertmanager 配置。

此构建中没有仪表盘。仪表盘很美观,但并不是监控;没人看的图表从未叫醒过任何人。如果需要,你可以稍后在相同数据之上添加一个。

开始前

  • 选一台 R-4 作为监控机。以十五秒间隔监控一百个节点,每分钟产生几十万个样本,这台机器能轻松处理。
  • 把它放在你的资产群之外的地方。任何与所监控对象共用一栋楼的监控机,在你最需要它喊叫的那一天,恰恰会保持安静。如果你的服务器群位于欧洲,多伦多或新加坡是合理的选择。
  • 通过 WireGuard 指南 与每个监控节点建立隧道。导出器会暴露大量关于机器的信息,不应该出现在公共接口附近。

1. 在每个监控节点上

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

替换为每个节点自己的隧道地址。绑定到隧道而不是所有接口,意味着防火墙是第二道防线,而不是唯一防线。

2. 在监控机上

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

写入 /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

基于文件的发现优于静态列表,值得增加一个额外目录。添加一个节点只需一个文件,而且该文件可以由任何配置你机器的工具写入。/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 }

这些标签使后面的告警更易读。一条说 db in AMS-01 的告警是可操作的;一条说 10.7.0.12 的告警让你去查电子表格。

3. 值得拥有的规则

/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 是这条构建的核心规则。对剩余空间的阈值告诉你磁盘已满;而将六小时的趋势向前外推,告诉你它将在下午四点左右满,这是你仍然可以冷静解决的问题。基于固定百分比的磁盘告警,要么在小容量卷上太过嘈杂,要么在大容量卷上毫无用处。

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

抑制规则是收到一条消息和四十条消息的区别。当一个节点宕机时,关于该节点的所有警告都被抑制,因为你已经知道:节点宕机了。

alertnamesite 分组意味着整个站点停电时只产生一封邮件列出每台机器,而不是每台机器一封邮件。那台邮件服务器是 邮件指南 中的那台,而依赖于你也在监控的基础设施作为告警路径,是一个已知的权衡;另一个指向某个 webhook 的接收器是廉价的保险。

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

保留期值得刻意设置。一百个节点九十天的数据是几十 GB:

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

验证

先检查语法,因为规则文件中的拼写错误会在加载时静默失败,而你会在事件发生时才察觉:

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

然后确认每个目标都被抓取:

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

每个目标都应报告 up。如果有一个报告 down,要么是防火墙规则问题,要么是导出器绑定了错误的地址。

现在,唯一能证明整个链路有效性的测试是故意破坏一些东西。在某个受监控节点上:

systemctl stop prometheus-node-exporter

三分钟后,告警应转为 pending,然后 firing。观察它的变化:

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

触发后大约一分钟内,邮件到达。如果告警触发但没有邮件,问题在 smarthost 凭据,journalctl -u prometheus-alertmanager 会直接指出。重新启动导出器,并确认你也收到恢复通知,因为一个从不告诉你事情已好转的告警系统会让你学会忽略它。

systemctl start prometheus-node-exporter

之后

在站点之间添加黑盒探针,从每个站点到其他站点,你会得到自己网络资产的延迟矩阵,在故障期间比任何状态页面都有用得多。我们的在 status,而 looking glass 在路由看起来不对时回答了问题的另一半。

随时恭候

选择城市,选择大小,用加密货币支付。

无需填写关于您的身份信息的表格,无需等待人工审批,无需电话验证。账单结清后,凭证将发送到您的邮箱。