AlertManager 部署及使用


 熟悉了 Grafana 的報警功能,但是 Grafana 的報警功能目前還比較弱,只支持 Graph 的圖表的報警。今天來給大家介紹一個功能更加強大的報警工具:AlertManager。

簡介

之前我們學習 Prometheus 的時候就了解到 Prometheus 包含一個報警模塊,就是我們的 AlertManager,Alertmanager 主要用於接收 Prometheus 發送的告警信息,它支持豐富的告警通知渠道,而且很容易做到告警信息進行去重,降噪,分組等,是一款前衛的告警通知系統。

架構架構

接下來我們就來學習下 AlertManager 的具體使用方法。

安裝

從官方文檔https://prometheus.io/docs/alerting/configuration/中我們可以看到下載AlertManager二進制文件后,可以通過下面的命令運行:

$ ./alertmanager --config.file=simple.yml 

其中-config.file參數是用來指定對應的配置文件的,由於我們這里同樣要運行到 Kubernetes 集群中來,所以我們使用docker鏡像的方式來安裝,使用的鏡像是:prom/alertmanager:v0.15.3

首先,指定配置文件,同樣的,我們這里使用一個 ConfigMap 資源對象:(alertmanager-conf.yaml)

apiVersion: v1 kind: ConfigMap metadata: name: alert-config namespace: kube-ops data: config.yml: |- global: # 在沒有報警的情況下聲明為已解決的時間 resolve_timeout: 5m # 配置郵件發送信息 smtp_smarthost: 'smtp.163.com:25' smtp_from: 'ych_1024@163.com' smtp_auth_username: 'ych_1024@163.com' smtp_auth_password: '<郵箱密碼>' smtp_hello: '163.com' smtp_require_tls: false # 所有報警信息進入后的根路由,用來設置報警的分發策略 route: # 這里的標簽列表是接收到報警信息后的重新分組標簽,例如,接收到的報警信息里面有許多具有 cluster=A 和 alertname=LatncyHigh 這樣的標簽的報警信息將會批量被聚合到一個分組里面 group_by: ['alertname', 'cluster'] # 當一個新的報警分組被創建后,需要等待至少group_wait時間來初始化通知,這種方式可以確保您能有足夠的時間為同一分組來獲取多個警報,然后一起觸發這個報警信息。 group_wait: 30s # 當第一個報警發送后,等待'group_interval'時間來發送新的一組報警信息。 group_interval: 5m # 如果一個報警信息已經發送成功了,等待'repeat_interval'時間來重新發送他們 repeat_interval: 5m # 默認的receiver:如果一個報警沒有被一個route匹配,則發送給默認的接收器 receiver: default # 上面所有的屬性都由所有子路由繼承,並且可以在每個子路由上進行覆蓋。 routes: - receiver: email group_wait: 10s match: team: node receivers: - name: 'default' email_configs: - to: '517554016@qq.com' send_resolved: true - name: 'email' email_configs: - to: '517554016@qq.com' send_resolved: true 

這是 AlertManager 的配置文件,我們先直接創建這個 ConfigMap 資源對象:

$ kubectl create -f alertmanager-conf.yaml
configmap "alert-config" created 

然后配置 AlertManager 的容器,我們可以直接在之前的 Prometheus 的 Pod 中添加這個容器,對應的 YAML 資源聲明如下:

  - name: alertmanager image: prom/alertmanager:v0.15.3 imagePullPolicy: IfNotPresent args: - "--config.file=/etc/alertmanager/config.yml" ports: - containerPort: 9093 name: http volumeMounts: - mountPath: "/etc/alertmanager" name: alertcfg resources: requests: cpu: 100m memory: 256Mi limits: cpu: 100m memory: 256Mi volumes: - name: alertcfg configMap: name: alert-config 

這里我們將上面創建的 alert-config 這個 ConfigMap 資源對象以 Volume 的形式掛載到 /etc/alertmanager 目錄下去,然后在啟動參數中指定了配置文件--config.file=/etc/alertmanager/config.yml,然后我們可以來更新這個 Prometheus 的 Pod:

$ kubectl apply -f prome-deploy.yaml
deployment.extensions "prometheus" configured 

當然我們也可以將 AlertManager 的配置文件內容直接放入到之前的 Prometheus 的 ConfigMap 的資源對象中,也可以用一個單獨的 Pod 來運行 AlertManager 這個容器,完整的資源清單文件可以參考這里:https://github.com/cnych/kubeapp/tree/master/prometheus

AlertManager 的容器啟動起來后,我們還需要在 Prometheus 中配置下 AlertManager 的地址,讓 Prometheus 能夠訪問到 AlertManager,在 Prometheus 的 ConfigMap 資源清單中添加如下配置:

alerting: alertmanagers: - static_configs: - targets: ["localhost:9093"] 

更新這個資源對象后,稍等一小會兒,執行 reload 操作:

$ kubectl delete -f prome-cm.yaml
configmap "prometheus-config" deleted $ kubectl create -f prome-cm.yaml configmap "prometheus-config" created # 隔一會兒后 $ kubectl get svc -n kube-ops NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE prometheus NodePort 10.102.74.90 <none> 9090:30358/TCP 3d $ curl -X POST "http://10.102.74.90:9090/-/reload" 

更新完成后,我們查看 Pod 發現有錯誤,查看下 alertmanager 容器的日志,發現有如下錯誤信息:

$ kubectl get pods -n kube-ops
NAME                          READY     STATUS             RESTARTS   AGE
prometheus-56d64bf6f7-rpz9j   1/2       CrashLoopBackOff   491        1d
$ kubectl logs -f prometheus-56d64bf6f7-rpz9j alertmanager -n kube-ops
level=info ts=2018-11-28T10:33:51.830071513Z caller=main.go:174 msg="Starting Alertmanager" version="(version=0.15.3, branch=HEAD, revision=d4a7697cc90f8bce62efe7c44b63b542578ec0a1)" level=info ts=2018-11-28T10:33:51.830362309Z caller=main.go:175 build_context="(go=go1.11.2, user=root@4ecc17c53d26, date=20181109-15:40:48)" level=error ts=2018-11-28T10:33:51.830464639Z caller=main.go:179 msg="Unable to create data directory" err="mkdir data/: read-only file system" 

這個是因為新版本dockerfile中的默認WORKDIR發生了變化,變成了/etc/alertmanager目錄,默認情況下存儲路徑--storage.path是相對目錄data/,因此,alertmanager 會在我們上面掛載的 ConfigMap 中去創建這個目錄,所以會報錯,我們可以通過覆蓋--storage.path參數來解決這個問題,在容器啟動參數中添加該參數:

- name: alertmanager
  image: prom/alertmanager:v0.15.3
  imagePullPolicy: IfNotPresent
  args:
  - "--config.file=/etc/alertmanager/config.yml" - "--storage.path=/alertmanager/data" 

重新更新 Pod,可以發現 Prometheus 已經是 Running 狀態了:

$ kubectl apply -f prome-deploy.yaml
deployment.extensions "prometheus" configured $ kubectl get pods -n kube-ops NAME READY STATUS RESTARTS AGE prometheus-646f457455-gr8x5 2/2 Running 0 3m $ kubectl logs -f prometheus-646f457455-gr8x5 alertmanager -n kube-ops level=info ts=2018-11-28T11:03:16.054633463Z caller=main.go:174 msg="Starting Alertmanager" version="(version=0.15.3, branch=HEAD, revision=d4a7697cc90f8bce62efe7c44b63b542578ec0a1)" level=info ts=2018-11-28T11:03:16.054931931Z caller=main.go:175 build_context="(go=go1.11.2, user=root@4ecc17c53d26, date=20181109-15:40:48)" level=info ts=2018-11-28T11:03:16.351058702Z caller=cluster.go:155 component=cluster msg="setting advertise address explicitly" addr=10.244.2.217 port=9094 level=info ts=2018-11-28T11:03:16.456683857Z caller=main.go:322 msg="Loading configuration file" file=/etc/alertmanager/config.yml level=info ts=2018-11-28T11:03:16.548558156Z caller=cluster.go:570 component=cluster msg="Waiting for gossip to settle..." interval=2s level=info ts=2018-11-28T11:03:16.556768564Z caller=main.go:398 msg=Listening address=:9093 level=info ts=2018-11-28T11:03:18.549158865Z caller=cluster.go:595 component=cluster msg="gossip not settled" polls=0 before=0 now=1 elapsed=2.000272112s level=info ts=2018-11-28T11:03:26.558221484Z caller=cluster.go:587 component=cluster msg="gossip settled; proceeding" elapsed=10.009335611s 

報警規則

現在我們只是把 AlertManager 容器運行起來了,也和 Prometheus 進行了關聯,但是現在我們並不知道要做什么報警,因為沒有任何地方告訴我們要報警,所以我們還需要配置一些報警規則來告訴我們對哪些數據進行報警。

警報規則允許你基於 Prometheus 表達式語言的表達式來定義報警報條件,並在觸發警報時發送通知給外部的接收者。

同樣在 Prometheus 的配置文件中添加如下報警規則配置:

rule_files: - /etc/prometheus/rules.yml 

其中rule_files就是用來指定報警規則的,這里我們同樣將rules.yml文件用 ConfigMap 的形式掛載到/etc/prometheus目錄下面即可:

apiVersion: v1 kind: ConfigMap metadata: name: prometheus-config namespace: kube-ops data: prometheus.yml: | ... rules.yml: | groups: - name: test-rule rules: - alert: NodeMemoryUsage expr: (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) / node_memory_MemTotal_bytes * 100 > 20 for: 2m labels: team: node annotations: summary: "{{$labels.instance}}: High Memory usage detected" description: "{{$labels.instance}}: Memory usage is above 20% (current value is: {{ $value }}" 

上面我們定義了一個名為NodeMemoryUsage的報警規則,其中:

  • for語句會使 Prometheus 服務等待指定的時間, 然后執行查詢表達式。
  • labels語句允許指定額外的標簽列表,把它們附加在告警上。
  • annotations語句指定了另一組標簽,它們不被當做告警實例的身份標識,它們經常用於存儲一些額外的信息,用於報警信息的展示之類的。

為了方便演示,我們將的表達式判斷報警臨界值設置為20,重新更新 ConfigMap 資源對象,由於我們在 Prometheus 的 Pod 中已經通過 Volume 的形式將 prometheus-config 這個一個 ConfigMap 對象掛載到了/etc/prometheus目錄下面,所以更新后,該目錄下面也會出現rules.yml文件,所以前面配置的rule_files路徑也是正常的,更新完成后,重新執行reload操作,這個時候我們去 Prometheus 的 Dashboard 中切換到alerts路徑下面就可以看到有報警配置規則的數據了:

prometheus alertsprometheus alerts

我們可以看到頁面中出現了我們剛剛定義的報警規則信息,而且報警信息中還有狀態顯示。一個報警信息在生命周期內有下面3種狀態:

  • inactive: 表示當前報警信息既不是firing狀態也不是pending狀態
  • pending: 表示在設置的閾值時間范圍內被激活了
  • firing: 表示超過設置的閾值時間被激活了

我們這里的狀態現在是firing就表示這個報警已經被激活了,我們這里的報警信息有一個team=node這樣的標簽,而最上面我們配置 alertmanager 的時候就有如下的路由配置信息了:

routes: - receiver: email group_wait: 10s match: team: node 

所以我們這里的報警信息會被email這個接收器來進行報警,我們上面配置的是郵箱,所以正常來說這個時候我們會收到一封如下的報警郵件:

prometheus email receiverprometheus email receiver

我們可以看到收到的郵件內容中包含一個View In AlertManager的鏈接,我們同樣可以通過 NodePort 的形式去訪問到 AlertManager 的 Dashboard 頁面:

$ kubectl get svc -n kube-ops
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S) AGE prometheus NodePort 10.102.74.90 <none> 9093:31788/TCP,9090:30358/TCP 34d 

然后通過<任一Node節點>:31788進行訪問,我們就可以查看到 AlertManager 的 Dashboard 頁面:

alertmanager webuialertmanager webui

在這個頁面中我們可以進行一些操作,比如過濾、分組等等,里面還有兩個新的概念:Inhibition(抑制)和 Silences(靜默)。

  • Inhibition:如果某些其他警報已經觸發了,則對於某些警報,Inhibition 是一個抑制通知的概念。例如:一個警報已經觸發,它正在通知整個集群是不可達的時,Alertmanager 則可以配置成關心這個集群的其他警報無效。這可以防止與實際問題無關的數百或數千個觸發警報的通知,Inhibition 需要通過上面的配置文件進行配置。
  • Silences:靜默是一個非常簡單的方法,可以在給定時間內簡單地忽略所有警報。Silences 基於 matchers配置,類似路由樹。來到的警告將會被檢查,判斷它們是否和活躍的 Silences 相等或者正則表達式匹配。如果匹配成功,則不會將這些警報發送給接收者。

由於全局配置中我們配置的repeat_interval: 5m,所以正常來說,上面的測試報警如果一直滿足報警條件(CPU使用率大於20%)的話,那么每5分鍾我們就可以收到一條報警郵件。

現在我們添加一個 Silences,如下圖所示,匹配 node02 節點的內存報警:

prometheus alertmanager Silencesprometheus alertmanager Silences

添加完成后,等下一次的報警信息觸發后,我們可以看到報警信息里面已經沒有了節點 node02 的報警信息了:

promtheus alertmanager emailpromtheus alertmanager email

由於我們上面添加的 Silences 是有過期時間的,所以在這個時間段過后,node02 的報警信息就會恢復了。

webhook接收器

上面我們配置的是 AlertManager 自帶的郵件報警模板,我們也說了 AlertManager 支持很多中報警接收器,比如 slack、微信之類的,其中最為靈活的方式當然是使用 webhook 了,我們可以定義一個 webhook 來接收報警信息,然后在 webhook 里面去進行處理,需要發送怎樣的報警信息我們自定義就可以。

比如我們這里用 Flask 編寫了一個簡單的處理釘釘報警的 webhook 的程序:

import os import json import requests from flask import Flask from flask import request app = Flask(__name__) @app.route('/', methods=['POST', 'GET']) def send(): if request.method == 'POST': post_data = request.get_data() send_alert(bytes2json(post_data)) return 'success' else: return 'weclome to use prometheus alertmanager dingtalk webhook server!' def bytes2json(data_bytes): data = data_bytes.decode('utf8').replace("'", '"') return json.loads(data) def send_alert(data): token = os.getenv('ROBOT_TOKEN') if not token: print('you must set ROBOT_TOKEN env') return url = 'https://oapi.dingtalk.com/robot/send?access_token=%s' % token send_data = { "msgtype": "text", "text": { "content": data } } req = requests.post(url, json=send_data) result = req.json() if result['errcode'] != 0: print('notify dingtalk error: %s' % result['errcode']) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) 

代碼非常簡單,通過一個 ROBOT_TOKEN 的環境變量傳入群機器人的 TOKEN,然后直接將 webhook 發送過來的數據直接以文本的形式轉發給群機器人。

大家可以根據自己的需求來定制報警數據,上述代碼倉庫地址:github.com/cnych/alertmanager-dingtalk-hook

當然我們得將上面這個服務部署到集群中來,對應的資源清單如下:(dingtalk-hook.yaml)

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: dingtalk-hook namespace: kube-ops spec: template: metadata: labels: app: dingtalk-hook spec: containers: - name: dingtalk-hook image: cnych/alertmanager-dingtalk-hook:v0.2 imagePullPolicy: IfNotPresent ports: - containerPort: 5000 name: http env: - name: ROBOT_TOKEN valueFrom: secretKeyRef: name: dingtalk-secret key: token resources: requests: cpu: 50m memory: 100Mi limits: cpu: 50m memory: 100Mi --- apiVersion: v1 kind: Service metadata: name: dingtalk-hook namespace: kube-ops spec: selector: app: dingtalk-hook ports: - name: hook port: 5000 targetPort: http 

要注意上面我們聲明了一個 ROBOT_TOKEN 的環境變量,由於這是一個相對於私密的信息,所以我們這里從一個 Secret 對象中去獲取,通過如下命令創建一個名為 dingtalk-secret 的 Secret 對象,然后部署上面的資源對象即可:

$ kubectl create secret generic dingtalk-secret --from-literal=token=替換成釘釘群聊的機器人TOKEN -n kube-ops secret "dingtalk-secret" created $ kubectl create -f dingtalk-hook.yaml deployment.extensions "dingtalk-hook" created service "dingtalk-hook" created $ kubectl get pods -n kube-ops NAME READY STATUS RESTARTS AGE dingtalk-hook-c4fcd8cd6-6r2b6 1/1 Running 0 45m ...... 

部署成功后,現在我們就可以給 AlertManager 配置一個 webhook 了,在上面的配置中增加一個路由接收器

  routes: - receiver: webhook match: filesystem: node receivers: - name: 'webhook' webhook_configs: - url: 'http://dingtalk-hook:5000' send_resolved: true 

我們這里配置了一個名為 webhook 的接收器,地址為:http://dingtalk-hook:5000,這個地址當然就是上面我們部署的釘釘的 webhook 的接收程序的 Service 地址。

然后我們也在報警規則中添加一條關於節點文件系統使用情況的報警規則,注意 labels 標簽要帶上filesystem=node,這樣報警信息就會被 webook 這一個接收器所匹配:

- alert: NodeFilesystemUsage expr: (node_filesystem_size_bytes{device="rootfs"} - node_filesystem_free_bytes{device="rootfs"}) / node_filesystem_size_bytes{device="rootfs"} * 100 > 10 for: 2m labels: filesystem: node annotations: summary: "{{$labels.instance}}: High Filesystem usage detected" description: "{{$labels.instance}}: Filesystem usage is above 10% (current value is: {{ $value }}" 

更新 AlertManager 和 Prometheus 的 ConfigMap 資源對象(先刪除再創建),更新完成后,隔一會兒執行 reload 操作是更新生效:

$ kubectl get svc -n kube-ops
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S) AGE prometheus NodePort 10.102.74.90 <none> 9093:31788/TCP,9090:30358/TCP 34d $ curl -X POST "http://10.102.74.90:9093/-/reload" $ curl -X POST "http://10.102.74.90:9090/-/reload" 

AlertManager 和 Prometheus 都可以通過上面的 reload 操作進行重新加載

都完成更新后,再次去 Prometheus 的 Alert 路徑下面查看報警信息:

prometheus alertsprometheus alerts

隔一會兒關於這個節點文件系統的報警就會被觸發了,由於這個報警信息包含一個filesystem=node的 label 標簽,所以會被路由到webhook這個接收器中,也就是上面我們自定義的這個 dingtalk-hook,觸發后可以觀察這個 Pod 的日志:

$ kubectl logs -f dingtalk-hook-cc677c46d-gf26f -n kube-ops
 * Serving Flask app "app" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) 10.244.2.217 - - [28/Nov/2018 17:14:09] "POST / HTTP/1.1" 200 - 

可以看到 POST 請求已經成功了,同時這個時候正常來說就可以收到一條釘釘消息了:

alertmanager dingtalk messagealertmanager dingtalk message

由於我們程序中是用一個非常簡單的文本形式直接轉發的,所以這里報警信息不夠友好,沒關系,有了這個示例我們完全就可以根據自己的需要來定制消息模板了,可以參考釘釘自定義機器人文檔:https://open-doc.dingtalk.com/microapp/serverapi2/qf2nxq

到這里我們就完成了完全手動的控制 Prometheus、Grafana 以及我們的 AlertManager 的報警功能,接下來我們會給大家講解 Kubernetes 中更加自動化的監控方案:Prometheus-Operator。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM