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