Kubernetes容器集群管理環境 - Prometheus監控篇


一、Prometheus介紹
之前已經詳細介紹了Kubernetes集群部署篇,今天這里重點說下Kubernetes監控方案-Prometheus+Grafana。Prometheus(普羅米修斯)是一個開源系統監控和警報工具,最初是在SoundCloud建立的。自2012年成立以來,許多公司和組織都采用了普羅米修斯,該項目擁有一個非常活躍的開發者和用戶社區。它現在是一個獨立的開放源碼項目,並且獨立於任何公司,為了強調該點並澄清項目的治理結構,Prometheus在2016年加入了雲計算基金會,成為繼Kubernetes之后的第二個托管項目。 Prometheus是用來收集數據的,同時本身也提供強大的查詢能力,結合Grafana即可以監控並展示出想要的數據。

Prometheus的主要特征
- 多維度數據模型
- 靈活的查詢語言 (PromQL)
- 不依賴分布式存儲,單個服務器節點是自主的
- 以HTTP方式,通過pull模型拉去時間序列數據
- 也通過中間網關支持push模型
- 通過服務發現或者靜態配置,來發現目標服務對象
- 支持多種多樣的圖表和界面展示,grafana也支持它

Prometheus組件
Prometheus生態包括了很多組件,它們中的一些是可選的:
- 主服務Prometheus Server負責抓取和存儲時間序列數據
- 客戶庫負責檢測應用程序代碼
- 支持短生命周期的PUSH網關
- 基於Rails/SQL儀表盤構建器的GUI
- 多種導出工具,可以支持Prometheus存儲數據轉化為HAProxy、StatsD、Graphite等工具所需要的數據存儲格式
- 警告管理器 (AlertManaager)
- 命令行查詢工具
- 其他各種支撐工具

Prometheus監控Kubernetes集群過程中,通常情況為:
- 使用metric-server收集數據給k8s集群內使用,如kubectl,hpa,scheduler等
- 使用prometheus-operator部署prometheus,存儲監控數據
- 使用kube-state-metrics收集k8s集群內資源對象數據
- 使用node_exporter收集集群中各節點的數據
- 使用prometheus收集apiserver,scheduler,controller-manager,kubelet組件數據
- 使用alertmanager實現監控報警
- 使用grafana實現數據可視化

Prometheus架構
下面這張圖說明了Prometheus的整體架構,以及生態中的一些組件作用

Prometheus整體流程比較簡單,Prometheus 直接接收或者通過中間的 Pushgateway 網關被動獲取指標數據,在本地存儲所有的獲取的指標數據,並對這些數據進行一些規則整理,用來生成一些聚合數據或者報警信息,Grafana 或者其他工具用來可視化這些數據。

Prometheus服務可以直接通過目標拉取數據,或者間接地通過中間網關拉取數據。它在本地存儲抓取的所有數據,並通過一定規則進行清理和整理數據,並把得到的結果存儲到新的時間序列中,PromQL和其他API可視化展示收集的數據在K8s中,關於集群的資源有metrics度量值的概念,有各種不同的exporter可以通過api接口對外提供各種度量值的及時數據,prometheus在與k8s融合工作的過程中就是通過與這些提供metric值的exporter進行交互,獲取數據,整合數據,展示數據,觸發告警的過程。

1)Prometheus獲取metrics
- 對短暫生命周期的任務,采取拉的形式獲取metrics (不常見)
- 對於exporter提供的metrics,采取拉的方式獲取metrics(通常方式),對接的exporter常見的有:kube-apiserver 、cadvisor、node-exporter,也可根據應用類型部署相應的exporter,獲取該應用的狀態信息,目前支持的應用有:nginx/haproxy/mysql/redis/memcache等。

2)Prometheus數據匯總及按需獲取
可以按照官方定義的expr表達式格式,以及PromQL語法對相應的指標進程過濾,數據展示及圖形展示。不過自帶的webui較為簡陋,但prometheus同時提供獲取數據的api,grafana可通過api獲取prometheus數據源,來繪制更精細的圖形效果用以展示。
expr書寫格式及語法參考官方文檔:https://prometheus.io/docs/prometheus/latest/querying/basics/

3)Prometheus告警推送
prometheus支持多種告警媒介,對滿足條件的告警自動觸發告警,並可對告警的發送規則進行定制,例如重復間隔、路由等,可以實現非常靈活的告警觸發。

Prometheus適用場景
Prometheus在記錄純數字時間序列方面表現非常好。它既適用於面向服務器等硬件指標的監控,也適用於高動態的面向服務架構的監控。對於現在流行的微服務,Prometheus的多維度數據收集和數據篩選查詢語言也是非常的強大。Prometheus是為服務的可靠性而設計的,當服務出現故障時,它可以使你快速定位和診斷問題。它的搭建過程對硬件和服務沒有很強的依賴關系。

Prometheus不適用場景
Prometheus,它的價值在於可靠性,甚至在很惡劣的環境下,你都可以隨時訪問它和查看系統服務各種指標的統計信息。 如果你對統計數據需要100%的精確,它並不適用,例如:它不適用於實時計費系統

二、Prometheus+Grafana部署
依據之前部署好的Kubernetes容器集群管理環境為基礎,繼續部署Prometheus+Grafana。如果不部署metrics-service的話,則要部署kube-state-metrics,它專門監控的是k8s資源對象,如pod,deployment,daemonset等,並且它會被Prometheus以endpoint方式自動識別出來。記錄如下: (k8s-prometheus-grafana.git打包后下載地址:https://pan.baidu.com/s/1nb-QCOc7lgmyJaWwPRBjPg  提取密碼: bh2e)

由於Zabbix不適用於容器環境下的指標采集和監控告警,為此使用了與K8s原生的監控工具Prometheus;Prometheus可方便地識別K8s中相關指標,並以極高的效率和便捷的配置實現了指標采集和監控告警。具體工作:
1)在K8s集群中部署Prometheus,以K8s本身的特性實現了Prometheus的高可用;
2)優化Prometheus配置,實現了配置信息的熱加載,在更新配置時無需重啟進程;
3)配置了Prometheus抓取規則,以實現對apiserver/etcd/controller-manager/scheduler/kubelet/kube-proxy以及K8s集群內運行中容器的信息采集;
4)配置了Prometheus及告警規則,以實現對采集到的信息進行計算和告警;

1.  Prometheus和Grafana部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
1)在k8s-master01節點上進行安裝部署。安裝git,並下載相關yaml文件
[root@k8s-master01 ~] # cd /opt/k8s/work/
[root@k8s-master01 work] # git clone https://github.com/redhatxl/k8s-prometheus-grafana.git
    
2)在所有的node節點下載監控所需鏡像
[root@k8s-master01 work] # source /opt/k8s/bin/environment.sh
[root@k8s-master01 work] # for node_node_ip in ${NODE_NODE_IPS[@]}
   do
     echo  ">>> ${node_node_ip}"
     ssh  root@${node_node_ip}  "docker pull prom/node-exporter"
   done
    
[root@k8s-master01 work] # for node_node_ip in ${NODE_NODE_IPS[@]}
   do
     echo  ">>> ${node_node_ip}"
     ssh  root@${node_node_ip}  "docker pull prom/prometheus:v2.0.0"
   done
    
[root@k8s-master01 work] # for node_node_ip in ${NODE_NODE_IPS[@]}
   do
     echo  ">>> ${node_node_ip}"
     ssh  root@${node_node_ip}  "docker pull grafana/grafana:4.2.0"
   done
    
3)采用daemonset方式部署node-exporter組件
[root@k8s-master01 work] # cd k8s-prometheus-grafana/
[root@k8s-master01 k8s-prometheus-grafana] # ls
grafana  node-exporter.yaml  prometheus  README.md
  
這里需要修改下默認的node-exporter.yaml文件內存,修改后的node-exporter.yaml內容如下:
[root@k8s-master01 k8s-prometheus-grafana] # cat node-exporter.yaml
---
apiVersion: extensions /v1beta1
kind: DaemonSet
metadata:
   name: node-exporter
   namespace: kube-system
   labels:
     k8s-app: node-exporter
spec:
   template:
     metadata:
       labels:
         k8s-app: node-exporter
     spec:
       containers:
       - image: prom /node-exporter
         name: node-exporter
         ports:
         - containerPort: 9100
           protocol: TCP
           name: http
       tolerations:
       hostNetwork:  true
       hostPID:  true
       hostIPC:  true
       restartPolicy: Always
  
---
apiVersion: v1
kind: Service
metadata:
   annotations:
     prometheus.io /scrape 'true'
     prometheus.io /app-metrics 'true'
     prometheus.io /app-metrics-path '/metrics'
   labels:
     k8s-app: node-exporter
   name: node-exporter
   namespace: kube-system
spec:
   ports:
   - name: http
     port: 9100
     nodePort: 31672
     protocol: TCP
   type : NodePort
   selector:
     k8s-app: node-exporter
  
[root@k8s-master01 k8s-prometheus-grafana] # kubectl create -f  node-exporter.yaml
    
稍等一會兒,查看node-exporter部署是否成功了
[root@k8s-master01 k8s-prometheus-grafana] # kubectl get pods -n kube-system|grep "node-exporter*"
node-exporter-9h2z6                     1 /1      Running   0          117s
node-exporter-sk4g4                     1 /1      Running   0          117s
node-exporter-stlwb                     1 /1      Running   0          117s
    
4)部署prometheus組件
[root@k8s-master01 k8s-prometheus-grafana] # cd prometheus/
    
4.1)部署rbac文件
[root@k8s-master01 prometheus] # kubectl create -f rbac-setup.yaml
    
4.2)以configmap的形式管理prometheus組件的配置文件
[root@k8s-master01 prometheus] # kubectl create -f configmap.yaml
    
4.3)Prometheus deployment 文件
[root@k8s-master01 prometheus] # kubectl create -f prometheus.deploy.yaml
    
4.4)Prometheus service文件
[root@k8s-master01 prometheus] # kubectl create -f prometheus.svc.yaml
    
5)部署grafana組件
[root@k8s-master01 prometheus] # cd ../grafana/
[root@k8s-master01 grafana] # ll
total 12
-rw-r--r-- 1 root root 1449 Jul  8 17:19 grafana-deploy.yaml
-rw-r--r-- 1 root root  256 Jul  8 17:19 grafana-ing.yaml
-rw-r--r-- 1 root root  225 Jul  8 17:19 grafana-svc.yaml
    
5.1)grafana deployment配置文件
[root@k8s-master01 grafana] # kubectl create -f grafana-deploy.yaml
    
5.2)grafana service配置文件
[root@k8s-master01 grafana] # kubectl create -f grafana-svc.yaml
    
5.3)grafana ingress配置文件
[root@k8s-master01 grafana] # kubectl create -f grafana-ing.yaml
    
6)web訪問界面配置
[root@k8s-master01 k8s-prometheus-grafana] # kubectl get pods -n kube-system
NAME                                    READY   STATUS    RESTARTS   AGE
coredns-5b969f4c88-pd5js                1 /1      Running   0          30d
grafana-core-5f7c6c786b-x8prc           1 /1      Running   0          17d
kube-state-metrics-5dd55c764d-nnsdv     2 /2      Running   0          23d
kubernetes-dashboard-7976c5cb9c-4jpzb   1 /1      Running   0          16d
metrics-server-54997795d9-rczmc         1 /1      Running   0          24d
node-exporter-9h2z6                     1 /1      Running   0          74s
node-exporter-sk4g4                     1 /1      Running   0          74s
node-exporter-stlwb                     1 /1      Running   0          74s
prometheus-8697656888-2vwbw             1 /1      Running   0          10d
    
[root@k8s-master01 k8s-prometheus-grafana] # kubectl get svc -n kube-system
NAME                            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
grafana                         NodePort    10.254.95.120    <none>        3000:31821 /TCP                   17d
kube-dns                        ClusterIP   10.254.0.2       <none>        53 /UDP ,53 /TCP ,9153 /TCP           30d
kube-state-metrics              NodePort    10.254.228.212   <none>        8080:30978 /TCP ,8081:30872 /TCP    23d
kubernetes-dashboard-external   NodePort    10.254.223.104   <none>        9090:30090 /TCP                   16d
metrics-server                  ClusterIP   10.254.135.197   <none>        443 /TCP                          24d
node-exporter                   NodePort    10.254.72.22     <none>        9100:31672 /TCP                   2m11s
prometheus                      NodePort    10.254.241.170   <none>        9090:30003 /TCP                   10d
    
7)查看node-exporter (http: //node-ip :31672/)
http: //172 .16.60.244:31672/
http: //172 .16.60.245:31672/
http: //172 .16.60.246:31672/
   
8)prometheus對應的nodeport端口為30003,通過訪問http: //node-ip :30003 /targets  可以看到prometheus已經成功連接上了k8s的apiserver
http: //172 .16.60.244:30003 /targets
http: //172 .16.60.245:30003 /targets
http: //172 .16.60.246:30003 /targets

2.  Prometheus配置K8s組件監控項
如上部署prometheus之后,默認的監控項是kubernetes-apiservers、kubernetes-nodes、kubernetes-service-endpoints(CoreDNS、kube-state-metric)等,這是都是在prometheus/configmap.yaml文件中配置的,而像其他組件kubernetes-schedule、kubernetes-control-manager、kubernetes-kubelet、kubernetes-kube-proxy、etcd就需要手動添加了,如下: 就需要手動添加了,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
1)在prometheus里手動添加kubernetes-schedule、kubernetes-control-manager、kubernetes-kubelet、kubernetes-kube-proxy組件的連接配置,非證書連接!
以下組件的配置,還不需要使用證書連接,直接ip+port就可以,默認路徑就是 /metrics
確保以下四個組件的metrcis數據可以通過下面方式正常獲取。
schedule的metrics接口 (Scheduler服務端口默認為10251)
# curl 172.16.60.241:10251/metrics
# curl 172.16.60.242:10251/metrics
# curl 172.16.60.243:10251/metrics
control-manager的metrics接口(ControllerManager服務端口默認為10252)
# curl 172.16.60.241:10252/metrics
# curl 172.16.60.242:10252/metrics
# curl 172.16.60.243:10252/metrics
kubelet的metrics接口 (kubelet服務只讀端口,沒有任何認證(0:disable),默認為10255,該功能只要配置端口,就必定開啟服務)
而10250是kubelet的https端口,10248是healthz http服務端口。
# curl 172.16.60.244:10255/metrics
# curl 172.16.60.245:10255/metrics
# curl 172.16.60.246:10255/metrics
kube-proxy的metrics接口 (kube-proxy服務端口默認為10249)
# curl 172.16.60.244:10249/metrics
# curl 172.16.60.245:10249/metrics
# curl 172.16.60.246:10249/metrics
 
所以prometheus連接以上四個組件的配置為:
[root@k8s-master01 ~] # cd /opt/k8s/work/k8s-prometheus-grafana/prometheus/
[root@k8s-master01 prometheus] # vim configmap.yaml
.........
.........
     - job_name:  'kubernetes-schedule'           #任務名
       scrape_interval: 5s                    #本任務的抓取間隔,覆蓋全局配置
       static_configs:
         - targets: [ '172.16.60.241:10251' , '172.16.60.242:10251' , '172.16.60.243:10251' ]
   
     - job_name:  'kubernetes-control-manager'
       scrape_interval: 5s
       static_configs:
         - targets: [ '172.16.60.241:10252' , '172.16.60.242:10252' , '172.16.60.243:10252' ]
   
     - job_name:  'kubernetes-kubelet'
       scrape_interval: 5s
       static_configs:
         - targets: [ '172.16.60.244:10255' , '172.16.60.245:10255' , '172.16.60.246:10255' ]
   
     - job_name:  'kubernetes-kube-proxy'
       scrape_interval: 5s
       static_configs:
         - targets: [ '172.16.60.244:10249' , '172.16.60.245:10249' , '172.16.60.246:10249' ]
 
接着更新config配置:
[root@k8s-master01 prometheus] # kubectl apply -f configmap.yaml
 
然后重啟pod,重啟的方式是:直接刪除pod
這種方式只是在當前被調度的node節點上刪除了pod,然后schedule再將pod重新調度到其他的node節點上。即刪除pod后,pod會自動被創建~
 
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system|grep "prometheus"
prometheus-6b96dcbd87-lwwv7             1 /1      Running   0          44h
 
[root@k8s-master01 prometheus] # kubectl delete pods/prometheus-6b96dcbd87-lwwv7 -n kube-system
pod  "prometheus-6b96dcbd87-lwwv7"  deleted
 
刪除后,再次查看,發現pod會自動創建,並可能被調度到其他node節點上了。可以理解為pod重啟
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system|grep "prometheus"            
prometheus-6b96dcbd87-c2n59             1 /1      Running   0          22s
 
2)在prometheus里手動添加etcd組件的連接配置,使用證書連接!
在prometheus配置文件configmap.yaml中,可以看出默認對kubernetes-apiservers的連接配置是將證書和token文件映射到了容器內部。
而對接etcd的配置,也是將etcd的證書映射到容器內部,方式如下:
 
首先創建secret,將需要的etcd證書保存到secret對象etcd-certs中:
[root@k8s-master01 prometheus] # kubectl -n kube-system create secret generic etcd-certs --from-file=/etc/etcd/cert/etcd-key.pem
                                 --from- file = /etc/etcd/cert/etcd .pem --from- file = /etc/kubernetes/cert/ca .pem
 
查看創建的secret
[root@k8s-master01 prometheus] # kubectl get secret -n kube-system|grep etcd-certs
etcd-certs                                       Opaque                                3      82s
 
[root@k8s-master01 prometheus] # kubectl describe secret/etcd-certs -n kube-system
Name:         etcd-certs
Namespace:    kube-system
Labels:       <none>
Annotations:  <none>
 
Type:  Opaque
 
Data
====
ca.pem:        1367 bytes
etcd-key.pem:  1675 bytes
etcd.pem:      1444 bytes
 
修改prometheus.deploy.yaml添加secrets,即將創建的secret對象 "etcd-certs" 通過volumes掛載方式,添加到prometheus.deploy.yaml部署文件中:
[root@k8s-master01 prometheus] # cat prometheus.deploy.yaml
........
     spec:
       containers:
       - image: prom /prometheus :v2.0.0
         name: prometheus
         command :
         "/bin/prometheus"
         args:
         "--config.file=/etc/prometheus/prometheus.yml"
         "--storage.tsdb.path=/prometheus"
         "--storage.tsdb.retention=24h"
         ports:
         - containerPort: 9090
           protocol: TCP
         volumeMounts:
         - mountPath:  "/prometheus"
           name: data
         - mountPath:  "/etc/prometheus"
           name: config-volume
         - name: k8s-certs      #添加下面這三行內容,即將secret對象里的內容映射到容器的/var/run/secrets/kubernetes.io/k8s-certs/etcd/目錄下(容器里會自動創建這個目錄)
           mountPath:  /var/run/secrets/kubernetes .io /k8s-certs/etcd/
           readOnly:  true
         resources:
           requests:
             cpu: 100m
             memory: 100Mi
           limits:
             cpu: 500m
             memory: 2500Mi
       serviceAccountName: prometheus   
       volumes:
       - name: data
         emptyDir: {}
       - name: config-volume
         configMap:
           name: prometheus-config  
       - name: k8s-certs             #添加下面這三行內容
         secret:
           secretName: etcd-certs
 
 
修改prometh的configmap.yaml配置文件,添加etcd連接配置 (注意.yaml結尾文件和.yml結尾文件都可以,不影響使用的)
[root@k8s-master01 prometheus] # vim configmap.yaml   
.........
     - job_name:  'kubernetes-etcd'
       scheme: https
       tls_config:
         ca_file:  /var/run/secrets/kubernetes .io /k8s-certs/etcd/ca .pem
         cert_file:  /var/run/secrets/kubernetes .io /k8s-certs/etcd/etcd .pem
         key_file:  /var/run/secrets/kubernetes .io /k8s-certs/etcd/etcd-key .pem
       scrape_interval: 5s
       static_configs:
         - targets: [ '172.16.60.241:2379' , '172.16.60.242:2379' , '172.16.60.243:2379' ]
 
更新config.yaml配置(也可以先delete刪除,再create創建,但是不建議這么操作)
[root@k8s-master01 prometheus] # kubectl apply -f configmap.yaml
 
更新prometheus.deploy.yml配置(也可以先delete刪除,再create創建,但是不建議這么操作)
[root@k8s-master01 prometheus] # kubectl apply -f prometheus.deploy.yaml
 
接着重啟pods。只需要刪除pod,然后就會自動拉起一個pod,即重啟了一次
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system|grep prometheus
prometheus-76fb9bc788-w28pf             1 /1      Running   0          11m
 
[root@k8s-master01 prometheus] # kubectl delete pods/prometheus-76fb9bc788-w28pf -n kube-system
pod  "prometheus-76fb9bc788-w28pf"  deleted
 
查看prometheus的pod,發現pod已重啟
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system|grep prometheus              
prometheus-76fb9bc788-lbf57             1 /1      Running   0          5s
 
========================================================================================
注意:
如果沒有修改configmap.yaml,只是修改的prometheus.deploy.yaml文件
那么只需要執行 "kubectl apply -f prometheus.deploy.yaml"
這樣就自動實現了deploy.yaml文件里的pod的重啟了
========================================================================================
 
查看prometheus的pod容器里是否正確掛載了secret(如下,一定要確保volumes掛載的secret生效了)
[root@k8s-master01 prometheus] # kubectl describe pods/prometheus-76fb9bc788-lbf57 -n kube-system
............
     Mounts:
       /etc/prometheus  from config-volume (rw)
       /prometheus  from data (rw)
       /var/run/secrets/kubernetes .io /k8s-certs/etcd/  from k8s-certs (ro)
       /var/run/secrets/kubernetes .io /serviceaccount  from prometheus-token-mbvhb (ro)
 
登錄prometheus容器查看
[root@k8s-master01 prometheus] # kubectl exec -ti prometheus-76fb9bc788-lbf57 -n kube-system sh
/prometheus  # ls /var/run/secrets/kubernetes.io/k8s-certs/etcd/
ca.pem        etcd-key.pem  etcd.pem
 
到這里,prometheus就已經成功配置了k8s的etcd集群,可以訪問prometheus查看了

3.  Prometheus的報警設置 (AlterManager)
AlertManager用於接收Prometheus發送的告警並對於告警進行一系列的處理后發送給指定的用戶,可以根據不同的需要可以設置郵件告警、短信告警等、釘釘告警(釘釘告警需要接入prometheus-webhook-dingtalk)等。Alertmanager與Prometheus是相互分離的兩個部分。Prometheus服務器根據報警規則將警報發送給Alertmanager,然后Alertmanager將silencing、inhibition、aggregation等消息通過電子郵件、PaperDuty和HipChat發送通知。設置警報和通知的主要步驟:
-  安裝配置Alertmanager;
-  配置Prometheus通過-alertmanager.url標志與Alertmanager通信;
-  在Prometheus中創建告警規則;

Alertmanager機制
Alertmanager處理由類似Prometheus服務器等客戶端發來的警報,之后需要刪除重復、分組,並將它們通過路由發送到正確的接收器,比如電子郵件、Slack等。Alertmanager還支持沉默和警報抑制的機制。

-  分組
分組是指當出現問題時,Alertmanager會收到一個單一的通知,而當系統宕機時,很有可能成百上千的警報會同時生成,這種機制在較大的中斷中特別有用。例如,當數十或數百個服務的實例在運行,網絡發生故障時,有可能服務實例的一半不可達數據庫。在告警規則中配置為每一個服務實例都發送警報的話,那么結果是數百警報被發送至Alertmanager。但是作為用戶只想看到單一的報警頁面,同時仍然能夠清楚的看到哪些實例受到影響,因此,人們通過配置Alertmanager將警報分組打包,並發送一個相對看起來緊湊的通知。分組警報、警報時間,以及接收警報的receiver是在配置文件中通過路由樹配置的。

-  抑制
抑制是指當警報發出后,停止重復發送由此警報引發其他錯誤的警報的機制。例如,當警報被觸發,通知整個集群不可達,可以配置Alertmanager忽略由該警報觸發而產生的所有其他警報,這可以防止通知數百或數千與此問題不相關的其他警報。抑制機制可以通過Alertmanager的配置文件來配置。

-  沉默
沉默是一種簡單的特定時間靜音提醒的機制。一種沉默是通過匹配器來配置,就像路由樹一樣。傳入的警報會匹配RE,如果匹配,將不會為此警報發送通知。沉默機制可以通過Alertmanager的Web頁面進行配置。

Prometheus以scrape_interval(默認為1m)規則周期,從監控目標上收集信息。其中scrape_interval可以基於全局或基於單個metric定義;然后將監控信息持久存儲在其本地存儲上。Prometheus以evaluation_interval(默認為1m)另一個獨立的規則周期,對告警規則做定期計算。其中evaluation_interval只有全局值;然后更新告警狀態。其中包含三種告警狀態:
inactive沒有觸發閾值。即表示當前告警信息既不是firing狀態,也不是pending狀態;
pending已觸發閾值但未滿足告警持續時間。即表示告警消息在設置的閾值時間范圍內被激活了;
firing已觸發閾值且滿足告警持續時間。即表示告警信息在超過設置的閾值時間內被激活了;

如果采用Prometheus Operator方式部署,則prometheus和alertmanager兩個模塊會一起被安裝。這里我先安裝的prometheus容器,然后再安裝的alertmanager容器,這兩個是分開部署的。操作記錄如下 (這里配置實現的時郵件報警):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
[root@k8s-master01 ~] # cd /opt/k8s/work/k8s-prometheus-grafana/prometheus/
   
1)配置alertmanager-conf.yaml
[root@k8s-master01 prometheus] # cat alertmanager-conf.yaml
apiVersion: v1
kind: ConfigMap
metadata:
   name: alert-config
   namespace: kube-system
data:
   config.yml: |-
     global:
       #在沒有告警的情況下聲明為已解決的時間
       resolve_timeout: 5m
       smtp_smarthost:  'smtp.163.com:25'
       smtp_from:  'wangkevin@163.com'
       smtp_auth_username:  'wangkevin@163.com'
       smtp_auth_password:  'kevin123@#$12'
       smtp_hello:  '163.com'
       smtp_require_tls:  false
     #所有告警信息進入之后的根路由,用於設置告警的分發策略
     route:
       #這里的標簽列表是接收到告警信息后的重新分組標簽,例如,在接收到的告警信息里有許多具有 cluster=A 和 alertname=LatncyHigh 標簽的告警信息會被批量聚合到一個分組里
       group_by: [ 'alertname' 'cluster' ]
       #在一個新的告警分組被創建后,需要等待至少 group_wait 時間來初始化通知,這種方式可以確保有足夠的時間為同一分組收獲多條告警,然后一起觸發這條告警信息
       group_wait: 30s
       #在第 1 條告警發送后,等待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:  '102******@qq.com'
         send_resolved:  true
       - to:  'wang*****@sina.cn'
         send_resolved:  true
     - name:  'email'
       email_configs:
       - to:  '87486*****@163.com'
         send_resolved:  true
       - to:  'wang*******@163.com'
         send_resolved:  true
   
上面在alertmanager-conf.yaml文件中配置了郵件告警信息的發送發和接收方,發送發為wang_shibo1987@163.com,接收方為1025337607@qq.com和wangshiboloveni@163.com。
[root@k8s-master01 prometheus] # kubectl create -f alertmanager-conf.yaml
   
2)修改config.yaml文件配置
配置configmap.yaml,添加告警的監控項。如下,添加一個測試告警監控項,當內存使用率超過1%時候,就報警
[root@k8s-master01 prometheus] # vim configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
   name: prometheus-config
   namespace: kube-system
data:
   prometheus.yml: |
     global:
       scrape_interval:     15s
       evaluation_interval: 15s
   
     alerting:                               #添加下面緊接着的這四行
       alertmanagers:
         - static_configs:
           - targets: [ "localhost:9093" ]
   
     rule_files:                            #添加下面緊接着的這兩行
       /etc/prometheus/rules .yml
   
     scrape_configs:
   
     - job_name:  'kubernetes-schedule'      
       scrape_interval: 5s               
       static_configs:
         - targets: [ '172.16.60.241:10251' , '172.16.60.242:10251' , '172.16.60.243:10251' ]
.......
.......
   
   rules.yml: |                   #結尾添加下面這幾行配置
     groups :
     - name: alert-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 > 1
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "{{$labels.instance}}: Memory usage is above 1% (current value is: {{ $value }}%)"
           value:  "{{ $value }}%"
           threshold:  "1%"
   
   
更新config.yaml文件配置
[root@k8s-master01 prometheus] # kubectl apply -f configmap.yaml
   
3)修改prometheus.deploy.yaml文件配置
[root@k8s-master01 prometheus] # vim prometheus.deploy.yml
.......
     spec:
       containers:
       - image: prom /alertmanager :v0.15.3           #添加下面緊接的內容,即alertmanager容器配置
         name: alertmanager
         imagePullPolicy: IfNotPresent
         args:
         "--config.file=/etc/alertmanager/config.yml"
         "--storage.path=/alertmanager/data"
         ports:
         - containerPort: 9093
           name: http
         volumeMounts:
         - mountPath:  "/etc/alertmanager"
           name: alertcfg
         resources:
           requests:
             cpu: 100m
             memory: 256Mi
           limits:
             cpu: 100m
             memory: 256Mi                        #上面添加的配置到這里結束
       - image: prom /prometheus :v2.0.0
         name: prometheus
.......
       volumes:
       - name: alertcfg          #添加下面緊接着這三行配置
         configMap:
           name: alert-config
       - name: data
         emptyDir: {}
.......
   
更新prometheus.deploy.yaml文件配置
[root@k8s-master01 prometheus] # kubectl apply -f prometheus.deploy.yaml
   
重啟pods
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system|grep prometheus           
prometheus-76fb9bc788-lbf57             1 /1      Running   0          5s
   
[root@k8s-master01 prometheus] # kubectl delete pods/prometheus-76fb9bc788-lbf57 -n kube-system
   
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system|grep prometheus            
prometheus-8697656888-2vwbw             2 /2      Running   0          5s
   
4)修改prometheus.svc.yaml文件配置
[root@k8s-master01 prometheus] # vim prometheus.svc.yml
---
kind: Service
apiVersion: v1
metadata:
   labels:
     app: prometheus
   name: prometheus
   namespace: kube-system
spec:
   type : NodePort
   ports:
   - port: 9090
     targetPort: 9090
     nodePort: 30003
     name: prom             #添加下面這緊接的五行內容
   - port: 9093
     targetPort: 9093
     nodePort: 30013
     name: alert
   selector:
     app: prometheus
   
更新prometheus.svc.yml文件
[root@k8s-master01 prometheus] # kubectl apply -f prometheus.svc.yml
  
查看pods
 
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system
NAME                                    READY   STATUS    RESTARTS   AGE
coredns-5b969f4c88-pd5js                1 /1      Running   0          30d
grafana-core-5f7c6c786b-x8prc           1 /1      Running   0          17d
kube-state-metrics-5dd55c764d-nnsdv     2 /2      Running   0          23d
kubernetes-dashboard-7976c5cb9c-4jpzb   1 /1      Running   0          16d
metrics-server-54997795d9-rczmc         1 /1      Running   0          24d
node-exporter-t65bn                     1 /1      Running   0          3m20s
node-exporter-tsdbc                     1 /1      Running   0          3m20s
node-exporter-zmb68                     1 /1      Running   0          3m20s
prometheus-8697656888-7kxwg             2 /2      Running   0          11m    
  
可以看出prometheus-8697656888-7kxwg的pod里面有兩個容器都正常啟動了(2 /2 ),一個是prometheus容器,一個是altermanager容器(prometheus.deploy.yaml文件里配置)
  
登錄容器
[root@k8s-master01 prometheus] # kubectl exec -ti prometheus-8697656888-7kxwg -n kube-system -c prometheus /bin/sh
/prometheus  #
  
[root@k8s-master01 prometheus] # kubectl exec -ti prometheus-8697656888-7kxwg -n kube-system -c alertmanager /bin/sh
/etc/alertmanager  #
 
查看services
[root@k8s-master01 prometheus] # kubectl get svc -n kube-system
NAME                            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
grafana                         NodePort    10.254.95.120    <none>        3000:31821 /TCP                   17d
kube-dns                        ClusterIP   10.254.0.2       <none>        53 /UDP ,53 /TCP ,9153 /TCP           30d
kube-state-metrics              NodePort    10.254.228.212   <none>        8080:30978 /TCP ,8081:30872 /TCP    23d
kubernetes-dashboard-external   NodePort    10.254.223.104   <none>        9090:30090 /TCP                   16d
metrics-server                  ClusterIP   10.254.135.197   <none>        443 /TCP                          24d
node-exporter                   NodePort    10.254.168.172   <none>        9100:31672 /TCP                   11m
prometheus                      NodePort    10.254.241.170   <none>        9090:30003 /TCP ,9093:30013 /TCP    10d
 
這時候,訪問http: //172 .16.60.245:30003 /alerts 就能看到Prometheus的告警設置了。

雙擊上面的Alerts

收到的郵件告警信息如下:

訪問30013端口,可以看到Alertmanager的Silences靜默狀態等

4. Prometheus針對K8s容器集群的監控指標告警設置
指標數據以及后面grafana里監控項的值都可以直接在prometheus的"graph"的查詢欄里直接查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
修改configmap.yaml文件
[root@k8s-master01 prometheus] # pwd
/opt/k8s/work/k8s-prometheus-grafana/prometheus
[root@k8s-master01 prometheus] # cp configmap.yaml configmap.yaml.bak
[root@k8s-master01 prometheus] # vim configmap.yaml
............
............
   rules.yml: |
     groups :
     - name: alert-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 > 85
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "{{$labels.instance}}: Memory usage is above 1% (current value is: {{ $value }}%)"
           value:  "{{ $value }}%"
           threshold:  "85%"
       - alert: InstanceDown
         expr : up == 0
         for : 1m
         labels:
           team: admin
         annotations:   
           description:  "{{$labels.job}}({{$labels.instance}})采集任務down"
           value:  "{{ $value }}"
           threshold:  "1"    
       - alert: KubeCpuUsage
         expr : rate(process_cpu_seconds_total{job=~ "kubernetes-kube-proxy|kubernetes-kubelet|kubernetes-schedule|kubernetes-control-manager|kubernetes-apiservers|kubernetes-etcd" }[1m]) * 100 > 95
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "組件{{$labels.job}}({{$labels.instance}}): Cpu使用率超過95%"
           value:  "{{ $value }}%"
           threshold:  "95%"
       - alert: AddonCpuUsage
         expr : rate(process_cpu_seconds_total{k8s_app=~ "kube-state-metrics|kube-dns" }[1m]) * 100 > 95
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "插件{{$labels.k8s_app}}({{$labels.instance}}): Cpu使用率超過95%"
           value:  "{{ $value }}%"
           threshold:  "95%"     
       - alert: KubeOpenFds
         expr : process_open_fds{job=~ "kubernetes-kube-proxy|kubernetes-kubelet|kubernetes-schedule|kubernetes-control-manager|kubernetes-apiservers|kubernetes-etcd" }  > 1024
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "組件{{$labels.job}}({{$labels.instance}}): 打開句柄數超過1024"
           value:  "{{ $value }}"
           threshold:  "1024"      
       - alert: AddonOpenFds
         expr : process_open_fds{k8s_app=~ "kube-state-metrics|kube-dns" }  > 1024
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "插件{{$labels.k8s_app}}({{$labels.instance}}): 打開句柄數超過1024"
           value:  "{{ $value }}"
           threshold:  "1024"            
       - alert: KubeVirtualMemory
         expr : process_virtual_memory_bytes{job=~ "kubernetes-kube-proxy|kubernetes-kubelet|kubernetes-schedule|kubernetes-control-manager|kubernetes-apiservers|kubernetes-etcd" }  > 2000000000
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "組件{{$labels.job}}({{$labels.instance}}): 使用虛擬內存超過2G"
           value:  "{{ $value }}"
           threshold:  "2G"      
       - alert: AddonKubeVirtualMemory
         expr : process_virtual_memory_bytes{k8s_app=~ "kube-state-metrics|kube-dns" }  > 2000000000
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "插件{{$labels.k8s_app}}({{$labels.instance}}): 使用虛擬內存超過2G"
           value:  "{{ $value }}"
           threshold:  "2G"
       - alert: HttpRequestsAvg
         expr sum (rate(rest_client_requests_total{job=~ "kubernetes-kube-proxy|kubernetes-kubelet|kubernetes-schedule|kubernetes-control-manager|kubernetes-apiservers" }[1m]))  > 1000
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "組件{{$labels.job}}({{$labels.instance}}): TPS超過1000"
           value:  "{{ $value }}"
           threshold:  "1000"    
       - alert: KubeletDockerOperationsErrors
         expr : rate(kubelet_docker_operations_errors{job= "kubernetes-kubelet" }[1m])  != 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "Kublet組件({{$labels.instance}})有{{$labels.operation_type}}操作錯誤"
           value:  "{{ $value }}"
           threshold:  "0"       
       - alert: KubeletNodeConfigError
         expr : kubelet_node_config_error{job= "kubernetes-kubelet" }  != 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "Kublet組件({{$labels.instance}})節點配置有誤"
           value:  "{{ $value }}"
           threshold:  "0"         
       - alert: DaemonSet_misscheduled
         expr : kube_daemonset_status_number_misscheduled{namespace=~ "kube-system|cattle-system" } > 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "空間{{$labels.namespace}}({{$labels.instance}}): 發現{{$labels.daemonset}}調度失敗"
           value:  "{{ $value }}"
           threshold:  "0"
       - alert: DaemonSet_unavailable
         expr : kube_daemonset_status_number_unavailable{namespace=~ "kube-system|cattle-system" } > 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "空間{{$labels.namespace}}({{$labels.instance}}): 發現{{$labels.daemonset}}不可用"
           value:  "{{ $value }}"
           threshold:  "0"
       - alert: Deployment_unavailable
         expr : kube_deployment_status_replicas_unavailable{namespace=~ "kube-system|cattle-system" } > 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "空間{{$labels.namespace}}({{$labels.instance}}): 發現{{$labels.deployment}}不可用"
           value:  "{{ $value }}"
           threshold:  "0"
       - alert: Deployment_unavailable_DOTA
         expr : kube_deployment_status_replicas_unavailable{deployment=~ "aimaster-nginx.*" ,namespace= "dev" } > 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "空間{{$labels.namespace}}({{$labels.instance}}): 發現{{$labels.deployment}}不可用"
           value:  "{{ $value }}"
           threshold:  "0"
           system:  "DOTA"
       - alert: Pod_waiting
         expr : kube_pod_container_status_waiting_reason{namespace=~ "kube-system|cattle-system" } == 1
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "空間{{$labels.namespace}}({{$labels.instance}}): 發現{{$labels.pod}}下的{{$labels.container}}啟動異常等待中"
           value:  "{{ $value }}"
           threshold:  "1"
       - alert: Pod_terminated
         expr : kube_pod_container_status_terminated_reason{namespace=~ "kube-system|cattle-system" } == 1
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "空間{{$labels.namespace}}({{$labels.instance}}): 發現{{$labels.pod}}下的{{$labels.container}}被刪除"
           value:  "{{ $value }}"
           threshold:  "1"
       - alert: Pod_restarts
         expr : kube_pod_container_status_restarts_total{namespace=~ "kube-system|cattle-system" } > 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "空間{{$labels.namespace}}({{$labels.instance}}): 發現{{$labels.pod}}下的{{$labels.container}}被重啟"
           value:  "{{ $value }}"
           threshold:  "0"
       - alert: Etcd_leader
         expr : etcd_server_has_leader{job= "kubernetes-etcd" } == 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "組件{{$labels.job}}({{$labels.instance}}): 當前沒有leader"
           value:  "{{ $value }}"
           threshold:  "0"
       - alert: Etcd_leader_changes
         expr : rate(etcd_server_leader_changes_seen_total{job= "kubernetes-etcd" }[1m]) > 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "組件{{$labels.job}}({{$labels.instance}}): 當前leader已發生改變"
           value:  "{{ $value }}"
           threshold:  "0"
       - alert: Etcd_failed
         expr : rate(etcd_server_proposals_failed_total{job= "kubernetes-etcd" }[1m]) > 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "組件{{$labels.job}}({{$labels.instance}}): 服務失敗"
           value:  "{{ $value }}"
           threshold:  "0"
       - alert: Etcd_db_total_size
         expr : etcd_debugging_mvcc_db_total_size_in_bytes{job= "kubernetes-etcd" } > 10000000000
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "組件{{$labels.job}}({{$labels.instance}}):db空間超過10G"
           value:  "{{ $value }}"
           threshold:  "10G"
       - alert: Endpoint_ready
         expr : kube_endpoint_address_not_ready{namespace=~ "kube-system|cattle-system" } == 1
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "空間{{$labels.namespace}}({{$labels.instance}}): 發現{{$labels.endpoint}}不可用"
           value:  "{{ $value }}"
           threshold:  "1"
       - alert: ReplicaSet_ready
         expr : (kube_replicaset_status_ready_replicas - kube_replicaset_status_replicas) != 0
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "{{$labels.instance}}: 發現空間{{$labels.namespace}}下的{{$labels.replicaset>}}不可用"
           value:  "{{ $value }}"
           threshold:  "0"
 
然后是config.yaml配置生效 (config更新后,必須要重啟pod才能生效)
[root@k8s-master01 prometheus] # kubectl delete -f configmap.yaml
configmap  "prometheus-config"  deleted
 
[root@k8s-master01 prometheus] # kubectl create -f configmap.yaml 
configmap /prometheus-config  created
 
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system|grep prometheus
prometheus-858989bcfb-v7dfl             2 /2      Running   0          10m
 
[root@k8s-master01 prometheus] # kubectl delete pods/prometheus-858989bcfb-v7dfl -n kube-system
pod  "prometheus-858989bcfb-v7dfl"  deleted
 
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system|grep prometheus              
prometheus-858989bcfb-l8dlx             2 /2      Running   0          4s
 
然后訪問prometheus,查看config配置,發現配置已經生效了

查看alert的對應郵件告警信息

5. Prometheus的熱加載機制
Promtheus的時序 數據庫 在存儲了大量的數據后,每次重啟Prometheus進程的時間會越來越慢。 而在日常運維工作中會經常調整Prometheus的配置信息,實際上Prometheus提供了在運行時熱加載配置信息的功能。Prometheus 內部提供了成熟的 hot reload 方案,這大大方便配置文件的修改和重新加載,在 Prometheus 生態中,很多 Exporter 也采用類似約定的實現方式。

Prometheus配置信息的熱加載有兩種方式:
1)第一種熱加載方式:查看Prometheus的進程id,發送 SIGHUP 信號:

1
# kill -HUP <pid>

2)第二種熱加載方式:發送一個POST請求到 /-/reload ,需要在啟動時給定 --web.enable-lifecycle 選項(注意下面的ip是pod ip):

1
# curl -X POST http://PodIP:9090/-/reload

當你采用以上任一方式執行 reload 成功的時候,將在 promtheus log 中看到如下信息:

1
... msg= "Loading configuration file"  filename=prometheus.yml ...

這里注意下:
個人更傾向於采用 curl -X POST 的方式,因為每次 reload 過后, pid 會改變,使用 kill 方式需要找到當前進程號。
從 2.0 開始,hot reload 功能是默認關閉的,如需開啟,需要在啟動 Prometheus 的時候,添加 --web.enable-lifecycle 參數。

在本案例中Prometheus熱加載功能添加的操作如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
[root@k8s-master01 ~] # cd /opt/k8s/work/k8s-prometheus-grafana/prometheus/
[root@k8s-master01 prometheus] # vim prometheus.deploy.yaml
...........
...........
       - image: prom /prometheus :v2.0.0
         name: prometheus
         command :
         "/bin/prometheus"
         args:
         "--config.file=/etc/prometheus/prometheus.yml"
         "--storage.tsdb.path=/prometheus"
         "--storage.tsdb.retention=24h"
         "--web.enable-lifecycle"                             # 在deploy.yaml文件中的prometheus容器構建參數里添加這一行內容
         ports:
         - containerPort: 9090
  
  
然后重啟該deploy配置
[root@k8s-master01 prometheus] # kubectl delete -f prometheus.deploy.yaml
deployment.apps  "prometheus"  deleted
  
[root@k8s-master01 prometheus] # kubectl create -f prometheus.deploy.yaml      
deployment.apps /prometheus  created
  
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system|grep prometheus
prometheus-858989bcfb-8mt92             2 /2      Running   0          22s
  
接下來驗證以下prometheus的熱加載機制
只要是更改了prometheus的相關配置,只需要使用下面的熱加載命令就行,無需重啟Prometheus的pod!
  
例如將Prometheus監控指標中pod內存使用率閾值由上面定義的85%改為90%
[root@k8s-master01 prometheus] # vim configmap.yaml
...........
...........
       - alert: NodeMemoryUsage
         expr : (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) / node_memory_MemT
otal_bytes * 100 > 90
         for : 1m
         labels:
           team: admin
         annotations:
           description:  "{{$labels.instance}}: Memory usage is above 1% (current value is: {{ $value }}%)"
           value:  "{{ $value }}%"
           threshold:  "90%"
 
這里注意:
宿主機 /opt/k8s/work/k8s-prometheus-grafana/prometheus/configmap .yaml文件里配置了兩個yml文件,分別為prometheus.yml和rules.yml,分別對應prometheus容器的
/etc/prometheus/prometheus .yml和 /etc/prometheus/rules .yml
 
 
由於Prometheus的熱加載功能是從資源對象里加載,不是從文件里加載。所以需要保證宿主機 /opt/k8s/work/k8s-prometheus-grafana/prometheus/configmap .yaml文件里
的rules.yml配置和prometheus容器里的 /etc/prometheus/rules .yml文件內容同步。 要想保證這兩者同步,必須在修改了configmap.yml文件后要執行apply更新操作!
(記住:凡是修改了configmap.yml或是alertmanager-conf.yaml等config.yml文件,都要執行apply更新操作!)
 
[root@k8s-master01 prometheus] # kubectl apply -f configmap.yaml
 
先查看prometheus的pod ip(這里prometheus的pod里包括兩個容器:alertmanager和prometheus,同一個pod下的容器共享一個pod ip)
[root@k8s-master01 prometheus] # kubectl get pods -n kube-system -o wide|grep prometheus
prometheus-858989bcfb-fhdfv             2 /2      Running   0          158m    172.30.56.4     k8s-node02   <none>           <none>
 
然后再進行prometheus的熱加載操作(-X POST 和 -XPOST 效果是一樣的)。注意Prometheus的熱加載POST方式中的ip指的是Pod IP地址!
[root@k8s-master01 prometheus] # curl -X POST http://172.30.56.4:9090/-/reload
[root@k8s-master01 prometheus] # curl -XPOST http://172.30.56.4:9090/-/reload
 
訪問訪問prometheus的web頁面,發現熱加載功能已經生效!

6. Grafana 數據源和圖形配置 (默認用戶名密碼均為admin)

1
2
3
4
5
6
7
[root@k8s-master01 grafana] # kubectl get svc -n kube-system|grep "grafana"
grafana            NodePort             10.254.95.120         <none>           3000:31821 /TCP        12m
 
訪問grafana的地址為:
http: //172 .16.60.244:31821/
http: //172 .16.60.245:31821/
http: //172 .16.60.246:31821/

為grafana添加數據源

導入面板,可以直接輸入模板編號315在線導入,或者下載好對應的json模板文件本地導入,面板模板下載地址https:///dashboards/315

查看Grafana的展示效果

這里注意下:k8s監控指標中tyoe為"counter"類型的用rate(速率)進行統計。比如:
指標名稱:etcd_server_leader_changes_seen_total
告警規則:以采集間隔1min為例,本次采集值減去上次采集值,結果大於0告警

則prometheus中監控的報警統計如下:
expr: rate(etcd_server_leader_changes_seen_total{job="kubernetes-etcd"}[1m]) > 0

下面制作了兩個dashboard,可以直接導入對應的json文件(地址:),導入前刪除上面的"Kubernetes cluster monitoring(via Prometheus)"  兩個json文件下載地址: https://pan.baidu.com/s/11GCffEtkvRTn5byDKIUlfg   提取密碼: d5mr

 

建議將上面Dashboard圖形中標題和各監控項的英文名稱改為中文名稱~

三、Prometheus高可用說明

1.  Prometheus的本地存儲
在構建Prometheus高可用方案之前,先來了解一下Prometheus的本地存儲相關的內容。Prometheus 2.x 采用自定義的存儲格式將樣本數據保存在本地磁盤當中。如下所示,按照兩個小時為一個時間窗口,將兩小時內產生的數據存儲在一個塊(Block)中,每一個塊中包含該時間窗口內的所有樣本數據(chunks),元數據文件(meta.json)以及索引文件(index)。

而在當前時間窗口內正在收集的樣本數據,Prometheus則會直接將數據保存在內容當中。為了確保此期間如果Prometheus發生崩潰或者重啟時能夠恢復數據,Prometheus啟動時會以寫入日志(WAL)的方式來實現重播,從而恢復數據。此期間如果通過API刪除時間序列,刪除記錄也會保存在單獨的邏輯文件當中(tombstone)。在文件系統中這些塊保存在單獨的目錄當中,Prometheus保存塊數據的目錄結構如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
. /data
    |- 01BKGV7JBM69T2G1BGBGM6KB12
       |- meta.json
       |- wal
         |- 000002
         |- 000001
    |- 01BKGTZQ1SYQJTR4PB43C8PD98
       |- meta.json
       |- index
       |- chunks
         |- 000001
       |- tombstones
    |- 01BKGTZQ1HHWHV8FBJXW1Y3W0K
       |- meta.json
       |- wal
         |-000001

通過時間窗口的形式保存所有的樣本數據,可以明顯提高Prometheus的查詢效率,當查詢一段時間范圍內的所有樣本數據時,只需要簡單的從落在該范圍內的塊中查詢數據即可。同時該存儲方式可以簡化歷史數據的刪除邏輯。只要一個塊的時間范圍落在了配置的保留范圍之外,直接丟棄該塊即可。

本地存儲配置
用戶可以通過命令行啟動參數的方式修改本地存儲的配置。(本地歷史數據最多保存15天)

在一般情況下,Prometheus中存儲的每一個樣本大概占用1-2字節大小。如果需要對Prometheus Server的本地磁盤空間做容量規划時,可以通過以下公式計算:

1
needed_disk_space = retention_time_seconds * ingested_samples_per_second * bytes_per_sample

保留時間(retention_time_seconds)和樣本大小(bytes_per_sample)不變的情況下,如果想減少本地磁盤的容量需求,只能通過減少每秒獲取樣本數(ingested_samples_per_second)的方式。因此有兩種手段,一是減少時間序列的數量,二是增加采集樣本的時間間隔。考慮到Prometheus會對時間序列進行壓縮,因此減少時間序列的數量效果更明顯。

從失敗中恢復
如果本地存儲由於某些原因出現了錯誤,最直接的方式就是停止Prometheus並且刪除data目錄中的所有記錄。當然也可以嘗試刪除那些發生錯誤的塊目錄,不過這就意味着用戶會丟失該塊中保存的大概兩個小時的監控記錄。

Promthues高效的本地存儲模型,可以讓單台Prometheus能夠高效的處理大量的數據。 但是也導致Promthues數據持久化的問題,無法保存長時間的數據。同時也導致Promthues自身無法進行彈性的擴展,下一部分介紹Promthues的持久化存儲方案Remote Storae。

2.  Prometheus的遠端存儲
在Prometheus設計上,使用本地存儲可以降低Prometheus部署和管理的復雜度同時減少高可用 (HA) 帶來的復雜性。 在默認情況下,用戶只需要部署多套Prometheus,采集相同的Targets即可實現基本的HA。

當然本地存儲也帶來了一些不好的地方,首先就是數據持久化的問題,特別是在像Kubernetes這樣的動態集群環境下,如果Promthues的實例被重新調度,那所有歷史監控數據都會丟失。 其次本地存儲也意味着Prometheus不適合保存大量歷史數據(一般Prometheus推薦只保留幾周或者幾個月的數據)。最后本地存儲也導致Prometheus無法進行彈性擴展。為了適應這方面的需求,Prometheus提供了remote_write和remote_read的特性,支持將數據存儲到遠端和從遠端讀取數據。通過將監控樣本采集和數據存儲分離,解決Prometheus的持久化問題。除了本地存儲方面的問題,由於Prometheus基於Pull模型,當有大量的Target需要采樣本時,單一Prometheus實例在數據抓取時可能會出現一些性能問題,聯邦集群的特性可以讓Prometheus將樣本采集任務划分到不同的Prometheus實例中,並且通過一個統一的中心節點進行聚合,從而可以使Prometheuse可以根據規模進行擴展。

遠程存儲
Prometheus的本地存儲設計可以減少其自身運維和管理的復雜度,同時能夠滿足大部分用戶監控規模的需求。但是本地存儲也意味着Prometheus無法持久化數據,無法存儲大量歷史數據,同時也無法靈活擴展和遷移。為了保持Prometheus的簡單性,Prometheus並沒有嘗試在自身中解決以上問題,而是通過定義兩個標准接口(remote_write/remote_read),讓用戶可以基於這兩個接口將數據保存到任意第三方的存儲服務中,這種方式在Promthues中稱為遠程存儲(Remote Storage)。

Remote Write
用戶可以在Prometheus配置文件中指定Remote Write(遠程寫)的URL地址,比如指向influxdb中,也可指向消息隊列等。一旦設置了該配置項,Prometheus將樣本數據通過HTTP的形式發送給適配器(Adaptor)。而用戶則可以在適配器中對接外部任意服務。外部服務可以是真正的存儲系統, 公有雲存儲服務, 也可以是消息隊列等任意形式。

Remote Read
Promthues的Remote Read(遠程讀)也通過了一個適配器實現。Promthues的Remote Read(遠程讀)的流程當中,當用戶發起查詢請求后(也就是說Remote Read只在數據查詢時有效),Promthues將向remote_read中配置的URL發起查詢請求(matchers,ranges),接收Promthues的原始樣本數據。Adaptor根據請求條件從第三方存儲服務中獲取響應的數據。同時將數據轉換為Promthues的原始樣本數據返回給Prometheus Server。當獲取到樣本數據后,Promthues在本地使用PromQL對樣本數據進行二次處理。注意:即使使用了遠程讀,Prometheus中對於規則文件的處理,以及Metadata API的處理都只在本地完成。

配置文件
用戶需要使用遠程讀寫功能時,主要通過在Prometheus配置文件中添加remote_write和remote_read配置,其中url用於指定遠程讀/寫的HTTP服務地址。如果該URL啟動了認證則可以通過basic_auth進行安全認證配置。對於https的支持需要設定tls_concig。proxy_url主要用於Prometheus無法直接訪問適配器服務的情況下。remote_write和remote_write具體配置如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
remote_write:
     url: <string>
     [ remote_timeout: <duration> | default = 30s ]
     write_relabel_configs:
     [ - <relabel_config> ... ]
     basic_auth:
     [ username: <string> ]
     [ password: <string> ]
     [ bearer_token: <string> ]
     [ bearer_token_file:  /path/to/bearer/token/file  ]
     tls_config:
     [ <tls_config> ]
     [ proxy_url: <string> ]
  
remote_read:
     url: <string>
     required_matchers:
     [ <labelname>: <labelvalue> ... ]
     [ remote_timeout: <duration> | default = 30s ]
     [ read_recent: <boolean> | default =  false  ]
     basic_auth:
     [ username: <string> ]
     [ password: <string> ]
     [ bearer_token: <string> ]
     [ bearer_token_file:  /path/to/bearer/token/file  ]
     [ <tls_config> ]
     [ proxy_url: <string> ]

自定義Remote Stoarge Adaptor
實現自定義Remote Storage需要用戶分別創建用於支持remote_read和remote_write的HTTP服務。一般使用Influxdb作為Remote Stoarge。目前Prometheus社區也提供了部分對於第三方數據庫的Remote Storage支持,如influxDB,OpenTSDB,PostgreSQL等。ES也可以作為遠端存儲,不過如果將ES作為Prometheus的遠端存儲,則默認只能往ES里面寫,Prometheus默認不能從ES里面讀歷史數據(說白了就是ES默認不支持Prometheus的PromQL查詢語法,要用的法,需要做修改)。通過Remote Storage特性可以將Promthues中的監控樣本數據存儲在第三方的存儲服務中,從而解決了Promthues的數據持久化問題。同時由於解除了本地存儲的限制,Promthues自身也可以進行彈性的擴展,在諸如Kubernetes這樣的環境下可以進行動態的調度。使用influxdb作為Remote Stoarge遠端存儲的方式這里就不介紹了。下面介紹下Prometheus的聯邦集群。

3.  Prometheus的聯邦集群
單個Prometheus Server可以輕松的處理數以百萬的時間序列。當然根據規模的不同的變化,Prometheus同樣可以輕松的進行擴展。這部分將會介紹利用Prometheus的聯邦集群特性,對Prometheus進行擴展。聯邦有不同的用例, 它通常用於實現可擴展的prometheus,或者將metrics從一個服務的prometheus拉到另一個Prometheus上用於展示。

Prometheus支持使用聯邦集群的方式,對Prometheus進行擴展。對於大部分監控規模而言,我們只需要在每一個數據中心 (例如:EC2可用區,Kubernetes集群) 安裝一個Prometheus Server實例,就可以在各個數據中心處理上千規模的集群。同時將Prometheus Server部署到不同的數據中心可以避免網絡配置的復雜性。

對於大部分監控規模而言,我們只需要在每一個數據中心(例如一個Kubernetes集群)安裝一個Prometheus Server實例,就可以在各個數據中心處理上千規模的集群,這也可以避免網絡配置的復雜性。

如上圖所示,在每個數據中心部署單獨的Prometheus Server,用於采集當前數據中心監控數據,並由一個中心的Prometheus Server負責聚合多個數據中心的監控數據。這一特性在Promthues中稱為聯邦集群。聯邦集群的核心在於每一個Prometheus Server都包含一個用於獲取當前實例中監控樣本的接口/federate。對於中心Prometheus Server而言,無論是從其他的Prometheus實例還是Exporter實例中獲取數據實際上並沒有任何差異。

每一個Prometheus Server實例包含一個/federate接口,用於獲取一組指定的時間序列的監控數據。因此在中心Prometheus Server中只需要配置一個采集任務用於從其他Prometheus Server中獲取監控數據。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
scrape_configs:
   - job_name:  'federate'
     scrape_interval: 15s
     honor_labels:  true
     metrics_path:  '/federate'
     params:
       'match[]' :
         '{job="prometheus"}'
         '{__name__=~"job:.*"}'
         '{__name__=~"node.*"}'
     static_configs:
       - targets:
         '172.16.60.240:9090'
         '172.16.60.241:9090'

通過params可以用於控制Prometheus Server向Target實例請求監控數據的URL當中添加請求參數。例如:

1
"http://172.16.60.240:9090/federate?match[]={job%3D" prometheus "}&match[]={__name__%3D~" job%3A.* "}&match[]={__name__%3D~" node.* "}"

通過URL中的match[]參數指定,可以指定需要獲取的時間序列。honor_labels配置true可以確保當采集到的監控指標沖突時,能夠自動忽略沖突的監控數據。如果為false時,prometheus會自動將沖突的標簽替換為exported_的形式。

功能分區
功能分區,即通過聯邦集群的特性在任務級別對Prometheus采集任務進行划分,以支持規模的擴展。而當你的監控大到單個Prometheus Server無法處理的情況下,我們可以在各個數據中心中部署多個Prometheus Server實例。每一個Prometheus Server實例只負責采集當前數據中心中的一部分任務(Job),例如可以將應用監控和主機監控分離到不同的Prometheus實例當中。假如監控采集任務的規模繼續增大,通過功能分區的方式可以進一步細化采集任務。對於中心Prometheus Server只需要從這些實例中聚合數據即可。例如如下所示,可以在各個數據中心中部署多個Prometheus Server實例。每一個Prometheus Server實例只負責采集當前數據中心中的一部分任務(Job),再通過中心Prometheus實例進行聚合。

水平擴展
另外一種極端的情況,假如當單個采集任務的量也變得非常的大,這時候單純通過功能分區Prometheus Server也無法有效處理。在這種情況下,我們只能考慮在任務(Job)的實例級別進行水平擴展。將采集任務的目標實例划分到不同的Prometheus Server當中。水平擴展:即通過聯邦集群的特性在任務的實例級別對Prometheus采集任務進行划分,以支持規模的擴展。水平擴展可以將統一任務的不同實例的監控數據采集任務划分到不同的Prometheus實例。通過relabel設置,我們可以確保當前Prometheus Server只收集當前采集任務的一部分實例的監控指標。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
global:
   external_labels:
     slave: 1   # This is the 2nd slave. This prevents clashes between slaves.
scrape_configs:
   - job_name: some_job
     # Add usual service discovery here, such as static_configs
     relabel_configs:
     - source_labels: [__address__]
       modulus:       4     # 4 slaves
       target_label:  __tmp_hash
       action:        hashmod
     - source_labels: [__tmp_hash]
       regex:         ^1$   # This is the 2nd slave
       action:        keep

並且通過當前數據中心的一個中心Prometheus Server將監控數據進行聚合到任務級別。

1
2
3
4
5
6
7
8
9
10
11
12
13
- scrape_config:
   - job_name: slaves
     honor_labels:  true
     metrics_path:  /federate
     params:
       match[]:
         '{__name__=~"^slave:.*"}'    # Request all slave-level time series
     static_configs:
       - targets:
         - slave0:9090
         - slave1:9090
         - slave3:9090
         - slave4:9090

幾種高可用方案
遠程存儲解決了prometheus數據持久化和可擴展性的問題,聯邦解決了單台prometheus數據采集任務量過大的問題。它們的組合可以作為高可用方案。

1.  基本HA:服務可用性
此方案用戶只需要部署多套Prometheus Server實例,並且采集相同的Exporter目標即可。基本的HA模式只能確保Promthues服務的可用性問題,但是不解決Prometheus Server之間的數據一致性問題以及持久化問題(數據丟失后無法恢復),也無法進行動態的擴展。因此這種部署方式適合監控規模不大,Promthues Server也不會頻繁發生遷移的情況,並且只需要保存短周期監控數據的場景。

2.  基本HA + 遠程存儲
在基本HA模式的基礎上通過添加Remote Storage存儲支持,將監控數據保存在第三方存儲服務上。在保證Promthues服務可用性的基礎上,同時確保了數據的持久化,當Promthues Server發生宕機或者數據丟失的情況下,可以快速的恢復。 同時Promthues Server可能很好的進行遷移。因此,該方案適用於用戶監控規模不大,但是希望能夠將監控數據持久化,同時能夠確保Promthues Server的可遷移性的場景。

 

3.  基本HA + 遠程存儲 + 聯邦集群
當單台Promthues Server無法處理大量的采集任務時,用戶可以考慮基於Prometheus聯邦集群的方式將監控采集任務划分到不同的Promthues實例當中,即在任務級別進行功能分區。這種方案適用於兩種場景:
場景一:單數據中心 + 大量的采集任務
這種場景下Promthues的性能瓶頸主要在於大量的采集任務,因此用戶需要利用Prometheus聯邦集群的特性,將不同類型的采集任務划分到不同的Promthues子服務中,從而實現功能分區。
場景二:多數據中心
這種模式也適合與多數據中心的情況,當Promthues Server無法直接與數據中心中的Exporter進行通訊時,在每一個數據中部署一個單獨的Promthues Server負責當前數據中心的采集任務是一個不錯的方式。這樣可以避免用戶進行大量的網絡配置,只需要確保主Promthues Server實例能夠與當前數據中心的Prometheus Server通訊即可。 中心Promthues Server負責實現對多數據中心數據的聚合。

持久化就是歷史數據落盤,Prometheus實例跑在K8s中,只保存24小時的。本地存放短時間內的數據,如果要長時間存放數據,可以再遠端存儲上存放歷史數據。通過聯邦的方式,實現了遠程同步並保存歷史數據的這個功能。prometheus 高可用分為實例高可用和存儲高可用:
1)實例高可用使用k8s的多pod方式。啟兩個pod,兩個都采集數據,落在本地,設置保留時間,比如2小時。2小時內的數據可以進行監控和報警。
2)存儲高可用使用的是聯邦方式。采用聯邦高可用方式,數據先寫到本地落盤,接着上層去讀(上層不落盤),讀到下層的遠程存儲里落盤。寫只能在本地,讀可以在本地也可以在遠端存儲上。

4.  Alertmanager的聯邦集群
在prometheus server高可用的情況下,單個alertmanager容易引發單點故障。

解決該問題最直接方式就是部署多套Alertmanager, 但由於Alertmanager之間不存在並不了解彼此的存在,因此則會出現告警通知被不同的Alertmanager重復發送多次的問題。

為了解決這一問題,Alertmanager引入了Gossip機制,保證多個Alertmanager之間的信息傳遞。確保在多個Alertmanager分別接收到相同告警信息的情況下,也只有一個告警通知被發送給Receiver。

Gossip協議
Gossip是分布式系統中被廣泛使用的協議,用於實現分布式節點之間的信息交換和狀態同步。如下所示,當Alertmanager接收到來自Prometheus的告警消息后,會按照以下流程對告警進行處理:

1. 在第一個階段Silence中,Alertmanager會判斷當前通知是否匹配到任何的靜默規則,如果沒有則進入下一個階段,否則則中斷流水線不發送通知。
2. 在第二個階段Wait中,Alertmanager會根據當前Alertmanager在集群中所在的順序(index)等待index * 5s的時間。
3. 當前Alertmanager等待階段結束后,Dedup階段則會判斷當前Alertmanager數據庫中該通知是否已經發送,如果已經發送則中斷流水線,不發送告警,否則則進入下一階段Send對外發送告警通知。
4. 告警發送完成后該Alertmanager進入最后一個階段Gossip,Gossip會通知其他Alertmanager實例當前告警已經發送。其他實例接收到Gossip消息后,則會在自己的數據庫中保存該通知已發送的記錄。

因此如下所示,Gossip機制的關鍵在於兩點:

1. Silence設置同步:Alertmanager啟動階段基於Pull-based從集群其它節點同步Silence狀態,當有新的Silence產生時使用Push-based方式在集群中傳播Gossip信息。
2. 通知發送狀態同步:告警通知發送完成后,基於Push-based同步告警發送狀態。Wait階段可以確保集群狀態一致。

Alertmanager基於Gossip實現的集群機制雖然不能保證所有實例上的數據時刻保持一致,但是實現了CAP理論中的AP系統,即可用性和分區容錯性。同時對於Prometheus Server而言保持了配置了簡單性,Promthues Server之間不需要任何的狀態同步。

Gossip集群搭建
多個Alertmanager可以組成gossip集群,需要在Alertmanager啟動時設置相應的參數。其中主要的參數包括:
1. --cluster.listen-address: 當前alertmanager在gossip集群的監聽地址【這地址指的是啥沒太懂,如有錯誤還望指點】
2. --cluster.peer: 需要關聯的gossip集群的監聽地址

舉個例子:

1
2
3
. /alertmanager  --web.listen-address= ":9093"  --cluster.listen-address= "127.0.0.1:8001"  --storage.path= /tmp/data01  --config. file = /etc/prometheus/alertmanager01 .yml --log.level=debug
. /alertmanager  --web.listen-address= ":9094"  --cluster.listen-address= "127.0.0.1:8002"  --cluster.peer=127.0.0.1:8001 --storage.path= /tmp/data02  --config. file = /etc/prometheus/alertmanager02 .yml --log.level=debug
. /alertmanager  --web.listen-address= ":9095"  --cluster.listen-address= "127.0.0.1:8003"  --cluster.peer=127.0.0.1:8001 --storage.path= /tmp/data03  --config. file = /etc/prometheus/alertmanager03 .yml --log.level=debug

該例子創建了三個alertmanager組成gossip集群,后兩個創建的alertmanager需要關聯第一個創建alertmanager對應的gossip監聽地址。啟動完成后訪問任意Alertmanager節點http://localhost:9093/#/status,可以查看當前Alertmanager集群的狀態。

對應的prometheus配置文件中的告警部分需要添加多個alertmanager地址:

1
2
3
4
5
6
7
alerting:
   alertmanagers:
   - static_configs:
     - targets:
       - 127.0.0.1:9093
       - 127.0.0.1:9094
       - 127.0.0.1:9095
轉載散盡浮華


免責聲明!

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



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