Prometheus監控神器-Alertmanager篇(1)

雲原生之道發表於2020-08-06

本章節主要涵蓋了Alertmanager的工作機制與配置檔案的比較詳細的知識內容,由淺入深的給大家講解。

警報一直是整個監控系統中的重要組成部分,Prometheus監控系統中,採集與警報是分離的。警報規則在 Prometheus 定義,警報規則觸發以後,才會將資訊轉發到給獨立的元件
Alertmanager ,經過 Alertmanager r對警報的資訊處理後,最終通過接收器傳送給指定使用者,另外在 Alertmanager 中沒有通知組的概念,只能自己對軟體重新Coding,或者使用第三方外掛來實現。
注意,這個通知組不是Alertmanager中的group概念,下面會詳細講 Group ,不要混淆哦。

前面已經介紹過一些關於 Alertmanager 知識點,本章開始針通過安裝 Alertmanager 元件,對配置檔案做詳細說明,同時介紹 Prometheus 的警報規則的定義,最後使用Email、Wechat(Robot)、Dingtalk(webhook)來接受警報通知。

Alertmanager工作機制

alertmanager-arch

在Prometheus生態架構裡,警報是由獨立的倆部分組成,可以通過上圖很清晰的瞭解到 Prometheus 的警報工作機制。其中 PrometheusAlertmanager 是分離的倆個元件。我們使用Prometheus Server端通過靜態或者動態配置
去拉取 pull 部署在k8s或雲主機上的各種類別的監控指標資料,然後基於我們前面講到的 PromQL 對這些已經儲存在本地儲存 HDD/SSDTSDB 中的指標定義閾值警報規則 Rules 。Prometheus會根據配置的引數週期性的對警報規則進行計算,
如果滿足警報條件,生產一條警報資訊,將其推送到 Alertmanager 元件,Alertmanager 收到警報資訊之後,會對警告資訊進行處理,進行 分組 Group 並將它們通過定義好的路由 Routing 規則轉到 正確的接收器 receiver
比如 Email Slack 釘釘、企業微信 Robot(webhook) 企業微信 等,最終異常事件 WarningError通知給定義好的接收人,其中如釘釘是基於第三方通知來實現的,對於通知人定義是在釘釘的第三方元件中配置。

Prometheus 中, 我們不僅僅可以對單條警報進行命名通過 PromQL定義規則,更多時候是對相關的多條警報進行分組後統一定義。這些定義會在後面說明與其管理方法。下面開始把 Alertmanager 中的分組 Grouping 、抑制 Inhibition、延遲 Silences
核心特性進行介紹,便於大家系統性的學習與理解。

AlertManager的三個概念

分組

GroupingAlertmanager 把同型別的警報進行分組,合併多條警報到一個通知中。在生產環境中,特別是雲環境下的業務之間密集耦合時,若出現多臺 Instance 故障,可能會導致成千上百條警報觸發。在這種情況下使用分組機制,
可以把這些被觸發的警報合併為一個警報進行通知,從而避免瞬間突發性的接受大量警報通知,使得管理員無法對問題進行快速定位。

舉個例子,在Kubernetes叢集中,執行著重量級規模的例項,即便是叢集中持續很小一段時間的網路延遲或者延遲導致網路抖動,也會引發大量類似服務應用無法連線 DB 的故障。如果在警報規則中定義每一個應用例項都傳送警報,那麼到最後的結果就是
會有大量的警報資訊傳送給 Alertmanager

作為運維組或者相關業務組的開發人員,可能更關心的是在一個通知中就可以快速檢視到哪些服務例項被本次故障影響了。為此,我們對服務所在叢集或者服務警報名稱的維度進行分組配置,把警報彙總成一條通知時,就不會受到警報資訊的頻繁傳送影響了。

抑制

Inhibition 是 當某條警報已經傳送,停止重複傳送由此警報引發的其他異常或故障的警報機制。在生產環境中,IDC託管機櫃中,若每一個機櫃接入層僅僅是單臺交換機,那麼該機櫃接入交換機故障會造成機櫃中伺服器非 up 狀態警報。再有伺服器上部署的應用服務不可訪問也會觸發警報。
這時候,可以通過在 Alertmanager 配置忽略由於交換機故障而造成的此機櫃中的所有伺服器及其應用不可達而產生的警報。

在我們的災備體系中,當原有叢集故障當機業務徹底無法訪問的時候,會把使用者流量切換到備份叢集中,這樣為故障叢集及其提供的各個微服務狀態傳送警報機會失去了意義,此時, Alertmanager 的抑制特性就可以在一定程度上避免管理員收到過多無用的警報通知。

靜默

Silences 提供了一個簡單的機制,根據標籤快速對警報進行靜默處理;對傳進來的警報進行匹配檢查,如果接受到警報符合靜默的配置,Alertmanager 則不會傳送警報通知。

以上除了分組、抑制是在 Alertmanager 配置檔案中配置,靜默是需要在 WEB UI 介面中設定臨時遮蔽指定的警報通知。

以上的概念需要好好理解,這樣才可以輕鬆的在監控系統設計的時候針對警報設計的一些場景自行調整。

安裝Alertmanager

前面已經講過了,我們可以使用 ansible 中自動化對 Alertmanager 進行安裝、配置、啟動、更新,這裡僅僅只是用 Alertmanager 的二進位制安裝,以 systemd 管理啟動。

## 建立相關目錄
mkdir -p /data/alertmanager/{bin,conf,logs,data,templates}
## 下載二進位制包,並
wget https://github.com/prometheus/alertmanager/releases/download/v0.21.0/alertmanager-0.21.0.linux-amd64.tar.gz
tar xvf alertmanager-0.21.0.linux-amd64.tar.gz
mv alertmanager-0.21.0.linux-amd64/{alertmanager,amtool} /data/alertmanager/bin/
mv alertmanager-0.21.0.linux-amd64/alertmanager.yml /data/alertmanager/conf/
# 目錄結構
/data/alertmanager/
├── bin
│   ├── alertmanager
│   └── amtool
├── conf
│   └── alertmanager.yml
├── data
├── logs
└── templates
## 加入systemd啟動指令碼
cat <<EOF >/lib/systemd/system/alertmanager.service
[Unit]
Description=alertmanager
Documentation=https://prometheus.io/
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
User=prometheus
ExecStart=/data/alertmanager/bin/alertmanager --storage.path="/data/alertmanager/data/" \
--config.file=/usr/local/alertmanager/alertmanager.yml \
--web.external-url=http://192.168.1.220 # 此處可以寫域名,需要做proxy。
Restart=always
RestartSec=1
# Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

## 啟動
systemctl enable alertmanager
systemctl start alertmanager

Alertmanager 引數

引數 描述
--config.file="alertmanager.yml" 指定Alertmanager配置檔案路徑
--storage.path="data/" Alertmanager的資料存放目錄
--data.retention=120h 歷史資料保留時間,預設為120h
--alerts.gc-interval=30m 警報gc之間的間隔
--web.external-url=WEB.EXTERNAL-URL 外部可訪問的Alertmanager的URL(例如Alertmanager是通過nginx反向代理)
--web.route-prefix=WEB.ROUTE-PREFIX wen訪問內部路由路徑,預設是 --web.external-url
--web.listen-address=":9093" 監聽埠,可以隨意修改
--web.get-concurrency=0 併發處理的最大GET請求數,預設為0
--web.timeout=0 web請求超時時間
--cluster.listen-address="0.0.0.0:9094" 叢集的監聽埠地址。設定為空字串禁用HA模式
--cluster.advertise-address=CLUSTER.ADVERTISE-ADDRESS 配置叢集通知地址
--cluster.gossip-interval=200ms 傳送條訊息之間的間隔,可以以增加頻寬為代價更快地跨叢集傳播。
--cluster.peer-timeout=15s 在同級之間等待傳送通知的時間
... ...
--log.level=info 自定義訊息格式 [debug, info, warn, error]
--log.format=logfmt 日誌訊息的輸出格式: [logfmt, json]
--version 顯示版本號

Alertmanager配置詳解

Alertmanager一個完整的配置檔案範例:

## Alertmanager 配置檔案
global:
  resolve_timeout: 5m
  # smtp配置
  smtp_from: "123456789@qq.com"
  smtp_smarthost: 'smtp.qq.com:465'
  smtp_auth_username: "123456789@qq.com"
  smtp_auth_password: "auth_pass"
  smtp_require_tls: true
# email、企業微信的模板配置存放位置,釘釘的模板會單獨講如果配置。
templates:
  - '/data/alertmanager/templates/*.tmpl'
# 路由分組
route:
  receiver: ops
  group_wait: 30s # 在組內等待所配置的時間,如果同組內,30秒內出現相同報警,在一個組內出現。
  group_interval: 5m # 如果組內內容不變化,合併為一條警報資訊,5m後傳送。
  repeat_interval: 24h # 傳送報警間隔,如果指定時間內沒有修復,則重新傳送報警。
  group_by: [alertname]  # 報警分組
  routes:
      - match:
          team: operations
        group_by: [env,dc]
        receiver: 'ops'
      - match_re:
          service: nginx|apache
        receiver: 'web'
      - match_re:
          service: hbase|spark
        receiver: 'hadoop'
      - match_re:
          service: mysql|mongodb
        receiver: 'db'
# 接收器
# 抑制測試配置
      - receiver: ops
        group_wait: 10s
        match:
          status: 'High'
# ops
      - receiver: ops # 路由和標籤,根據match來指定傳送目標,如果 rule的lable 包含 alertname, 使用 ops 來傳送
        group_wait: 10s
        match:
          team: operations
# web
      - receiver: db # 路由和標籤,根據match來指定傳送目標,如果 rule的lable 包含 alertname, 使用 db 來傳送
        group_wait: 10s
        match:
          team: db
# 接收器指定傳送人以及傳送渠道
receivers:
# ops分組的定義
- name: ops
  email_configs:
  - to: '9935226@qq.com,10000@qq.com'
    send_resolved: true
    headers:
      subject: "[operations] 報警郵件"
      from: "警報中心"
      to: "小煜狼皇"
  # 釘釘配置
  webhook_configs:
  - url: http://localhost:8070/dingtalk/ops/send
    # 企業微信配置
  wechat_configs:
  - corp_id: 'ww5421dksajhdasjkhj'
    api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
    send_resolved: true
    to_party: '2'
    agent_id: '1000002'
    api_secret: 'Tm1kkEE3RGqVhv5hO-khdakjsdkjsahjkdksahjkdsahkj'

# web
- name: web
  email_configs:
  - to: '9935226@qq.com'
    send_resolved: true
    headers: { Subject: "[web] 報警郵件"} # 接收郵件的標題
  webhook_configs:
  - url: http://localhost:8070/dingtalk/web/send
  - url: http://localhost:8070/dingtalk/ops/send
# db
- name: db
  email_configs:
  - to: '9935226@qq.com'
    send_resolved: true
    headers: { Subject: "[db] 報警郵件"} # 接收郵件的標題
  webhook_configs:
  - url: http://localhost:8070/dingtalk/db/send
  - url: http://localhost:8070/dingtalk/ops/send
# hadoop
- name: hadoop
  email_configs:
  - to: '9935226@qq.com'
    send_resolved: true
    headers: { Subject: "[hadoop] 報警郵件"} # 接收郵件的標題
  webhook_configs:
  - url: http://localhost:8070/dingtalk/hadoop/send
  - url: http://localhost:8070/dingtalk/ops/send

# 抑制器配置
inhibit_rules: # 抑制規則
  - source_match: # 源標籤警報觸發時抑制含有目標標籤的警報,在當前警報匹配 status: 'High'
      status: 'High'  # 此處的抑制匹配一定在最上面的route中配置不然,會提示找不key。
    target_match:
      status: 'Warning' # 目標標籤值正則匹配,可以是正規表示式如: ".*MySQL.*"
    equal: ['alertname','operations', 'instance'] # 確保這個配置下的標籤內容相同才會抑制,也就是說警報中必須有這三個標籤值才會被抑制。

global

即為全域性設定,在 Alertmanager 配置檔案中,只要全域性設定配置了的選項,全部為公共設定,可以讓其他設定繼承,作為預設值,可以子引數中覆蓋其設定。其中 resolve_timeout 用於設定處理超時時間,也是生命警報狀態為解決的時間,
這個時間會直接影響到警報恢復的通知時間,需要自行結合實際生產場景來設定主機的恢復時間,預設是5分鐘。在全域性設定中可以設定smtp服務,同時也支援slack、victorops、pagerduty等,在這裡只講我們常用的Email,釘釘,企業微信,
同時也可以自己使用go語言開發的gubot進行二次開發,對接自定義webhook通知源。

template

警報模板可以自定義通知的資訊格式,以及其包含的對應警報指標資料,可以自定義Email、企業微信的模板,配置指定的存放位置,對於釘釘的模板會單獨講如何配置,這裡的模板是指的傳送的通知源資訊格式模板,比如Email,企業微信。

route

警報路由模組描述了在收到 Prometheus 生成的警報後,將警報資訊傳送給接收器 receiver 指定的目標地址規則。 Alertmanager 對傳入的警報資訊進行處理,根據所定義的規則與配置進行匹配。對於路由可以理解為樹狀結構,
設定的第一個route是跟節點,往下的就是包含的子節點,每個警報傳進來以後,會從配置的跟節點路由進入路由樹,按照深度優先從左向右遍歷匹配,當匹配的節點後停止,進行警報處理。

引數描述

引數 描述
receiver: <string> 傳送警報的接收器名稱
group_by: ['label_name1,...'] 根據 prometheus 的 lables 進行報警分組,這些警報會合併為一個通知傳送給接收器,也就是警報分組。
match: [ <label_name>: <labelvalue>,...] 通過此設定來判斷當前警報中是否有標籤的labelname,等同於labelvalue。
match_re: [<label_name>: <regex>,...] 通過正規表示式進行警報配置
group_wait: [<duration>]|default=30s 設定從接受警報到傳送的等待時間,若在等待時間中group接收到新的警報資訊,這些警報會合併為一條傳送。
group_interval: [<duration>]|default=5m 此設定控制的是 group 之間傳送警報通知的間隔時間。
repeat_interval: [<duration>]|default=4h 此設定控制的是警報傳送成功以後,沒有對警報做解決操作的話,狀態 Firing 沒有變成 Inactive 或者 Pending ,會再次傳送警報的的間隔時間。
routes: - <route>... 子路由的匹配設定

路由匹配規則:

例子:

route:
  receiver: admin # 預設的接收器名稱
  group_wait: 30s # 在組內等待所配置的時間,如果同組內,30秒內出現相同報警,在一個組內出現。
  group_interval: 5m # 如果組內內容不變化,5m後傳送。
  repeat_interval: 24h # 傳送報警間隔,如果指定時間內沒有修復,則重新傳送報警
  group_by: [alertname,cluster]  # 報警分組,根據 prometheus 的 lables 進行報警分組,這些警報會合併為一個通知傳送給接收器,也就是警報分組。
  routes:
      - match:
          team: ops
        group_by: [env,dc]
        receiver: 'ops'
      - match_re:
          service: nginx|apache
        receiver: 'web'
      - match_re:
          service: mysql|mongodb
        receiver: 'db'
      - match_re:
          service: hbase|spark
        receiver: 'hadoop'

在以上的例子中,預設的警報組全部傳送給 admin ,且根據路由按照 alertname cluster 進行警報分組。在子路由中的若匹配警報中的標籤 team 的值為 ops,Alertmanager 會按照標籤 env dc 進行警報分組然後傳送給接收器 receiver ops配置的警報通知源。
繼續匹配的操作是對 service 標籤進行匹配,並且配到了 nginx redis mongodb 的值,就會向接收器 receiver web配置的警報通知源傳送警報資訊。

對這種匹配驗證操作灰常考究個人的邏輯思維能力,這不是人乾的事情呀~因此,Prometheus釋出了一個 Routing tree editor
用於檢測Alertmanager的配置檔案結構配置資訊,然後除錯。使用方法很簡單,就是把 alertmanager.yml 的配置信心複製到這個站點,然後點選 Draw Routing Tree 按鈕生成路由結構樹,
然後在 Match Label Set 前面輸入以 {<label name> = "<value>"} 格式的警報標籤,然後點選 Match Label Set 按鈕會顯示傳送狀態圖。

以下是通過routing tree editor生成的樹結構圖.

routing-tree-1

然後我們可以使用 {service="nginx"}{service="spark"} 表示式來做匹配的規則用於驗證其傳送通知源是否為 receiver 中db的傳送配置。

routing-tree-2

routing-tree-3

receiver

接受器是一個統稱,每個 receiver 都有需要設定一個全域性唯一的名稱,並且對應一個或者多個通知方式,包括email、微信、Slack、釘釘等。

官方現在滿足的配置是:

name: <string>
email_config:
    [ - <config> ]
hipchat_configs: #此模組配置已經被移除了
    [ <config> ]
pagerduty_configs:
    [ <config> ]
pushover_configs:
    [ <config> ]
slack_configs:
    [ <config> ]
opsgenie_configs:
    [ <config> ]
webhook_configs:
    [ <config> ]
victorops_configs:
    [ <config> ]
webchat_configs:
    [ <config> ]

可以看到Alertmanager提供了很多種接收器的通知配置,我們可以使用webhook接收器來定義通知整合,支援使用者自己定義編寫。

官方receiver配置

inhibit_rules

inhibit_rules 模組中設定警報抑制功能,可以指定在特定條件下需要忽略的警報條件。可以使用此選項設定首選,比如優先處理某些警報,如果同一組中的警報同時發生,則忽略其他警報。
合理使用 inhibit_rules ,可以減少頻發傳送沒有意義的警報的產生。

inhibit_rules 配置資訊:

trget_match:
     [ <label_name>: <labelvalue>,... ]
trget_match_re:
     [ <label_name>: <labelvalue>,... ]
source_match:
     [ <label_name>: <labelvalue>,... ]
source_match_re:
     [ <label_name>: <labelvalue>,... ]
[ equal: '[' <lable_name>, ...]']

範例:

inhibit_rules: # 抑制規則
  - source_match: # 源標籤警報觸發時抑制含有目標標籤的警報,在當前警報匹配 status: 'High'
      status: 'High'  # 此處的抑制匹配一定在最上面的route中配置不然,會提示找不key。
    target_match:
      status: 'Warning' # 目標標籤值正則匹配,可以是正規表示式如: ".*MySQL.*"
    equal: ['alertname','operations', 'instance'] # 確保這個配置下的標籤內容相同才會抑制,也就是說警報中必須有這三個標籤值才會被抑制。

以上示例是指 如果匹配 equal 中的抑制的標籤值,觸發了包含 equal 中的標籤值的 status: 'High' 警報 ,則不傳送含包含 equal 中的標籤值的 status: 'Warning' 標籤的警報。
這裡儘量避免 source_matchtarget_match 之間的重疊,否則很難做到理解與維護,同時建議謹慎使用此功能。使用基於症狀的警報時,警報之間很少需要相互依賴。

如果大家有什麼好的想法與意見,的可以掃碼關注公眾號,回覆群或者加我微信交流。

wecaht

相關文章