【云原生 ? Prometheus】云原生kubernetes服務(wù)發(fā)現(xiàn)原理圖解
云原生kubernetes服務(wù)發(fā)現(xiàn)原理圖解
(資料圖片)
概述
上節(jié)分析了Prometheus
服務(wù)發(fā)現(xiàn)核心流程(如下圖),Discoverer
基于不同協(xié)議發(fā)現(xiàn)采集點,通過channel
通知到updater
協(xié)程,然后更新到discoveryManager
結(jié)構(gòu)體trargets
字段中,最終由sender
協(xié)程將discoveryManager
的targets
字段數(shù)據(jù)發(fā)送給scrape
采集模塊。
Discoverer
定義的接口類型,不同的服務(wù)發(fā)現(xiàn)協(xié)議基于該接口進行實現(xiàn):
type Discoverer interface { // Run hands a channel to the discovery provider (Consul, DNS, etc.) through which // it can send updated target groups. It must return when the context is canceled. // It should not close the update channel on returning. Run(ctx context.Context, up chan<- []*targetgroup.Group)}
k8s協(xié)議配置
Prometheus
本身就是作為云原生監(jiān)控出現(xiàn)的,所以對云原生服務(wù)發(fā)現(xiàn)支持具有天然優(yōu)勢。kubernetes_sd_configs
服務(wù)發(fā)現(xiàn)協(xié)議核心原理就是利用API Server
提供的Rest接口
獲取到云原生集群中的POD
、Service
、Node
、Endpoints
、Endpointslice
、Ingress
等對象的元數(shù)據(jù),并基于這些信息生成Prometheus
采集點,并且可以隨著云原生集群狀態(tài)變更進行動態(tài)實時刷新。
?
kubernetes
云原生集群的POD
、Service
、Node
、Ingress
等對象元數(shù)據(jù)信息都被存儲到etcd
數(shù)據(jù)庫中,并通過API Server
組件暴露的Rest
接口方式提供訪問或操作這些對象數(shù)據(jù)信息。 ?
「kubernetes_sd_configs
配置示例:」
- job_name: kubernetes-pod kubernetes_sd_configs: - role: pod namespaces: names: - "test01" api_server: https://apiserver.simon:6443 bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token tls_config: ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
配置說明:
api_server
指定API Server
地址,出于安全考慮,這些接口是帶有安全認證的,bearer_token_file
和ca_file
則指定訪問API Server
使用到的認證信息;role
指定基于云原生集群中哪種對象類型做服務(wù)發(fā)現(xiàn),支持POD
、Service
、Node
、Endpoints
、Endpointslice
、Ingress
六種類型;namespaces
指定作用于哪個云原生命名空間下的對象,不配置則對所有的云原生命名空間生效;「為什么沒有配置api server信息也可以正常進行服務(wù)發(fā)現(xiàn)?」
很多時候我們并不需要配置api server
相關(guān)信息也可以進行服務(wù)發(fā)現(xiàn),如我們將上面示例簡化如下寫法:
- job_name: kubernetes-pod kubernetes_sd_configs: - role: pod namespaces: names: - "test01"
一般Prometheus
部署在監(jiān)控云原生集群上,從 Pod
使用 Kubernetes API
官方客戶端庫(client-go
)提供了更為簡便的方法:rest.InClusterConfig()
。 API Server
地址是從POD
的環(huán)境變量KUBERNETES_SERVICE_HOST
和KUBERNETES_SERVICE_PORT
構(gòu)建出來, token
以及 ca
信息從POD
固定的文件中獲取,因此這種場景下kubernetes_sd_configs
中api_server
和ca_file
是不需要配置的。
?
client-go
是kubernetes
官方提供的go
語言的客戶端庫,go
應(yīng)用使用該庫可以訪問kubernetes
的API Server
,這樣我們就能通過編程來對kubernetes
資源進行增刪改查操作。 ?
Informer機制
從之前分析的服務(wù)發(fā)現(xiàn)協(xié)議接口設(shè)計得知,了解k8s
服務(wù)發(fā)現(xiàn)協(xié)議入口在discovery/kubernetes.go
的Run
方法:
Run
方法中switch
羅列出不同role
的處理邏輯,剛好和配置示例中role
支持的六種云原生對象類型對應(yīng),只是基于不同的對象進行服務(wù)發(fā)現(xiàn),基本原理都是一致的。
云原生服務(wù)發(fā)現(xiàn)基本原理是訪問API Server
獲取到云原生集群資源對象,Prometheus
與API Server
進行交互這里使用到的是client-go
官方客戶端里的Informer
核心工具包。Informer
底層使用ListWatch
機制,在Informer
首次啟動時,會調(diào)用List API
獲取所有最新版本的資源對象,緩存在內(nèi)存中,然后再通過Watch API
來監(jiān)聽這些對象的變化,去維護這份緩存,降低API Server
的負載。除了ListWatch
,Informer
還可以注冊自定義事件處理邏輯,之后如果監(jiān)聽到事件變化就會調(diào)用對應(yīng)的用戶自定義事件處理邏輯,這樣就實現(xiàn)了用戶業(yè)務(wù)邏輯擴展。
Informer
機制工作流程如下圖:
Informer
機制本身比較復(fù)雜,這里先暫時不太具體說明,只需要理解Prometheus
使用Informer
機制獲取和監(jiān)聽云原生資源對象,即上圖中只有「綠色框部分是自定義業(yè)務(wù)邏輯」,其它都是client-go
框架informer
工具包提供的功能。
這其中的關(guān)鍵就是注冊自定義AddFunc
、DeleteFunc
和UpdateFunc
三種事件處理器,分別對應(yīng)增、刪、改操作,當(dāng)觸發(fā)對應(yīng)操作后,事件處理器就會被回調(diào)感知到。比如云原生集群新增一個POD
資源對象,則會觸發(fā)AddFunc
處理器,該處理器并不做復(fù)雜的業(yè)務(wù)處理,只是將該對象的key
放入到Workqueue
隊列中,然后Process Item
組件作為消費端,不停從Workqueue
中提取數(shù)據(jù)獲取到新增POD
的key
,然后交由Handle Object
組件,該組件通過Indexer
組件提供的GetByKey()
查詢到該新增POD
的所有元數(shù)據(jù)信息,然后基于該POD
元數(shù)據(jù)就可以構(gòu)建采集點信息,這樣就實現(xiàn)kubernetes
服務(wù)發(fā)現(xiàn)。
「為什么需要Workqueue隊列?」
Resource Event Handlers
組件注冊自定義事件處理器,獲取到事件時只是把對象key
放入到Workerqueue
中這種簡單操作,而沒有直接調(diào)用Handle Object
進行事件處理,這里主要是避免阻塞影響整個informer
框架運行。如果Handle Object
比較耗時放到Resource Event Handlers
組件中直接處理,可能就會影響到④⑤功能,所以這里引入Workqueue
類似于MQ
功能實現(xiàn)解耦。
源碼分析
熟悉了上面Informer機制
,下面以role=POD
為例結(jié)合Prometheus
源碼梳理下上面流程。
1、創(chuàng)建和API Server
交互底層使用的ListWatch
工具;
2、基于ListWatch
創(chuàng)建Informer
;
3、注冊資源事件,分別對應(yīng)資源創(chuàng)建、資源刪除和資源更新事件處理;
? 這里的
podAddCount
、podDeleteCount
和podUpdateCount
分別對應(yīng)下面三個指標(biāo)序列,指標(biāo)含義也比較明顯:prometheus_sd_kubernetes_events_total(role="pod", event="add")
prometheus_sd_kubernetes_events_total(role="pod", event="delete")
prometheus_sd_kubernetes_events_total(role="pod", event="update")
role
標(biāo)識資源類型,包括:"endpointslice", "endpoints", "node", "pod", "service", "ingress"
五種類型;event
標(biāo)識事件類型,包括:"add", "delete", "update"
三種類型。 ?
4、事件處理,AddFunc
、DeleteFunc
和UpdateFunc
注冊的事件處理邏輯一樣,處理邏輯也比較簡單:就是獲取資源對象key
,并將其寫入到Workqueue
中;
? 對于
POD
資源,這里的key
就是:namespace/pod_name
格式,比如key=test01/nginx-deployment-5ffc5bf56c-n2pl8
。 ?
5、給Workqueue
注冊一個無限循環(huán)處理邏輯,就能持續(xù)從Workqueue
中取出key
進行處理;
? 針對
Pod
里的每個Container
上的每個port
,都會生成一個對應(yīng)采集點target
,其中__address__
就是PodIP
+port
組合。 ?
6、最后啟動Informer
,讓整個流程運轉(zhuǎn)起來;
標(biāo)簽: