Prometheus告警規則編寫與Alertmanager通知配置實戰
一、概述
1.1 背景介紹
監控系統搭完了,指標也采集上來了,但如果沒有告警,等于白搭。我見過不少團隊Prometheus跑得好好的,Grafana大屏也掛在墻上,結果凌晨3點數據庫磁盤寫滿了,第二天早上用戶投訴才發現。監控不閉環,就是擺設。
Prometheus的告警分兩部分:Prometheus Server負責根據PromQL表達式評估告警規則,觸發后把告警推給Alertmanager;Alertmanager負責去重、分組、路由、靜默,最終通過郵件、釘釘、企業微信、Webhook等渠道發出通知。這個分工設計得很合理——Prometheus專注數據采集和規則評估,Alertmanager專注通知管理,各司其職。
我們團隊從2020年開始用這套告警體系,目前管理著600多條告警規則,覆蓋主機、容器、中間件、業務四個層面,日均觸發告警200-300條,通過分級策略和收斂機制,實際推送到人的不超過30條。
1.2 技術特點
PromQL驅動的告警規則:告警條件用PromQL表達式定義,能寫出非常靈活的判斷邏輯。比如"CPU使用率連續5分鐘超過85%"、"磁盤空間按當前速率24小時內會寫滿"、"HTTP錯誤率突然飆升到正常值的3倍",這些用PromQL都能精確表達。
路由樹+分組去重:Alertmanager的路由配置是樹狀結構,根據label匹配把告警分發到不同的接收器。同一組的告警會合并成一條通知發送,避免告警風暴。我們線上一次網絡故障觸發了80多條告警,經過分組后只發了3條通知。
抑制和靜默機制:抑制(Inhibition)可以設置告警之間的依賴關系,比如節點宕機時自動抑制該節點上所有服務的告警。靜默(Silence)可以在維護窗口臨時屏蔽特定告警,避免計劃內變更觸發誤報。
1.3 適用場景
基礎設施告警:主機CPU、內存、磁盤、網絡異常檢測,服務進程存活監控,硬件故障預警。這是最基礎的告警需求,覆蓋面廣,規則相對固定。
應用服務告警:HTTP接口的QPS、延遲、錯誤率監控,JVM內存和GC監控,數據庫連接池和慢查詢監控。需要和開發團隊配合定義合理的閾值。
業務指標告警:訂單量異常波動、支付成功率下降、用戶注冊量驟降。這類告警直接關聯業務,閾值需要根據業務特征動態調整。
1.4 環境要求
| 組件 | 版本要求 | 說明 |
|---|---|---|
| Prometheus | 2.45+ | 告警規則評估引擎,需要和Alertmanager版本匹配 |
| Alertmanager | 0.27+ | 0.27版本修復了集群模式下的幾個關鍵bug |
| 操作系統 | CentOS 7+ / Ubuntu 20.04+ | Alertmanager資源消耗很低,1C1G就夠 |
| 網絡 | 內網互通 | Prometheus到Alertmanager需要9093端口,Alertmanager集群間需要9094端口 |
| 通知渠道 | 郵件服務器/釘釘機器人/企微機器人 | 至少配一個通知渠道,建議配兩個做冗余 |
二、詳細步驟
2.1 準備工作
2.1.1 Alertmanager安裝
# 創建用戶 sudo useradd --no-create-home --shell /bin/falsealertmanager # 下載Alertmanager cd/tmp wget https://github.com/prometheus/alertmanager/releases/download/v0.27.0/alertmanager-0.27.0.linux-amd64.tar.gz tar xzf alertmanager-0.27.0.linux-amd64.tar.gz cdalertmanager-0.27.0.linux-amd64 # 安裝 sudo cp alertmanager /usr/local/bin/ sudo cp amtool /usr/local/bin/ sudo chown alertmanager:alertmanager /usr/local/bin/alertmanager sudo chown alertmanager:alertmanager /usr/local/bin/amtool # 創建配置和數據目錄 sudo mkdir -p /etc/alertmanager sudo mkdir -p /var/lib/alertmanager sudo chown -R alertmanager:alertmanager /etc/alertmanager sudo chown -R alertmanager:alertmanager /var/lib/alertmanager # 驗證 alertmanager --version
2.1.2 Systemd服務配置
sudo tee /etc/systemd/system/alertmanager.service > /dev/null <'EOF' [Unit] Description=Alertmanager Wants=network-online.target After=network-online.target [Service] Type=simple User=alertmanager Group=alertmanager ExecStart=/usr/local/bin/alertmanager ? --config.file=/etc/alertmanager/alertmanager.yml ? --storage.path=/var/lib/alertmanager ? --web.listen-address=0.0.0.0:9093 ? --web.external-url=http://alertmanager.example.com:9093 ? --cluster.listen-address=0.0.0.0:9094 ? --log.level=info ? --data.retention=120h Restart=always RestartSec=5 LimitNOFILE=65536 [Install] WantedBy=multi-user.target EOF
參數說明:
--data.retention=120h:告警數據保留5天,默認也是120h。這個數據是Alertmanager自己的狀態數據(靜默規則、通知記錄等),不是Prometheus的監控數據。
--cluster.listen-address:集群通信端口,多實例部署時用。單機可以設成空字符串禁用。
--web.external-url:外部訪問地址,告警通知里的鏈接會用這個地址。設錯了點告警鏈接會404。
2.1.3 防火墻配置
# Alertmanager Web UI和API sudo ufw allow 9093/tcp # Alertmanager集群通信 sudo ufw allow 9094/tcp sudo ufw allow 9094/udp sudo ufw reload
2.2 核心配置
2.2.1 Alertmanager主配置文件
# 文件路徑:/etc/alertmanager/alertmanager.yml global: resolve_timeout:5m smtp_from:'alertmanager@example.com' smtp_smarthost:'smtp.example.com:465' smtp_auth_username:'alertmanager@example.com' smtp_auth_password:'your_smtp_password' smtp_require_tls:false # 通知模板 templates: -'/etc/alertmanager/templates/*.tmpl' # 路由樹配置 route: # 分組依據,同一組的告警合并發送 group_by:['alertname','cluster','service'] # 新告警等待時間,等這么久再發送,讓同組告警有機會合并 group_wait:30s # 同一組告警的發送間隔 group_interval:5m # 已發送告警的重復發送間隔 repeat_interval:4h # 默認接收器 receiver:'default-webhook' routes: # P0級別 - 核心服務宕機,立刻通知 -match: severity:critical receiver:'critical-pager' group_wait:10s repeat_interval:1h continue:false # P1級別 - 性能告警,5分鐘內通知 -match: severity:warning receiver:'warning-dingtalk' group_wait:30s repeat_interval:4h continue:false # 數據庫相關告警單獨路由給DBA -match_re: job:'(mysql|redis|mongodb).*' receiver:'dba-dingtalk' group_wait:30s repeat_interval:2h continue:false # 業務告警路由給對應團隊 -match: team:'order' receiver:'order-team-webhook' continue:false -match: team:'payment' receiver:'payment-team-webhook' continue:false # 抑制規則 inhibit_rules: # 節點宕機時,抑制該節點上所有服務的告警 -source_match: alertname:'NodeDown' target_match_re: alertname:'.+' equal:['instance'] # critical級別告警觸發時,抑制同指標的warning告警 -source_match: severity:'critical' target_match: severity:'warning' equal:['alertname','instance'] # 接收器配置 receivers: # 默認接收器 - 企業微信 -name:'default-webhook' webhook_configs: -url:'http://localhost:8060/dingtalk/ops/send' send_resolved:true # P0告警 - 電話+短信+釘釘 -name:'critical-pager' webhook_configs: -url:'http://localhost:8060/dingtalk/critical/send' send_resolved:true -url:'http://oncall-api.internal:8080/api/v1/alert' send_resolved:true email_configs: -to:'oncall@example.com' send_resolved:true headers: Subject:'[P0-CRITICAL]{{ .GroupLabels.alertname }}' # Warning告警 - 釘釘群 -name:'warning-dingtalk' webhook_configs: -url:'http://localhost:8060/dingtalk/warning/send' send_resolved:true # DBA告警 -name:'dba-dingtalk' webhook_configs: -url:'http://localhost:8060/dingtalk/dba/send' send_resolved:true # 訂單團隊 -name:'order-team-webhook' webhook_configs: -url:'http://localhost:8060/dingtalk/order/send' send_resolved:true # 支付團隊 -name:'payment-team-webhook' webhook_configs: -url:'http://localhost:8060/dingtalk/payment/send' send_resolved:true
說明:group_wait設成30秒是經過權衡的。太短了同一批告警來不及合并,太長了延遲通知。P0級別的critical告警我們設成10秒,因為這類告警寧可多發也不能晚發。repeat_interval設4小時,避免同一個告警反復騷擾值班人員,但critical級別設1小時,確保持續關注。
2.2.2 告警規則文件 - 主機監控
# 文件路徑:/etc/prometheus/rules/node_alerts.yml
groups:
-name:node_alerts
rules:
-alert:NodeDown
expr:up{job="node-exporter"}==0
for:2m
labels:
severity:critical
team:ops
annotations:
summary:"節點{{ $labels.instance }}宕機"
description:"節點已超過2分鐘無響應,請立即排查"
runbook:"https://wiki.internal/runbook/node-down"
-alert:NodeCPUHigh
expr:|
1 - avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) > 0.85
for:5m
labels:
severity:warning
team:ops
annotations:
summary:"{{ $labels.instance }}CPU使用率{{ $value | humanizePercentage }}"
description:"CPU持續5分鐘超過85%,檢查是否有異常進程"
-alert:NodeMemoryHigh
expr:|
1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes > 0.90
for:5m
labels:
severity:warning
team:ops
annotations:
summary:"{{ $labels.instance }}內存使用率{{ $value | humanizePercentage }}"
-alert:NodeDiskAlmostFull
expr:|
1 - node_filesystem_avail_bytes{mountpoint="/",fstype!="tmpfs"}
/ node_filesystem_size_bytes{mountpoint="/",fstype!="tmpfs"} > 0.85
for:5m
labels:
severity:warning
team:ops
annotations:
summary:"{{ $labels.instance }}磁盤使用率{{ $value | humanizePercentage }}"
-alert:NodeDiskWillFull
expr:|
predict_linear(
node_filesystem_avail_bytes{mountpoint="/",fstype!="tmpfs"}[6h], 24*3600
) < 0
? ? ? ??for:10m
? ? ? ??labels:
? ? ? ? ??severity:warning
? ? ? ? ??team:ops
? ? ? ??annotations:
? ? ? ? ??summary:"{{ $labels.instance }}?磁盤預計24小時內寫滿"
? ? ? ? ??description:"按當前寫入速率推算,根分區將在24小時內耗盡"
? ? ??-alert:NodeNetworkErrors
? ? ? ??expr:|
? ? ? ? ? rate(node_network_receive_errs_total[5m]) > 10
or rate(node_network_transmit_errs_total[5m]) > 10
for:5m
labels:
severity:warning
team:ops
annotations:
summary:"{{ $labels.instance }}網卡{{ $labels.device }}出現錯誤包"
-alert:NodeLoadHigh
expr:node_load15/countby(instance)(node_cpu_seconds_total{mode="idle"})>2
for:10m
labels:
severity:warning
team:ops
annotations:
summary:"{{ $labels.instance }}15分鐘負載過高"
description:"負載/CPU核數比值{{ $value }},超過2說明系統嚴重過載"
說明:for參數很關鍵,設太短容易誤報,設太長又延遲告警。CPU和內存設5分鐘是因為短暫的毛刺很常見,持續5分鐘才說明真有問題。NodeDown設2分鐘,因為網絡抖動可能導致一兩次采集失敗,2分鐘(約8次采集)能過濾掉大部分誤報。
2.2.3 告警規則文件 - 應用服務監控
# 文件路徑:/etc/prometheus/rules/app_alerts.yml
groups:
-name:app_alerts
rules:
-alert:ServiceDown
expr:up{job=~"app-.*"}==0
for:1m
labels:
severity:critical
annotations:
summary:"服務{{ $labels.job }}實例{{ $labels.instance }}不可達"
-alert:HighErrorRate
expr:|
sum by(job) (rate(http_requests_total{status=~"5.."}[5m]))
/ sum by(job) (rate(http_requests_total[5m])) > 0.05
for:3m
labels:
severity:critical
annotations:
summary:"{{ $labels.job }}HTTP 5xx錯誤率{{ $value | humanizePercentage }}"
description:"錯誤率超過5%持續3分鐘,檢查應用日志"
-alert:HighLatencyP99
expr:|
histogram_quantile(0.99,
sum by(job, le) (rate(http_request_duration_seconds_bucket[5m]))
) > 2
for:5m
labels:
severity:warning
annotations:
summary:"{{ $labels.job }}P99延遲{{ $value | humanizeDuration }}"
-alert:QPSDropSudden
expr:|
sum by(job) (rate(http_requests_total[5m]))
< sum by(job) (rate(http_requests_total[1h] offset 1d)) * 0.5
? ? ? ??for:10m
? ? ? ??labels:
? ? ? ? ??severity:warning
? ? ? ??annotations:
? ? ? ? ??summary:"{{ $labels.job }}?QPS較昨日同期下降超過50%"
? ? ? ? ??description:"當前QPS?{{ $value }},可能存在流量異常"
? ? ??-alert:JVMHeapHigh
? ? ? ??expr:|
? ? ? ? ? jvm_memory_used_bytes{area="heap"}
? ? ? ? ? / jvm_memory_max_bytes{area="heap"} > 0.85
for:5m
labels:
severity:warning
annotations:
summary:"{{ $labels.instance }}JVM堆內存使用率{{ $value | humanizePercentage }}"
-alert:JVMGCTimeHigh
expr:|
rate(jvm_gc_pause_seconds_sum[5m])
/ rate(jvm_gc_pause_seconds_count[5m]) > 0.5
for:5m
labels:
severity:warning
annotations:
summary:"{{ $labels.instance }}GC平均耗時超過500ms"
2.2.4 釘釘通知模板配置
# 安裝prometheus-webhook-dingtalk cd/tmp wget https://github.com/timonwong/prometheus-webhook-dingtalk/releases/download/v2.1.0/prometheus-webhook-dingtalk-2.1.0.linux-amd64.tar.gz tar xzf prometheus-webhook-dingtalk-2.1.0.linux-amd64.tar.gz sudo cp prometheus-webhook-dingtalk-2.1.0.linux-amd64/prometheus-webhook-dingtalk /usr/local/bin/
# 文件路徑:/etc/prometheus-webhook-dingtalk/config.yml targets: ops: url:https://oapi.dingtalk.com/robot/send?access_token=YOUR_OPS_TOKEN secret:SEC_YOUR_OPS_SECRET message: title:'{{ template "ding.link.title" . }}' text:'{{ template "ding.link.content" . }}' critical: url:https://oapi.dingtalk.com/robot/send?access_token=YOUR_CRITICAL_TOKEN secret:SEC_YOUR_CRITICAL_SECRET warning: url:https://oapi.dingtalk.com/robot/send?access_token=YOUR_WARNING_TOKEN secret:SEC_YOUR_WARNING_SECRET dba: url:https://oapi.dingtalk.com/robot/send?access_token=YOUR_DBA_TOKEN secret:SEC_YOUR_DBA_SECRET
# Systemd服務 sudo tee /etc/systemd/system/dingtalk-webhook.service > /dev/null <'EOF' [Unit] Description=Prometheus Webhook DingTalk After=network-online.target [Service] Type=simple ExecStart=/usr/local/bin/prometheus-webhook-dingtalk ? --config.file=/etc/prometheus-webhook-dingtalk/config.yml ? --web.listen-address=0.0.0.0:8060 Restart=always RestartSec=5 [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl start dingtalk-webhook sudo systemctl?enable?dingtalk-webhook
2.3 啟動和驗證
2.3.1 啟動服務
# 檢查Alertmanager配置語法 amtool check-config /etc/alertmanager/alertmanager.yml # 輸出:Checking '/etc/alertmanager/alertmanager.yml' SUCCESS # 檢查告警規則語法 promtool check rules /etc/prometheus/rules/node_alerts.yml promtool check rules /etc/prometheus/rules/app_alerts.yml # 啟動Alertmanager sudo systemctl start alertmanager sudo systemctlenablealertmanager sudo systemctl status alertmanager # 重載Prometheus配置使告警規則生效 curl -X POST http://localhost:9090/-/reload
2.3.2 功能驗證
# 驗證Alertmanager健康狀態 curl -s http://localhost:9093/-/healthy # 輸出:OK # 查看當前告警規則 curl -s http://localhost:9090/api/v1/rules | python3 -m json.tool | head -40 # 查看活躍告警 curl -s http://localhost:9090/api/v1/alerts | python3 -m json.tool # 用amtool查看Alertmanager狀態 amtool --alertmanager.url=http://localhost:9093 config show # 發送測試告警驗證通知鏈路 curl -X POST http://localhost:9093/api/v2/alerts -H'Content-Type: application/json' -d'[{ "labels": { "alertname": "TestAlert", "severity": "warning", "instance": "test-node:9100" }, "annotations": { "summary": "這是一條測試告警,驗證通知鏈路" }, "startsAt": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'" }]' # 等30秒后檢查釘釘群是否收到通知 # 然后發送resolve清除測試告警 curl -X POST http://localhost:9093/api/v2/alerts -H'Content-Type: application/json' -d'[{ "labels": { "alertname": "TestAlert", "severity": "warning", "instance": "test-node:9100" }, "endsAt": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'" }]'
說明:每次改完告警規則或Alertmanager配置,一定要先用amtool和promtool做語法檢查。我們有一次直接reload了一個有語法錯誤的規則文件,Prometheus沒報錯但那條規則靜默失效了,直到出了故障才發現告警沒觸發。
三、示例代碼和配置
3.1 完整配置示例
3.1.1 K8s集群告警規則集
# 文件路徑:/etc/prometheus/rules/k8s_alerts.yml groups: -name:kubernetes_alerts rules: -alert:KubePodCrashLooping expr:| rate(kube_pod_container_status_restarts_total[15m]) * 60 * 5 > 0 for:5m labels: severity:warning annotations: summary:"Pod{{ $labels.namespace }}/{{ $labels.pod }}頻繁重啟" description:"過去15分鐘重啟次數:{{ $value | humanize }}" -alert:KubePodNotReady expr:| sum by(namespace, pod) ( max by(namespace, pod) (kube_pod_status_phase{phase=~"Pending|Unknown"}) * on(namespace, pod) group_left(owner_kind, owner_name) max by(namespace, pod, owner_kind, owner_name) (kube_pod_owner) ) > 0 for:10m labels: severity:warning annotations: summary:"Pod{{ $labels.namespace }}/{{ $labels.pod }}超過10分鐘未就緒" -alert:KubeDeploymentReplicasMismatch expr:| kube_deployment_spec_replicas != kube_deployment_status_ready_replicas for:10m labels: severity:warning annotations: summary:"Deployment{{ $labels.namespace }}/{{ $labels.deployment }}副本數不匹配" description:"期望{{ $labels.spec_replicas }},實際就緒{{ $labels.ready_replicas }}" -alert:KubeNodeNotReady expr:kube_node_status_condition{condition="Ready",status="true"}==0 for:5m labels: severity:critical annotations: summary:"K8s節點{{ $labels.node }}NotReady" -alert:KubeContainerOOMKilled expr:| kube_pod_container_status_last_terminated_reason{reason="OOMKilled"} == 1 for:0m labels: severity:warning annotations: summary:"容器{{ $labels.namespace }}/{{ $labels.pod }}/{{ $labels.container }}被OOM Kill" -alert:KubePVCAlmostFull expr:| kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes > 0.85 for:5m labels: severity:warning annotations: summary:"PVC{{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }}使用率超過85%"
3.1.2 中間件告警規則集
# 文件路徑:/etc/prometheus/rules/middleware_alerts.yml groups: -name:mysql_alerts rules: -alert:MySQLDown expr:mysql_up==0 for:1m labels: severity:critical team:dba annotations: summary:"MySQL{{ $labels.instance }}宕機" -alert:MySQLSlowQueries expr:rate(mysql_global_status_slow_queries[5m])>0.1 for:5m labels: severity:warning team:dba annotations: summary:"MySQL{{ $labels.instance }}慢查詢增多" description:"每秒慢查詢數{{ $value }}" -alert:MySQLConnectionsHigh expr:| mysql_global_status_threads_connected / mysql_global_variables_max_connections > 0.8 for:5m labels: severity:warning team:dba annotations: summary:"MySQL{{ $labels.instance }}連接數使用率{{ $value | humanizePercentage }}" -name:redis_alerts rules: -alert:RedisDown expr:redis_up==0 for:1m labels: severity:critical team:dba annotations: summary:"Redis{{ $labels.instance }}宕機" -alert:RedisMemoryHigh expr:| redis_memory_used_bytes / redis_memory_max_bytes > 0.85 for:5m labels: severity:warning team:dba annotations: summary:"Redis{{ $labels.instance }}內存使用率{{ $value | humanizePercentage }}" -alert:RedisRejectedConnections expr:increase(redis_rejected_connections_total[5m])>0 for:1m labels: severity:warning team:dba annotations: summary:"Redis{{ $labels.instance }}出現連接拒絕"
3.1.3 自定義釘釘通知模板
{{/* 文件路徑:/etc/alertmanager/templates/dingtalk.tmpl */}}
{{ define"ding.link.title"}}
{{ifeq (index .Alerts0).Labels.severity"critical"}}[P0-嚴重]{{else}}[P1-警告]{{ end }} {{ .GroupLabels.alertname }} ({{ .Alerts |len}}條)
{{ end }}
{{ define"ding.link.content"}}
{{ifeq .Status"firing"}}** 告警觸發**{{else}}** 告警恢復**{{ end }}
**告警名稱**: {{ .GroupLabels.alertname }}
**告警級別**: {{ (index .Alerts0).Labels.severity }}
**告警數量**: {{ .Alerts |len}}條
**觸發時間**: {{ (.Alerts.Firing | first).StartsAt.Local.Format"2006-01-02 1505"}}
{{range.Alerts }}
---
**實例**: {{ .Labels.instance }}
**摘要**: {{ .Annotations.summary }}
**詳情**: {{ .Annotations.description }}
{{ end }}
[查看詳情]({{ .ExternalURL }}/#/alerts?receiver={{ .Receiver | urlquery }})
{{ end }}
3.2 實際應用案例
案例一:告警分級策略落地
場景描述:我們團隊把告警分成P0-P3四個級別,不同級別走不同通知渠道和響應時效。這套分級策略跑了兩年多,告警疲勞問題基本解決了。
分級標準:
| 級別 | 定義 | 通知方式 | 響應時效 | 示例 |
|---|---|---|---|---|
| P0 | 核心服務不可用 | 電話+短信+釘釘 | 5分鐘內響應 | 數據庫宕機、支付服務掛了 |
| P1 | 服務降級但可用 | 釘釘+郵件 | 15分鐘內響應 | 錯誤率超5%、延遲超2秒 |
| P2 | 資源預警 | 釘釘群 | 1小時內處理 | 磁盤85%、內存90% |
| P3 | 信息通知 | 郵件 | 下個工作日處理 | 證書30天后過期 |
實現方式:在告警規則的labels里加severity字段,Alertmanager路由樹根據severity分發。
# Alertmanager路由配置片段 route: group_by:['alertname','cluster'] receiver:'default' routes: -match: severity:critical receiver:'p0-pager' group_wait:10s repeat_interval:30m -match: severity:warning receiver:'p1-dingtalk' group_wait:30s repeat_interval:4h -match: severity:info receiver:'p2-dingtalk' group_wait:1m repeat_interval:12h -match: severity:none receiver:'p3-email' repeat_interval:24h
案例二:企業微信Webhook告警腳本
場景描述:部分團隊用企業微信而不是釘釘,Alertmanager原生不支持企微,需要通過Webhook中轉。我們寫了個輕量的Python腳本做格式轉換。
實現代碼:
#!/usr/bin/env python3
# 文件名:/opt/scripts/wecom_webhook.py
# 功能:接收Alertmanager Webhook,轉發到企業微信機器人
# 啟動:python3 /opt/scripts/wecom_webhook.py
importjson
importrequests
fromflaskimportFlask, request
app = Flask(__name__)
WECOM_WEBHOOK_URL ="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_WECOM_KEY"
@app.route('/webhook', methods=['POST'])
defwebhook():
data = request.json
status = data.get('status','unknown')
alerts = data.get('alerts', [])
ifstatus =='firing':
color ="warning"
title =f"告警觸發 ({len(alerts)}條)"
else:
color ="info"
title =f"告警恢復 ({len(alerts)}條)"
content_lines = [f"##{title}
"]
foralertinalerts[:10]: # 最多顯示10條
labels = alert.get('labels', {})
annotations = alert.get('annotations', {})
content_lines.append(f"**{labels.get('alertname','N/A')}**")
content_lines.append(f"> 實例:{labels.get('instance','N/A')}")
content_lines.append(f"> 級別:{labels.get('severity','N/A')}")
content_lines.append(f"> 摘要:{annotations.get('summary','N/A')}
")
payload = {
"msgtype":"markdown",
"markdown": {
"content":"
".join(content_lines)
}
}
resp = requests.post(WECOM_WEBHOOK_URL, json=payload, timeout=10)
returnjson.dumps({"status":"ok","wecom_response": resp.status_code})
if__name__ =='__main__':
app.run(host='0.0.0.0', port=8065)
運行結果:
告警觸發 (2條) NodeCPUHigh > 實例: 10.0.1.12:9100 > 級別: warning > 摘要: 10.0.1.12:9100 CPU使用率 92.3% NodeMemoryHigh > 實例: 10.0.1.12:9100 > 級別: warning > 摘要: 10.0.1.12:9100 內存使用率 94.1%
四、最佳實踐和注意事項
4.1 最佳實踐
4.1.1 性能優化
告警規則分組評估:把相關的告警規則放在同一個group里,Prometheus會并行評估不同group。我們把600多條規則分成了12個group,評估耗時從3.2秒降到了0.8秒。
# 查看規則評估耗時
curl -s'http://localhost:9090/api/v1/query?query=prometheus_rule_group_duration_seconds{quantile="0.99"}'| jq .
避免在告警規則中使用高開銷PromQL:count()、group_left、label_replace這些操作在大數據量下很耗CPU。能用Recording Rules預聚合的先聚合,告警規則里直接查預聚合后的指標。
合理設置evaluation_interval:默認15秒評估一次,600條規則每次評估都要跑一遍PromQL。如果規則不需要那么高的時效性,可以在group級別設置更長的interval。比如磁盤空間告警,60秒評估一次完全夠用。
Alertmanager通知去重:group_by的選擇直接影響告警合并效果。按['alertname', 'cluster']分組,同一個集群同一類告警會合并成一條通知。別把instance放進group_by,不然每臺機器單獨發一條,網絡故障時釘釘群直接被刷屏。
4.1.2 安全加固
Alertmanager開啟Basic Auth:和Prometheus一樣,Alertmanager也支持web.yml配置認證。裸奔的Alertmanager任何人都能創建靜默規則,等于能讓告警失效。
# /etc/alertmanager/web.yml basic_auth_users: admin:$2a$12$KmR3iR5eJx5Oj5Yl5FpNOuJGQwMOsKOqJ7Mcp7hVQ8sKqGzLkjS6
Webhook地址用內網:釘釘/企微的Webhook轉發服務只監聽內網地址,不要暴露到公網。Webhook URL里包含access_token,泄露了別人就能往你的群里發消息。
告警通知脫敏:告警內容里不要包含敏感信息,比如數據庫連接串、密碼、內網IP段。通過模板控制輸出內容,只展示必要的診斷信息。
靜默規則審計:定期檢查Alertmanager的靜默規則,防止有人創建了永久靜默忘記刪除。我們寫了個腳本每天掃描一次,超過7天的靜默規則自動告警通知。
4.1.3 高可用配置
Alertmanager集群模式:生產環境至少部署3個Alertmanager實例,通過gossip協議同步狀態。Prometheus配置里寫上所有實例地址,任何一個掛了不影響告警通知。
# 實例1 alertmanager --cluster.listen-address=0.0.0.0:9094 --cluster.peer=10.0.1.51:9094 --cluster.peer=10.0.1.52:9094 # 實例2 alertmanager --cluster.listen-address=0.0.0.0:9094 --cluster.peer=10.0.1.50:9094 --cluster.peer=10.0.1.52:9094 # 實例3 alertmanager --cluster.listen-address=0.0.0.0:9094 --cluster.peer=10.0.1.50:9094 --cluster.peer=10.0.1.51:9094
通知渠道冗余:critical級別的告警至少配兩個通知渠道。我們的做法是釘釘+電話,釘釘掛了電話還能打通。曾經釘釘API故障了2小時,全靠電話通知兜底。
備份策略:Alertmanager的靜默規則和通知狀態存在--storage.path目錄下,定期備份這個目錄。
4.2 注意事項
4.2.1 配置注意事項
WARNING:告警配置改錯了可能導致關鍵告警丟失,后果比監控掛了還嚴重。
for參數不要設成0m,除非你確定這個告警不會有瞬時抖動。我們有個同事把CPU告警的for設成0,結果每天收到上百條CPU毛刺告警,一周后整個團隊都對告警通知免疫了。
continue: true要謹慎使用。設了continue后告警會繼續匹配下一條路由,可能導致同一條告警發到多個渠道。除非你確實需要多渠道通知,否則別加。
抑制規則的equal字段必須精確匹配。如果source和target的label名稱不一致,抑制不會生效,而且不會報錯。
4.2.2 常見錯誤
| 錯誤現象 | 原因分析 | 解決方案 |
|---|---|---|
| 告警規則配了但從不觸發 | PromQL表達式有誤或for時間太長 | 在Prometheus UI手動執行表達式驗證 |
| 同一條告警重復收到通知 | group_by配置不當導致分組過細 | 檢查group_by字段,減少分組維度 |
| 告警恢復通知沒收到 | receiver沒配send_resolved: true | 在webhook_configs里加上send_resolved |
| Alertmanager集群狀態不同步 | gossip端口不通或網絡分區 | 檢查9094端口連通性和防火墻規則 |
| 釘釘通知發送失敗 | access_token過期或IP白名單限制 | 檢查釘釘機器人配置和安全設置 |
4.2.3 兼容性問題
版本兼容:Alertmanager 0.27對配置文件格式做了一些調整,match和match_re在未來版本會被matchers替代。建議新項目直接用matchers語法。
平臺兼容:釘釘機器人2023年后強制要求加簽或IP白名單,老的Webhook URL直接用會返回310000錯誤碼。企業微信機器人對消息格式有長度限制,markdown內容超過4096字節會被截斷。
組件依賴:prometheus-webhook-dingtalk 2.x版本要求Go 1.19+編譯,低版本系統可能需要手動編譯。
五、故障排查和監控
5.1 故障排查
5.1.1 日志查看
# 查看Alertmanager日志 sudo journalctl -u alertmanager -f --no-pager # 查看最近的錯誤 sudo journalctl -u alertmanager --since"1 hour ago"| grep -i"error|warn" # 查看釘釘Webhook轉發服務日志 sudo journalctl -u dingtalk-webhook -f --no-pager
5.1.2 常見問題排查
問題一:告警規則配了但不觸發
# 檢查規則是否被Prometheus加載
curl -s http://localhost:9090/api/v1/rules | jq'.data.groups[].rules[] | select(.name=="NodeCPUHigh")'
# 手動執行告警表達式,看是否有返回值
curl -s'http://localhost:9090/api/v1/query?query=1-avg+by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m]))>0.85'| jq .
# 檢查for條件是否滿足(pending狀態說明條件滿足但還沒到for時間)
curl -s http://localhost:9090/api/v1/alerts | jq'.data.alerts[] | select(.labels.alertname=="NodeCPUHigh")'
解決方案:
先在Prometheus UI的Graph頁面手動執行PromQL,確認有數據返回
檢查for時間是否太長,臨時改短測試
檢查label是否匹配,job名、instance格式是否和實際一致
問題二:告警觸發了但通知沒收到
# 檢查Alertmanager是否收到了告警 curl -s http://localhost:9093/api/v2/alerts | jq'.[0:5]' # 檢查路由匹配結果 amtool --alertmanager.url=http://localhost:9093 config routestest severity=warning alertname=NodeCPUHigh # 檢查是否被靜默規則屏蔽 amtool --alertmanager.url=http://localhost:9093 silence query # 檢查是否被抑制 curl -s http://localhost:9093/api/v2/alerts | jq'.[] | select(.status.state=="suppressed")'
解決方案:
確認Prometheus配置了正確的Alertmanager地址
用amtool測試路由匹配,確認告警能匹配到正確的receiver
檢查靜默規則和抑制規則是否誤傷
問題三:Alertmanager集群腦裂
# 查看集群成員狀態 curl -s http://localhost:9093/api/v2/status | jq'.cluster' # 檢查gossip端口連通性 nc -zv 10.0.1.51 9094 nc -zv 10.0.1.52 9094 # 查看集群日志中的gossip相關信息 journalctl -u alertmanager | grep -i"gossip|cluster|peer"
解決方案:
確認9094端口TCP和UDP都放通了,gossip協議兩個都用
檢查各實例的--cluster.peer參數是否正確
如果網絡分區導致腦裂,恢復網絡后集群會自動合并
5.1.3 調試模式
# Alertmanager開啟debug日志 # 修改systemd服務,添加 --log.level=debug sudo systemctl edit alertmanager # 添加 ExecStart 覆蓋 # 查看告警路由匹配過程 amtool --alertmanager.url=http://localhost:9093 config routes show # 測試特定告警的路由匹配 amtool --alertmanager.url=http://localhost:9093 config routestest alertname=NodeDown severity=critical instance=10.0.1.10:9100
5.2 性能監控
5.2.1 關鍵指標監控
# Alertmanager通知發送成功率 curl -s'http://localhost:9093/metrics'| grep alertmanager_notifications_total # 通知發送延遲 curl -s'http://localhost:9093/metrics'| grep alertmanager_notification_latency # 當前活躍告警數 curl -s'http://localhost:9093/api/v2/alerts?active=true'| jq'length' # Prometheus規則評估耗時 curl -s'http://localhost:9090/metrics'| grep prometheus_rule_group_duration
5.2.2 監控指標說明
| 指標名稱 | 正常范圍 | 告警閾值 | 說明 |
|---|---|---|---|
| alertmanager_notifications_failed_total | 0 | >0 | 通知發送失敗計數 |
| alertmanager_notification_latency_seconds | <5s | >30s | 通知發送延遲 |
| prometheus_rule_group_duration_seconds | <1s | >5s | 規則組評估耗時 |
| prometheus_rule_evaluation_failures_total | 0 | >0 | 規則評估失敗數 |
| alertmanager_alerts | 根據規模定 | >500 | 活躍告警數量 |
5.2.3 Alertmanager自監控告警規則
# 文件路徑:/etc/prometheus/rules/alertmanager_self_rules.yml
groups:
-name:alertmanager_self
rules:
-alert:AlertmanagerDown
expr:up{job="alertmanager"}==0
for:1m
labels:
severity:critical
annotations:
summary:"Alertmanager{{ $labels.instance }}宕機"
-alert:AlertmanagerNotificationFailed
expr:increase(alertmanager_notifications_failed_total[5m])>0
for:1m
labels:
severity:critical
annotations:
summary:"Alertmanager通知發送失敗"
description:"集成{{ $labels.integration }}發送失敗"
-alert:AlertmanagerClusterMemberDown
expr:alertmanager_cluster_members<3
? ? ? ??for:5m
? ? ? ??labels:
? ? ? ? ??severity:warning
? ? ? ??annotations:
? ? ? ? ??summary:"Alertmanager集群成員數不足3"
5.3 備份與恢復
5.3.1 備份策略
#!/bin/bash
# 文件名:/opt/scripts/alertmanager_backup.sh
# 備份Alertmanager配置和狀態數據
BACKUP_DIR="/data/backup/alertmanager"
DATE=$(date +%Y%m%d)
mkdir -p"${BACKUP_DIR}"
# 備份配置文件
tar czf"${BACKUP_DIR}/alertmanager_config_${DATE}.tar.gz"
/etc/alertmanager/
/etc/prometheus/rules/
# 備份狀態數據(靜默規則等)
tar czf"${BACKUP_DIR}/alertmanager_data_${DATE}.tar.gz"
/var/lib/alertmanager/
# 清理30天前的備份
find"${BACKUP_DIR}"-name"*.tar.gz"-mtime +30 -delete
5.3.2 恢復流程
停止服務:sudo systemctl stop alertmanager
恢復配置:tar xzf /data/backup/alertmanager/alertmanager_config_20241215.tar.gz -C /
恢復數據:tar xzf /data/backup/alertmanager/alertmanager_data_20241215.tar.gz -C /
重啟服務:sudo systemctl start alertmanager
六、總結
6.1 技術要點回顧
告警規則的for參數是過濾誤報的關鍵手段。CPU/內存類告警設5分鐘,服務宕機類設1-2分鐘,磁盤預測類設10分鐘,這是我們反復調優后的經驗值。
Alertmanager的路由樹設計決定了告警通知的效率。按severity分級路由,配合group_by做告警合并,能把日均300條告警收斂到30條有效通知。
抑制規則能大幅減少告警風暴。節點宕機時自動抑制該節點上所有服務告警,一次網絡故障從80條告警收斂到3條通知。
告警分級策略(P0-P3)是告警治理的基礎。不同級別走不同通知渠道和響應時效,避免所有告警一視同仁導致的告警疲勞。
通知渠道要做冗余,critical級別至少配兩個渠道。釘釘API故障時電話通知兜底,這個設計救過我們好幾次。
6.2 進階學習方向
告警自愈(Auto-Remediation):告警觸發后自動執行修復腳本,比如磁盤滿了自動清理日志、服務掛了自動重啟。可以通過Webhook對接自動化平臺實現。
實踐建議:從簡單的場景開始,比如自動重啟崩潰的服務,逐步擴展到更復雜的自愈場景
AIOps智能告警:基于歷史告警數據做異常檢測,替代固定閾值。Prometheus的predict_linear是最簡單的預測函數,更復雜的可以對接外部ML模型。
實踐建議:先用predict_linear做磁盤和流量預測,積累經驗后再考慮引入ML模型
OnCall輪值管理:配合PagerDuty或自建OnCall系統,實現告警自動分派和升級。值班人員15分鐘沒響應自動升級給主管。
6.3 參考資料
Alertmanager官方文檔 - 配置參數和路由規則詳解
Awesome Prometheus Alerts - 社區告警規則集合
prometheus-webhook-dingtalk - 釘釘通知轉發工具
PromQL備忘單 - 告警表達式編寫參考
附錄
A. 命令速查表
# Alertmanager操作 amtool check-config /etc/alertmanager/alertmanager.yml # 檢查配置語法 amtool --alertmanager.url=http://localhost:9093 alert query # 查看活躍告警 amtool --alertmanager.url=http://localhost:9093 silence add alertname=NodeCPUHigh -d 2h -c"計劃維護" # 創建2小時靜默 amtool --alertmanager.url=http://localhost:9093 silence query # 查看靜默規則 amtool --alertmanager.url=http://localhost:9093 silence expire# 刪除靜默 # 告警規則操作 promtool check rules /etc/prometheus/rules/*.yml # 檢查規則語法 promtooltestrules test_rules.yml # 單元測試告警規則 curl -X POST http://localhost:9090/-/reload # 熱重載規則
B. 配置參數詳解
Alertmanager路由參數:
| 參數 | 默認值 | 說明 |
|---|---|---|
| group_by | [] | 告警分組依據的label列表 |
| group_wait | 30s | 新告警組等待合并的時間 |
| group_interval | 5m | 同組告警發送間隔 |
| repeat_interval | 4h | 已發送告警重復通知間隔 |
| continue | false | 匹配后是否繼續匹配下一條路由 |
| match | - | 精確匹配label |
| match_re | - | 正則匹配label |
| receiver | - | 接收器名稱 |
C. 術語表
| 術語 | 英文 | 解釋 |
|---|---|---|
| 告警規則 | Alert Rule | 基于PromQL表達式定義的告警條件,由Prometheus評估 |
| 路由樹 | Route Tree | Alertmanager中告警分發的樹狀匹配結構 |
| 分組 | Grouping | 將相同label的告警合并為一條通知發送 |
| 抑制 | Inhibition | 當某條告警觸發時自動屏蔽相關的其他告警 |
| 靜默 | Silence | 在指定時間窗口內屏蔽匹配條件的告警通知 |
| 接收器 | Receiver | 告警通知的目標渠道配置(郵件、Webhook等) |
| 去重 | Deduplication | Alertmanager集群中避免同一告警被多次通知的機制 |
| for持續時間 | For Duration | 告警條件需要持續滿足的時間,用于過濾瞬時抖動 |
-
容器
+關注
關注
0文章
531瀏覽量
22965 -
Prometheus
+關注
關注
0文章
36瀏覽量
2054
原文標題:企業級監控告警落地:Prometheus 規則分層與 Alertmanager 通知編排
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
Prometheus的基本原理與開發指南
基于人工智能的網絡告警關聯分析處理方法
編寫PCB設計規則檢查器技巧
編寫屬于自己的PCB設計規則檢查器
加權增量關聯規則挖掘在通信告警預測中的應用說明
可視化操作的告警軟件背景現狀
Prometheus API使用介紹
SpringBoot+Prometheus+Grafana實現自定義監控
prometheus下載安裝教程
Prometheus告警規則編寫與Alertmanager通知配置實戰
評論