Alertmanager已經在前面Prometheus初體驗(三)已經介紹過了。現在介紹一下在kube-promethues里面怎么修改alertmanager配置文件,以及怎么通過各種媒介發送信息。
一、配置 PrometheusRule(觸發器)
kube-promethues把所有資源監控起來之后,就需要配置告警這一塊了,而告警其實就是配置觸發器。在promethues的Alert界面,已經有了很多觸發器了。

那么,這些報警信息是哪里來的呢?他們應該用怎樣的方式通知我們呢?我們知道之前使用二進制部署的時候,是通過自定義的方式在 Prometheus 的配置文件之中指定 AlertManager 實例和 報警的 rules 文件,現在我們通過 Operator 部署的呢?我們可以在 Prometheus Dashboard 的 Config 頁面下面查看關於 AlertManager 的配置:
global:
scrape_interval: 30s
scrape_timeout: 10s
evaluation_interval: 30s
external_labels:
prometheus: monitoring/k8s
prometheus_replica: prometheus-k8s-0
alerting:
alert_relabel_configs:
- separator: ;
regex: prometheus_replica
replacement: $1
action: labeldrop
alertmanagers:
- kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- monitoring
scheme: http
path_prefix: /
timeout: 10s
api_version: v1
relabel_configs:
- source_labels: [__meta_kubernetes_service_name]
separator: ;
regex: alertmanager-main
replacement: $1
action: keep
- source_labels: [__meta_kubernetes_endpoint_port_name]
separator: ;
regex: web
replacement: $1
action: keep
rule_files:
- /etc/prometheus/rules/prometheus-k8s-rulefiles-0/*.yaml
上面 alertmanagers 實例的配置我們可以看到是通過角色為 endpoints 的 kubernetes 的服務發現機制獲取的,匹配的是服務名為 alertmanager-main,端口名為 web 的 Service 服務,我們查看下 alertmanager-main 這個 Service:
[root@vm10-0-0-12 ~]# kubectl describe svc alertmanager-main -n monitoring
Name: alertmanager-main
Namespace: monitoring
Labels: alertmanager=main
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"alertmanager":"main"},"name":"alertmanager-main","namespace":"...
Selector: alertmanager=main,app=alertmanager
Type: ClusterIP
IP: 10.254.160.2
Port: web 9093/TCP
TargetPort: web/TCP
Endpoints: 10.8.0.21:9093,10.8.1.72:9093,10.8.2.19:9093
Session Affinity: ClientIP
Events: <none>
可以看到服務名正是 alertmanager-main,Port 定義的名稱也是 web,符合上面的規則,所以 Prometheus 和 AlertManager 組件就正確關聯上了。而對應的報警規則文件位於:/etc/prometheus/rules/prometheus-k8s-rulefiles-0/目錄下面所有的 YAML 文件。我們可以進入 Prometheus 的 Pod 中驗證下該目錄下面是否有 YAML 文件:
$ kubectl exec -it prometheus-k8s-0 /bin/sh -n monitoring
Defaulting container name to prometheus.
Use 'kubectl describe pod/prometheus-k8s-0 -n monitoring' to see all of the containers in this pod.
/prometheus $ ls /etc/prometheus/rules/prometheus-k8s-rulefiles-0/
monitoring-prometheus-k8s-rules.yaml
/prometheus $ cat /etc/prometheus/rules/prometheus-k8s-rulefiles-0/monitoring-prometheus-k8s-rules.yaml
groups:
- name: k8s.rules
rules:
- expr: |
sum(rate(container_cpu_usage_seconds_total{job="kubelet", image!="", container_name!=""}[5m])) by (namespace)
record: namespace:container_cpu_usage_seconds_total:sum_rate
......
這個 YAML 文件實際上就是我們之前創建的一個 PrometheusRule 文件包含的:
$ cat prometheus-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
labels:
prometheus: k8s
role: alert-rules
name: prometheus-k8s-rules
namespace: monitoring
spec:
groups:
- name: k8s.rules
rules:
- expr: |
sum(rate(container_cpu_usage_seconds_total{job="kubelet", image!="", container_name!=""}[5m])) by (namespace)
record: namespace:container_cpu_usage_seconds_total:sum_rate
我們這里的 PrometheusRule 的 name 為 prometheus-k8s-rules,namespace 為 monitoring,我們可以猜想到我們創建一個 PrometheusRule 資源對象后,會自動在上面的 prometheus-k8s-rulefiles-0 目錄下面生成一個對應的<namespace>-<name>.yaml文件,所以如果以后我們需要自定義一個報警選項的話,只需要定義一個 PrometheusRule 資源對象即可。
至於為什么 Prometheus 能夠識別這個 PrometheusRule 資源對象呢?這就需要查看我們創建的 prometheus 這個資源對象了,里面有非常重要的一個屬性 ruleSelector,用來匹配 rule 規則的過濾器,要求匹配具有 prometheus=k8s 和 role=alert-rules 標簽的 PrometheusRule 資源對象,現在明白了吧?
cat prometheus-prometheus.yaml
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
labels:
prometheus: k8s
name: k8s
namespace: monitoring
spec:
alerting:
alertmanagers:
- name: alertmanager-main
namespace: monitoring
port: web
baseImage: prom/prometheus
nodeSelector:
beta.kubernetes.io/os: linux
podMonitorSelector: {}
replicas: 2
resources:
requests:
memory: 400Mi
ruleSelector:
matchLabels:
prometheus: k8s
role: alert-rules
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 1000
serviceAccountName: prometheus-k8s
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
version: v2.11.0
所以我們要想自定義一個報警規則,只需要創建一個具有 prometheus=k8s 和 role=alert-rules 標簽的 PrometheusRule 對象就行了,比如現在我們添加一個 etcd 是否可用的報警,我們知道 etcd 整個集群有一半以上的節點可用的話集群就是可用的,所以我們判斷如果不可用的 etcd 數量超過了一半那么就觸發報警,創建文件 prometheus-etcdRules.yaml:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
labels:
prometheus: k8s
role: alert-rules
name: etcd-rules
namespace: monitoring
spec:
groups:
- name: etcd
rules:
- alert: EtcdClusterUnavailable
annotations:
summary: etcd cluster small
description: If one more etcd peer goes down the cluster will be unavailable
expr: |
count(up{job="etcd"} == 0) > (count(up{job="etcd"}) / 2 - 1)
for: 3m
labels:
severity: critical
注意:label 標簽一定至少要有 prometheus=k8s 和 role=alert-rules!
rule文件的頭部都是統一的,只有spec里面不同。
創建完成后,隔一會兒再去容器中查看下 rules 文件夾:
kubectl exec -it prometheus-k8s-0 /bin/sh -n monitoring Defaulting container name to prometheus. Use 'kubectl describe pod/prometheus-k8s-0 -n monitoring' to see all of the containers in this pod. /prometheus $ ls /etc/prometheus/rules/prometheus-k8s-rulefiles-0/ monitoring-etcd-rules.yaml monitoring-prometheus-k8s-rules.yaml
可以看到我們創建的 rule 文件已經被注入到了對應的 rulefiles 文件夾下面了,證明我們上面的設想是正確的。然后再去 Prometheus Dashboard 的 Rules頁面下面就可以查看到上面我們新建的報警規則了:

二、配置promethuesAlert(告警媒介)
觸發器配置完成后,接下來需要在kube-promethues環境里配置告警通知了。promethues支持多種告警方式:釘釘、微信、郵件、webhook。其中webhook最為靈活,可以和自研的第三方平台對接。
告警配置相關可以在alertmanager里面查看:

這些配置信息實際上是來自於我們之前在prometheus-operator/contrib/kube-prometheus/manifests目錄下面創建的 alertmanager-secret.yaml 文件:
apiVersion: v1 data: alertmanager.yaml: Imdsb2JhbCI6IAogICJyZXNvbHZlX3RpbWVvdXQiOiAiNW0iCiJyZWNlaXZlcnMiOiAKLSAibmFtZSI6ICJudWxsIgoicm91dGUiOiAKICAiZ3JvdXBfYnkiOiAKICAtICJqb2IiCiAgImdyb3VwX2ludGVydmFsIjogIjVtIgogICJncm91cF93YWl0IjogIjMwcyIKICAicmVjZWl2ZXIiOiAibnVsbCIKICAicmVwZWF0X2ludGVydmFsIjogIjEyaCIKICAicm91dGVzIjogCiAgLSAibWF0Y2giOiAKICAgICAgImFsZXJ0bmFtZSI6ICJEZWFkTWFuc1N3aXRjaCIKICAgICJyZWNlaXZlciI6ICJudWxsIg== kind: Secret metadata: name: alertmanager-main namespace: monitoring type: Opaque
可以將 alertmanager-secret.yaml 對應的 value 值做一個 base64 解碼:
echo "Imdsb2JhbCI6IAogICJyZXNvbHZlX3RpbWVvdXQiOiAiNW0iCiJyZWNlaXZlcnMiOiAKLSAibmFtZSI6ICJudWxsIgoicm91dGUiOiAKICAiZ3JvdXBfYnkiOiAKICAtICJqb2IiCiAgImdyb3VwX2ludGVydmFsIjogIjVtIgogICJncm91cF93YWl0IjogIjMwcyIKICAicmVjZWl2ZXIiOiAibnVsbCIKICAicmVwZWF0X2ludGVydmFsIjogIjEyaCIKICAicm91dGVzIjogCiAgLSAibWF0Y2giOiAKICAgICAgImFsZXJ0bmFtZSI6ICJEZWFkTWFuc1N3aXRjaCIKICAgICJyZWNlaXZlciI6ICJudWxsIg==" | base64 -d

也就是說,如果我們需要修改告警的主配置文件,只要修改 alertmanager-secret.yaml文件就行了。而 alertmanager-secret.yaml是一個secret,所以修改過程如下:
1、新建一個alertmanager.yaml文件
2、刪除之前的secret文件(alertmanager-main)
3、新建secret文件
cat alertmanager.yaml
global:
resolve_timeout: 5m
wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
wechat_api_secret: '*****'
wechat_api_corp_id: '*******'
smtp_smarthost: 'smtp.163.com:25'
smtp_from: '你的郵箱'
smtp_auth_username: '郵箱用戶名'
smtp_auth_password: '密碼或授權碼'
smtp_require_tls: false
templates: ##消息模板
- '*.tmpl'
route:
group_by: ['alertname','job']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receiver: 'wechat'
routes:
- match:
job: 'prometheus'
receiver: 'wechat'
receivers:
- name: 'email'
email_configs:
- to: '郵件接收人'
- name: 'wechat'
wechat_configs:
- send_resolved: true
to_party: '2'
agent_id: '1'
- name: 'webhook'
webhook_configs:
# - url: 'http://dingtalk-hook:5000'
- url: 'http://webhook-dingtalk.monitoring.svc.cluster.local:8060/dingtalk/webhook1/send'
send_resolved: true
# 先將之前的 secret 對象刪除 $ kubectl delete secret alertmanager-main -n monitoring secret "alertmanager-main" deleted # 創建新的secret對象 $ kubectl create secret generic alertmanager-main --from-file=alertmanager.yaml -n monitoring secret "alertmanager-main" created
注意:這里--from-file可以使用多個,如果你使用多重告警方式的話。
以上過程執行完成后,就可以在alertmanager中看到最新的配置了:

三、配置promethuesAlert(郵件告警)
郵件告警是最簡單的,只需要直接在alertmanager的config里面配置就行。
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.163.com:25'
smtp_from: 'xuequn_2008@163.com'
smtp_auth_username: 'xuequn_2008@163.com'
smtp_auth_password: 'password'
smtp_require_tls: false
templates: ##消息模板
- '*.tmpl'
route:
group_by: ['alertname','job']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receiver: 'wechat'
routes:
- match:
job: 'prometheus'
receiver: 'wechat'
receivers:
- name: 'email'
email_configs:
- to: 'xuequn_2008@163.com'
以上是一個簡單的配置,完成后,將repeat-interval設置小一點,比如1m。去郵箱查看對應的告警就行了。


四、配置promethuesAlert(釘釘告警)
1、注冊釘釘賬號->機器人管理

2、自定義(通過webhook接入自定義服務)

3、添加->復制webhook

重點在webhook,復制webhook的url鏈接。
4、編寫yaml
在/data/k8s-install/prometheus/alertmanager目錄下,新建dingtalk-webhook.yaml
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
run: dingtalk
name: webhook-dingtalk
namespace: monitoring
spec:
replicas: 1
template:
metadata:
labels:
run: dingtalk
spec:
containers:
- name: dingtalk
image: timonwong/prometheus-webhook-dingtalk:v0.3.0
imagePullPolicy: IfNotPresent
# 設置釘釘群聊自定義機器人后,使用實際 access_token 替換下面 xxxxxx部分
args:
- --ding.profile=webhook1=https://oapi.dingtalk.com/robot/send?access_token=你的token
ports:
- containerPort: 8060
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
labels:
run: dingtalk
name: webhook-dingtalk
namespace: monitoring
spec:
ports:
- port: 8060
protocol: TCP
targetPort: 8060
selector:
run: dingtalk
sessionAffinity: None
填上上面復制的webhook鏈接地址。
5、應用配置
kubectl apply -f dingtalk-webhook.yaml
應用配置后,對應的pod和service就起來了,我們可以看到偵聽的端口為8060.
6、alertmanager配置告警通知
global:
resolve_timeout: 5m
templates: ##消息模板
- '*.tmpl'
route:
group_by: ['alertname','job']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receiver: 'webhook'
receivers:
#配置郵件告警
- name: 'email'
email_configs:
- to: 'xuequn_2008@163.com'
#配置釘釘告警的webhook
- name: 'webhook'
webhook_configs:
- url: 'http://webhook-dingtalk.monitoring.svc.cluster.local:8060/dingtalk/webhook1/send'
send_resolved: true
7、更新告警文件
# 先將之前的 secret 對象刪除 $ kubectl delete secret alertmanager-main -n monitoring secret "alertmanager-main" deleted # 創建新的secret對象 $ kubectl create secret generic alertmanager-main --from-file=alertmanager.yaml -n monitoring secret "alertmanager-main" created
8、測試告警
一般情況下,沒有問題的話,你就可以接收到釘釘告警拉。

五、配置promethuesAlert(微信告警)
由於wechat的強大,所以alertmanager官方直接支持wechat告警,直接配置即可。
1、注冊企業微信
找到以下幾個東西:
wechat_api_secret 應用ID
wechat_api_corp_id 企業ID
to_party 中心(部門的上級)
agent_id 部門ID
2、配置alertmanager
global:
resolve_timeout: 5m
wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
wechat_api_secret: '應用ID'
wechat_api_corp_id: '企業ID'
templates: ##消息模板
- '*.tmpl'
route:
group_by: ['alertname','job']
group_wait: 10s
group_interval: 10s
repeat_interval: 1m
receiver: 'wechat'
receivers:
- name: 'wechat'
wechat_configs:
- send_resolved: true
to_party: '2' #中心ID
agent_id: '1' #部門ID
按照以上方式配置完成后,直接測試即可,一般沒有問題的情況下,你會收到如下形式的告警:

六、配置promethuesAlert(自研平台)
自研平台,就是自己開發的平台。其實也是通過webhook方式和第三方對接。前提是:自研平台有對應的API接口接受告警。
比如,我們自己開發的接口如下:
curl -X POST "http://www.baibai.com/eventhub/api/v1/failure_events/" \
-H "Content-Type:application/json" \
-H "Authorization:Token 7HNSNBqqRf6EHCBaCgDdMPYHCq9VK6RE" \
-d @- << EOF
{
"name": "告警事件名",
"description":"事件描述",
"project_name": "告警項目",
"failure_type":"程序故障-通用應用程序故障-通用應用程序BUG"
}
EOF
上面對接的是一個事件系統,有一個POST接口,可以直接接受事件告警。
因為我們希望webhook同樣運行在k8s環境里,方便維護和開發,所以,我們先要制作一個對應webhook的鏡像文件。
1、制作鏡像
編寫app
import os
import json
import requests
import datetime
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()
post_data = eval(str(post_data, encoding = "utf-8"))
event_status = post_data.get('alerts')[0].get('status','')
event_job = post_data.get('alerts')[0].get('labels','').get('job','')
event_type = post_data.get('alerts')[0].get('labels','').get('alertname','')
event_desc = post_data.get('alerts')[0].get('annotations','').get('message','')
event_level = post_data.get('alerts')[0].get('labels','').get('severity','')
event_time = post_data.get('alerts')[0].get('startsAt')[0:-11]
new_data = {
"alert_status": event_status,
"alert_instance": event_job,
"alert_type": event_type,
"alert_desc": event_desc,
"alert_severity": event_level,
"alert_time": event_time
}
send_alert(new_data)
return 'success'
else:
return 'weclome to use prometheus alertmanager events-hub webhook server!'
class ComplexEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime.datetime):
return obj.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(obj, bytes):
return str(obj, encoding='utf-8')
else:
return json.JSONEncoder.default(self, obj)
def send_alert(data):
url = "http://www.baibai/eventhub/api/v1/failure_events/"
headers = {
"Content-Type": "application/json",
"Authorization": "Token 7HNSNBqqRf6EHCBaCgDdMPYHCq9VK6RE"
}
send_data = {
"name": data.get('alert_desc',''),
"description": data,
"project_name": "維護支持部",
"failure_type": "程序故障-通用應用程序故障-通用應用程序BUG"
}
req = requests.post(url, data=json.dumps(send_data,cls=ComplexEncoder),headers=headers)
print(req.text)
result = req.json()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
2、編寫Dockerfile
cat Dockerfile
FROM python:3.6.4 # set working directory WORKDIR /src # add app ADD . /src # install requirements RUN pip install -r requirements.txt # run server CMD python app.py
cat requirements.txt
certifi==2018.10.15 chardet==3.0.4 Click==7.0 Flask==1.0.2 idna==2.7 itsdangerous==1.1.0 Jinja2==2.10 MarkupSafe==1.1.0 requests==2.20.1 urllib3==1.24.1 Werkzeug==0.14.1
上面其實就是寫了一個簡單的flask app,通過POST方法,向第三方系統的API提交數據。
3、構建鏡像
docker build -t loveliuli/events-hub:v0.1 .
4、上傳鏡像到Dockerhub
當然,這里的前提是你得先在Dockerhub上注冊了賬號,並且在本地使用docker login登錄。
docker push loveliuli/events-hub:v0.1

這樣就方便在任何地方都可以進行使用這個鏡像了。
5、alertmanager編寫yaml
cat dingtalk-webhook-flask.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: dingtalk-hook
namespace: monitoring
spec:
template:
metadata:
labels:
app: dingtalk-hook
spec:
containers:
- name: dingtalk-hook
image: loveliuli/events-hub:v0.30
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
name: http
resources:
requests:
cpu: 50m
memory: 100Mi
limits:
cpu: 50m
memory: 100Mi
---
apiVersion: v1
kind: Service
metadata:
name: dingtalk-hook
namespace: monitoring
spec:
type: NodePort
selector:
app: dingtalk-hook
ports:
- name: hook
port: 5000
targetPort: http
以上name命名可能有點誤導,其實和釘釘毫無關系。
6、應用配置
kubectl apply -f dingtalk-webhook-flask.yaml
應用配置后,我們即可查看啟動情況:

7、配置alertmanager
global:
resolve_timeout: 5m
templates: ##消息模板
- '*.tmpl'
route:
group_by: ['alertname','job']
group_wait: 10s
group_interval: 10s
repeat_interval: 1m
receiver: 'webhook'
receivers:
- name: 'webhook'
webhook_configs:
- url: 'http://dingtalk-hook:5000'
send_resolved: true
8、更新告警文件
# 先將之前的 secret 對象刪除 $ kubectl delete secret alertmanager-main -n monitoring secret "alertmanager-main" deleted # 創建新的secret對象 $ kubectl create secret generic alertmanager-main --from-file=alertmanager.yaml -n monitoring secret "alertmanager-main" created
注意:我們每次更新alertmanager的配置文件,都必須更新告警文件,才能生成最新的配置。
9、測試告警
不出意外的話,你將會看到如下log信息,那就表示成功了。

第三方系統接收信息:

通過第三方系統和自己企業的短信、內部系統對接,就非常簡單了!
