本文介紹了如何基于 kube-prometheus 設計一個監控系統, 以靈活簡單的方式對 kubernetes 上的應用進行指標采集,并實現監控報警功能。
本文提供了作者的應用示例,另外還記錄了作者在學習、使用 Prometheus 過程中的一些筆記,如 arm 版鏡像獲取、一些工具的使用等。
前言
衆所周知,大數據産品作為底層平臺,其運維監控一直是生産實踐的痛點難點,且在穩定運行的基礎之上,往往還需要對性能進行評估優化,所以其監控系統的建設顯得尤為重要。
Prometheus 作為云原生時代最火的監控軟件,很多大數據組件或原生或以第三方插件 / exporter 的形式對 Prometheus 做了支持。
我使用的大數據平臺是基于 kubernetes 運行的,有部署靈活管理方便的優點,更容易與 Prometheus 進行結合。
下面將對設計思路和技術實現進行闡述探討。
設計思路
監控系統的核心任務是將暴露出來的指標數據進行抓取,在此之上進行分析、告警所以有以下幾個要明確的問題:
監控對象是什么
監控對象如何暴露指標數據
監控系統如何對指標進行抓取
如何實現告警規則動態配置、管理
監控對象
以 pod(容器)形式運行在 kubernetes 集群上的各個大數據組件。
指標暴露方式
各組件根據對 Prometheus 的支持程度,可分為 3 種類型的指標暴露方式:
直接暴露 Prometheus 指標數據 (直接,拉)
主動將指標數據推送到 prometheus-pushGateway,由 pushGateway 暴露數據(間接,推)
自定義 exporter 將其他形式的指標數據轉換為符合 Prometheus 標準的格式進行暴露(exporter,直接,拉)
個別組件同時支持多種方式,如 flink 支持直接和間接方式,spark 支持直接方式而且也有第三方 exporter。大部分組件都有官方 / 第三方的 exporter,極少數需要自己開發。
一般情況下直接方式就可以了。
需要注意的是,像 flink(spark) on yarn 模式運行的時候,flink 節點是跑在 yarn 容器里面的。這種情況下 Prometheus 很難對其直接進行抓取,這種時候就只能用間接方式,主動將數據推送到 pushGateway。
另外那些短暫生命周期的組件也建議用主動 push 到 pushGateway。
指標抓取方式
不管是 exporter 還是 pushGateway,到最后必然是由 Prometheus 主動對這些目標進行抓取。
?
Prometheus 主要通過 Pull 的方式來抓取目標服務暴露出來的監控接口,因此需要配置對應的抓取任務來請求監控數據并寫入到 Prometheus 提供的存儲中,目前 Prometheus 服務提供了如下幾個任務的配置:
原生 Job 配置:提供 Prometheus 原生抓取 Job 的配置。
Pod Monitor:在 K8S 生態下,基于 Prometheus Operator 來抓取 Pod 上對應的監控數據。
Service Monitor:在 K8S 生態下,基于 Prometheus Operator 來抓取 Service 對應 Endpoints 上的監控數據。
參考:https://cloud.tencent.com/document/product/1416/55995
既然都上了 kubernetes 環境了,一般當然是推薦直接用 podMonitor。配置更簡潔易懂。podMonitorSelector 的過濾在 prometheus-prometheus.yaml 配置。
?
prometheus-prometheus.yaml 是核心配置文件,不宜頻繁修改 (會導致 Prometheus 重啟)。
主要配置項為:serviceMonitorSelector,podMonitorSelector,ruleSelector,alertmanagers。
其中 service 監控選擇器和 pod 監控選擇器默認選擇所有,這里建議把 ruleSelector 也修改為選擇所有。
不過一個 podMonitor 一般只對應一種類型的 pod,在已有 pod 類型較多的情況下,還可以考慮一種更取巧的方法就是 Prometheus 的 kubernetes 服務發現功能。即 kubernetes_sd_config。這種屬于原生 Job 配置,建議使用 additional-scrape-config[1] 進行配置。
kubernetes_sd_config[2] 賦予了 Prometheus 通過 kubernetes rest api 感知 kubernetes 資源的功能,利用該能力,可以使用原生 Job 配置自動發現 pod,將其作為監控目標。再利用 Prometheus 的 Relabel 功能[3]可以改寫發現的標簽,進行前置處理、轉換。實現 pod 篩選,修改抓取配置的效果。而自動發現的 pod 的標簽的來源又可以是 pod 資源的 label/annotation 等。
最終實現的效果如下:
這是一個 pushGateway 的 pod 的配置 , 則 Prometheus 會通過其 19091 端口訪問 / metrics 路徑獲取其指標數據
annotations: prometheus.io/scrape:"true" prometheus.io/scheme:"http" prometheus.io/path:"/metrics" prometheus.io/port:"19091"
這部分的內容主要參考:
https://godleon.github.io/blog/Prometheus/Prometheus-Relabel
https://yunlzheng.gitbook.io/prometheus-book/part-iii-prometheus-shi-zhan/readmd/service-discovery-with-kubernetes
podMonitor 是官方支持,簡潔易懂。kubernetes_sd_config+relabel 的方案較復雜,難度較高,但不用寫那么多的 podMonitor。自行抉擇就行,也可以一起用。
告警設計
告警流程
prometheus 的監控告警基本流程是:
服務發生異常
觸發 prometheus 服務器發出告警信息(alert)
alertmanager 收到告警信息
alertmanager 根據預配置的規則對告警信息進行處理,實現業務邏輯,如分組、抑制、觸發短信郵箱等
當然具體的流程沒那么簡單,有很多細節需要注意,特別是觸發告警時機,是個重點。
這些屬于 Prometheus 的機制實現,這里就不展開贅述,推薦閱讀以下文章:
Prometheus 一條告警的觸發流程、等待時間[4]
AlertManager 何時報警[5]
后邊會給出一個本人實際應用測試的例子,可供參考,會直觀一些。
告警的動態配置
kube-prometheus 的告警規則分兩部分:
alertmanager: 即對告警信息的處理策略
配置參考:https://yunlzheng.gitbook.io/prometheus-book/parti-prometheus-ji-chu/alert/alert-manager-config
核心是 alertmanager-secret.yaml 配置文件,該文件以 secret 的形式被 Alertmanager 讀取。Alertmanager 會自動讀取 secret 中的配置進行更新。
alertRule: 即具體的告警規則
配置參考:https://yunlzheng.gitbook.io/prometheus-book/parti-prometheus-ji-chu/alert/prometheus-alert-rule
在 kubernetes 中是以 PrometheusRule 類型操作,所以管理起來跟 pod 一樣,直接使用 kubelet 增刪改即可。
接入自定義告警平臺
從個人實踐的角度來看,AlertManager 處理 web hook 之外的告警接收插件,如短信、郵箱等只適合測著玩。生産使用還是要通過 web hook 將告警信息發送到自己的告警平臺。可以根據業務需要對告警信息做高度定制化處理、記錄等。另外可以在告警信息中攜帶具體告警規則等信息指導告警平臺進行處理。
這里要做個區分,AlertManager 是告警信息的前置處理,負責非業務性前置操作,如告警信息分組、平抑等。而自定義告警平臺則負責告警信息的業務處理,如記錄、去敏、發送到多終端等。
AlertManager 可能收到 1w 條告警信息,經過處理最終只發了 1 條到自定義告警平臺。而自定義告警平臺可以將這 1 條告警信息記錄起來,修改內容,同時使用郵箱、短信通知到多個負責人。
告警層級標簽設計
監控對象的粒度決定告警的層級,體現在配置上則是告警規則的分組。分組信息決定 alertManager 的處理方式。
alertManager 對告警信息的路由策略是樹狀的,所以可通過多個分組標簽實現多層級路由處理。
具體設計應結合業務需求,不在這里展開,感興趣的可以看我下面的實現舉例。
技術實現
技術實現主要分以下幾部分:
kubernetes 環境下 prometheus 的部署 (kube-prometheus)
kube-prometheus 的增強配置 : 即 kubernetes_sd_config+relabel 方案的實現
bigdata-exporter 的實現
告警設計實例
kubernetes 環境下 prometheus 的部署
1) kube-prometheus vs prometheus-operator
github 上 coreos 下有兩個項目:kube-prometheus 和 prometheus-operator,兩者都可以實現 prometheus 的創建及管理。
需要注意的是,kube-prometheus 上的配置操作也是基于 prometheus-operator 的,并提供了大量的默認配置,故這里使用的是 kube-prometheus 項目的配置。
另外使用前需注意 k8s 版本要求,找到對應的 kube-prometheus 版本,弄清楚對應的 prometheus-operator 版本。如:k8s1.14 版本最高可使用 kube-prometheus 0.3,對應的 prometheus-operator 版本是 0.32,閱讀文檔時注意對應版本。
2) kube-prometheus 使用前說明
kube-prometheus 使用 jsonnet 編寫配置模板文件,生成 k8s 配置清單。已提供默認清單文件,在 manifests 文件夾下。如果需要修改默認清單配置,需要在 go 環境下使用 jp 編譯清單。
下面都以默認配置為例
3) 安裝教程
參考官方說明即可
1、git clone 項目 并切換到指定分支
2、kubectl create
清單文件中各配置已附帶 namespace 信息,故執行時不需要指定 namespace,否則可能出錯。
官方命令如下:
#CreatethenamespaceandCRDs,andthenwaitforthemtobeavailblebeforecreatingtheremainingresources $kubectlcreate-fmanifests/setup $untilkubectlgetservicemonitors--all-namespaces;dodate;sleep1;echo"";done $kubectlcreate-fmanifests/
kubernetes_sd_config+relabel 方案的實現
見:https://github.com/linshenkx/kube-prometheus-enhance
bigdata-exporter 的實現
hdfs、yarn、hbase、yarn 等組件都提供了 web 獲取 jmx 指標的方式。
這里的思路是使用一個 bigdata-exporter,去采集多個組件多個節點的指標數據,并進行轉換,然后以 Prometheus 規定的格式對外公開。
指標數據的轉換規則可以查看 github 上的一些項目,要注意版本,也可以像我一樣自己寫,更可靠。
bigdata-exporter 如何感知到采集目標?
除了部署 ip 不同,不同組件不同角色的指標對外端口、路徑、內容(解析規則)也都不一樣。
這里可以參考上面 kubernetes_sd_config+relabel 的方案,做得優雅一些:
授予 bigdata-exporter 調用 kubernetes app 的能力,
利用 label 和 annotations 進行篩選和信息傳遞,確定捕捉目標和途徑。
使用 role 代表解析內容的類型,根據 role 確定解析規則
labels: bigData.metrics.object:pod annotations: bigData.metrics/scrape:"true" bigData.metrics/scheme:"https" bigData.metrics/path:"/jmx" bigData.metrics/port:"29871" bigData.metrics/role:"hdfs-nn,common"
告警設計示例
這里以組和實例兩個維度為例,用 groupId 和 instanceId 表示。
1) alertManager 配置示例
以下是 alertmanager 的規則配置,有兩個接收者,其中 test.web.hook 指向自定義告警平臺。default 是空白接收者,不做處理。路由策略是根據 groupId,instanceId 分組,對節點磁盤使用率、kafka 隊列堆積兩個組處理,instanceId 還沒有展開。
舊版本是用 secret 的 data 字段,需要將配置內容轉成 base64 編碼格式。新版本直接用 stringData 字段。推薦用 stringData 字段配置。其實只要看一下 kube-prometheus 的 alertmanager-secret.yaml 文件就知道怎么回事了。
使用 data 字段的配置方法:寫好 config 文件,以 alertmanager.yaml 命名(不能使用其他名稱)。執行以下命令 , 即可更新 secret。
$kubectl-nmonitoringcreatesecretgenericalertmanager-main--from-file=alertmanager.yaml--dry-run-oyaml|kubectl-n=monitoringapply-f-
global: resolve_timeout:5m receivers: -name:'default' -name:'test.web.hook' webhook_configs: -url:'http://alert-url' route: receiver:'default' group_wait:30s group_interval:5m repeat_interval:2h group_by:[groupId,instanceId] routes: -receiver:'test.web.hook' continue:true match: groupId:node-disk-usage -receiver:'test.web.hook' continue:true match: groupId:kafka-topic-highstore
2) alertRule 配置示例
組代表一個類型的所有目標:即所有節點。實例則代表具體的某個節點。
disk-usage.yaml 磁盤使用率告警配置示例如下:
?
注意:${path} 為監控的磁盤路徑,${thresholdValue} 為使用率閾值,需自行替換。labels 中的 userIds 和 receivers 為傳遞給自定義告警平臺的參數,以指導告警平臺如何操作。
在這個任務中,我們的目標是組粒度的(所有節點),所以不需要設置 instanceId。
apiVersion:monitoring.coreos.com/v1 kind:PrometheusRule metadata: creationTimestamp:null labels: role:alert-rules name:node-disk-usage namespace:monitoring spec: groups: -name:node-disk-usage rules: -alert:node-disk-usage expr:100*(1-node_filesystem_avail_bytes{mountpoint="${path}"}/node_filesystem_size_bytes{mountpoint="${path}"})>${thresholdValue} for:1m labels: groupId:node-disk-usage userIds:super receivers:SMS annotations: title:"磁盤警告:節點{{$labels.instance}}的${path}目錄使用率已達到{{$value}}%" content:"磁盤警告:節點{{$labels.instance}}的${path}目錄使用率已達到{{$value}}%"
kafka-topic-highstore.yaml kafka 隊列消費堆積告警配置示例如下:
我們只關心個別隊列的消費情況,所以這里的粒度為 instance。
?
注意:${uniqueName} 為隊列名,${consumergroup} 為消費組名稱,${thresholdValue} 為堆積數量閾值。
apiVersion:monitoring.coreos.com/v1 kind:PrometheusRule metadata: creationTimestamp:null labels: role:alert-rules name:kafka-topic-highstore-${uniqueName} namespace:monitoring spec: groups: -name:kafka-topic-highstore rules: -alert:kafka-topic-highstore-${uniqueName} expr:sum(kafka_consumergroup_lag{exporterType="kafka",consumergroup="${consumergroup}"})>${thresholdValue} for:1m labels: groupId:kafka-topic-highstore instanceId:${uniqueName} userIds:super receivers:SMS annotations: title:"KAFKA警告:消費組${consumergroup}的堆積數量達到:{{$value}}" content:"KAFKA警告:消費組${consumergroup}的堆積數量達到:{{$value}}"
其他
告警流程示例
這里以兩個節點 node1 和 node2 配置了磁盤空間監控為例,空間使用到達閾值則觸發告警。(測試過程中可通過生成、刪除指定體積的文件來控制空間占用)
其中配置項如下:
告警規則 : node-disk-usage
for 為 1m
告警中心 : alertManager
group_wait: 30s
group_interval: 5m
repeat_interval: 10m
收到的告警短信內容及時間線如下:
1014 收到第一次警報:node1 于 1044 進入異常
1014 收到第二次警報:node1 于 1044 進入異常node2 于 1044 進入異常
1029 收到第三次警報:node1 于 1044 進入異常node2 于 1044 進入異常
1044 收到第四次警報:node1 于 1044 進入異常node2 于 1044 進入異常
1044 收到第五次警報:恢復告警node1 于 1044 進入異常,并于 1044 恢復node2 于 1044 進入異常,并于 1014 恢復
總共收到 5 次短信,第 1 次是 node1 異常,第 2 到 4 次是 node1 和 node2 都異常,因為屬于同個分組 group,所以合并發送。第 5 次是已經恢復正常了。
根據短信內容和時間,整理出告警邏輯時間線如下:
node1 等待 for 1 分鐘 后警報進入 group
node1 記錄異常時間為 1044,實際異常狀態至少在 1044 的一分鐘前
group 等待 group_wait 30s 后發送第一次告警
firing:node1
node2 等待 for 1 分鐘 后警報進入 group
node2 記錄異常時間為 1044,實際異常狀態至少在 1044 的一分鐘前,此時 group 中有兩個異常目標 node1 和 node2。
group 等待 group_interval 5m 后發送第二次告警
firing:node1,node2
注意:因為 group 發生了變化,所以這里用的是 group_interval。
group 等待 repeat_interval 10m 后發送第三次告警
firing:node1,node2
注意:因為 group 沒有變化,屬于重復告警,用的是 repeat_interval。
group 等待 repeat_interval 10m 后發送第四次告警
firing:node1,node2
同上一次。
第四次告警后的 前 5 分鐘:node2 恢復正常
第四次告警后的 后 5 分鐘:node1 恢復正常
group 等待 repeat_interval 10m 后發送第五次告警
resolved:node1,node2
注意,這里 node1,node2 都恢復正常用的也是 repeat_interval。
綜上:
for 是告警規則個體的監控配置,用來衡量服務多久檢測不通過才算異常。
group_wait:初次發送告警的等待時間
用于 group 創建后的等待,這個值通常設置較小,在幾分鐘以內。
group_interval:同一個組其他新發生的告警發送時間間隔
是 group 內容發生變化后的告警間隔。
repeat_interval:重復發送同一個告警的時間間隔
group 內容沒有變化且上一次發生成功時用的發生間隔。
需要注意,恢復正常不屬于 group 變化,用的是 repeat_interval。這有點反直覺,且個人認為不是很合理,不知道是不是測試有問題,也沒有找到比較好的資料說明。希望知道的可以指教一下。
exporter 的位置
exporter 可以以 sidecar 的形式和原容器放在同一個 pod 內(1 對 1),也可以以獨立部署的形式存在(1 對 1/1 對多)。
這個視具體情況而定,技術上沒什么不同,sidecar 可以綁定生命周期,視為對原有組件的補充。獨立部署則耦合度更低,更靈活。像單節點的 mysql,用 sidecar 則只需要 1 個 pod,不會太復雜。
而如果像多節點的 kafka 集群,用獨立部署則只需要一個 exporter 就可以實現對多個節點的采集監控。
這里出于減小耦合、節省資源的目的,我主要使用的是獨立部署形式。
使用 promtool 檢查指標格式是否正確
promtool 使用方法:
#進入pod $kubectl-n=monitoringexec-itprometheus-k8s-0sh #查看幫助 $promtool-h #檢查指標格式 $curl-shttp://ip:9999/metrics|promtoolcheckmetrics
比方說 指標 name、labelname 不能使用小數點
使用 port-forward 臨時提供 Prometheus 外部訪問
#prometheus $nohupkubectlport-forward--address0.0.0.0service/prometheus-k8s19090:9090-n=monitoring& #grafana $nohupkubectlport-forward--address0.0.0.0service/grafana13000:3000-n=monitoring& #alertmanager $nohupkubectlport-forward--address0.0.0.0service/alertmanager-main9093:9093-n=monitoring&
用 jobs -l 可以查看
kube-prometheus 對 arm 的支持
目標是找到 kube-prometheus 用到的鏡像的 arm 版本。
可以使用 https://quay.io/[6] 搜索。
以下是用到的鏡像和各自對 arm 的支持情況。注意對照自己使用的版本,很多鏡像高版本都支持 arm 了。
-
監控系統
+關注
關注
21文章
3860瀏覽量
173496 -
軟件
+關注
關注
69文章
4770瀏覽量
87157 -
大數據
+關注
關注
64文章
8863瀏覽量
137292
原文標題:kube-prometheus 監控系統使用與總結
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論