1、Prometheus介紹
以前已經詳細介紹了Kubernetes集羣部署篇,今天這裏重點說下Kubernetes監控方案-Prometheus+Grafana。Prometheus(普羅米修斯)是一個開源系統監控和警報工具,最初是在SoundCloud創建的。自2012年成立以來,許多公司和組織都採用了普羅米修斯,該項目擁有一個很是活躍的開發者和用戶社區。它如今是一個獨立的開放源碼項目,而且獨立於任何公司,爲了強調該點並澄清項目的治理結構,Prometheus在2016年加入了雲計算基金會,成爲繼Kubernetes以後的第二個託管項目。 Prometheus是用來收集數據的,同時自己也提供強大的查詢能力,結合Grafana便可以監控並展現出想要的數據。node
Prometheus的主要特徵
- 多維度數據模型
- 靈活的查詢語言 (PromQL)
- 不依賴分佈式存儲,單個服務器節點是自主的
- 以HTTP方式,經過pull模型拉去時間序列數據
- 也經過中間網關支持push模型
- 經過服務發現或者靜態配置,來發現目標服務對象
- 支持多種多樣的圖表和界面展現,grafana也支持它mysql
Prometheus組件
Prometheus生態包括了不少組件,它們中的一些是可選的:
- 主服務Prometheus Server負責抓取和存儲時間序列數據
- 客戶庫負責檢測應用程序代碼
- 支持短生命週期的PUSH網關
- 基於Rails/SQL儀表盤構建器的GUI
- 多種導出工具,能夠支持Prometheus存儲數據轉化爲HAProxy、StatsD、Graphite等工具所須要的數據存儲格式
- 警告管理器 (AlertManaager)
- 命令行查詢工具
- 其餘各類支撐工具nginx
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實現數據可視化git
Prometheus架構
下面這張圖說明了Prometheus的總體架構,以及生態中的一些組件做用github
Prometheus總體流程比較簡單,Prometheus 直接接收或者經過中間的 Pushgateway 網關被動獲取指標數據,在本地存儲全部的獲取的指標數據,並對這些數據進行一些規則整理,用來生成一些聚合數據或者報警信息,Grafana 或者其餘工具用來可視化這些數據。web
Prometheus服務能夠直接經過目標拉取數據,或者間接地經過中間網關拉取數據。它在本地存儲抓取的全部數據,並經過必定規則進行清理和整理數據,並把獲得的結果存儲到新的時間序列中,PromQL和其餘API可視化展現收集的數據在K8s中,關於集羣的資源有metrics度量值的概念,有各類不一樣的exporter能夠經過api接口對外提供各類度量值的及時數據,prometheus在與k8s融合工做的過程當中就是經過與這些提供metric值的exporter進行交互,獲取數據,整合數據,展現數據,觸發告警的過程。redis
1)Prometheus獲取metrics
- 對短暫生命週期的任務,採起拉的形式獲取metrics (不常見)
- 對於exporter提供的metrics,採起拉的方式獲取metrics(一般方式),對接的exporter常見的有:kube-apiserver 、cadvisor、node-exporter,也可根據應用類型部署相應的exporter,獲取該應用的狀態信息,目前支持的應用有:nginx/haproxy/mysql/redis/memcache等。sql
2)Prometheus數據彙總及按需獲取
能夠按照官方定義的expr表達式格式,以及PromQL語法對相應的指標進程過濾,數據展現及圖形展現。不過自帶的webui較爲簡陋,但prometheus同時提供獲取數據的api,grafana可經過api獲取prometheus數據源,來繪製更精細的圖形效果用以展現。
expr書寫格式及語法參考官方文檔:https://prometheus.io/docs/prometheus/latest/querying/basics/docker
3)Prometheus告警推送
prometheus支持多種告警媒介,對知足條件的告警自動觸發告警,並可對告警的發送規則進行定製,例如重複間隔、路由等,能夠實現很是靈活的告警觸發。數據庫
Prometheus適用場景
Prometheus在記錄純數字時間序列方面表現很是好。它既適用於面向服務器等硬件指標的監控,也適用於高動態的面向服務架構的監控。對於如今流行的微服務,Prometheus的多維度數據收集和數據篩選查詢語言也是很是的強大。Prometheus是爲服務的可靠性而設計的,當服務出現故障時,它可使你快速定位和診斷問題。它的搭建過程對硬件和服務沒有很強的依賴關係。
Prometheus不適用場景
Prometheus,它的價值在於可靠性,甚至在很惡劣的環境下,你均可以隨時訪問它和查看系統服務各類指標的統計信息。 若是你對統計數據須要100%的精確,它並不適用,例如:它不適用於實時計費系統
2、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)在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)在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 ================================================================================================================================== 這裏貼下以前線上k8s集羣部署時用到的secret對象的建立命令 # kubectl -n kube-system create secret generic cmp-prometheus-certs --from-file=/opt/cmp/ssl/etcd/healthcheck-client.pem --from-file=/opt/cmp/ssl/etcd/healthcheck-client-key.pem --from-file=/opt/cmp/ssl/etcd/ca.pem # kubectl -n kube-system create secret generic cmp-prometheus-kubernetes-ca --from-file=/opt/cmp/ssl/kubernetes-ca/admin.pem --from-file=/opt/cmp/ssl/kubernetes-ca/admin-key.pem --from-file=/opt/cmp/ssl/kubernetes-ca/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容器,這兩個是分開部署的。操做記錄以下 (這裏配置實現的時郵件報警):
[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"的查詢欄裏直接查看
修改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 信號:
# kill -HUP <pid>
2)第二種熱加載方式:發送一個POST請求到 /-/reload ,須要在啓動時給定 --web.enable-lifecycle 選項(注意下面的ip是pod ip):
# curl -X POST http://PodIP:9090/-/reload
當你採用以上任一方式執行 reload 成功的時候,將在 promtheus log 中看到以下信息:
... msg="Loading configuration file" filename=prometheus.yml ...
這裏注意下:
我的更傾向於採用 curl -X POST 的方式,由於每次 reload 事後, pid 會改變,使用 kill 方式須要找到當前進程號。
從 2.0 開始,hot reload 功能是默認關閉的,如需開啓,須要在啓動 Prometheus 的時候,添加 --web.enable-lifecycle 參數。
在本案例中Prometheus熱加載功能添加的操做以下:
[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)
[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圖形中標題和各監控項的英文名稱改成中文名稱~
3、Prometheus高可用說明
1. Prometheus的本地存儲
在構建Prometheus高可用方案以前,先來了解一下Prometheus的本地存儲相關的內容。Prometheus 2.x 採用自定義的存儲格式將樣本數據保存在本地磁盤當中。以下所示,按照兩個小時爲一個時間窗口,將兩小時內產生的數據存儲在一個塊(Block)中,每個塊中包含該時間窗口內的全部樣本數據(chunks),元數據文件(meta.json)以及索引文件(index)。
而在當前時間窗口內正在收集的樣本數據,Prometheus則會直接將數據保存在內容當中。爲了確保此期間若是Prometheus發生崩潰或者重啓時可以恢復數據,Prometheus啓動時會以寫入日誌(WAL)的方式來實現重播,從而恢復數據。此期間若是經過API刪除時間序列,刪除記錄也會保存在單獨的邏輯文件當中(tombstone)。在文件系統中這些塊保存在單獨的目錄當中,Prometheus保存塊數據的目錄結構以下所示:
./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的本地磁盤空間作容量規劃時,能夠經過如下公式計算:
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具體配置以下所示:
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中獲取監控數據。
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當中添加請求參數。例如:
"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只收集當前採集任務的一部分實例的監控指標。
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將監控數據進行聚合到任務級別。
- 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集羣的監聽地址
舉個例子:
./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地址:
alerting: alertmanagers: - static_configs: - targets: - 127.0.0.1:9093 - 127.0.0.1:9094 - 127.0.0.1:9095