client-go詳細(xì)介紹
GVR/GVK
kubernetes API時(shí)通過HTTP協(xié)議RESTful的形式提供的,同時(shí)支持JSON和Protobuf的數(shù)據(jù)格式,Protobuf是方便集群內(nèi)部調(diào)用而支持的,我們一般使用JSON格式
在kubernetes API中,一般使用GVR或GVK來區(qū)分特定的資源。根據(jù)不同的分組、版本以及資源進(jìn)行URL的定義。
同時(shí),因?yàn)闅v史原因,API分組分為無域名資源組和有域名資源組。
無域名資源組也被稱為核心資源組 Core Group
有域名資源組
/apis/apps/v1/deployments
無域名資源組
/apis/v1/pods
GVR/GVK含義介紹
G Goup 資源組,包含一組資源操作的集合
V Version 資源版本,用于區(qū)分不同API的穩(wěn)定程度及兼容性
R Resource 資源信息,用于區(qū)分不同的資源API
K Kind 資源對象類型,每個(gè)資源對象都需要Kind來區(qū)分它自身代表的資源類型
接口調(diào)用的時(shí)候,只需要知道GVR即可
GVK相反,通過GVK信息可以獲取要讀取的資源的GVR,進(jìn)而構(gòu)造REST api。
這種GVK和GVR的映射叫做REST mapper。主要作用在ListWatcher時(shí),根據(jù)Schema定義的類型GVK解析出GVR,向APIServer發(fā)起HTTP請求獲取資源,然后Watch。
Client-go簡介
負(fù)責(zé)與APIServer服務(wù)進(jìn)行交互的客戶端庫??梢詫Ω黝愘Y源對象進(jìn)行管理操作,包括內(nèi)置對象和CRD。
開發(fā)流程
1、通過配置創(chuàng)建config對象
2、通過config對象創(chuàng)建對應(yīng)的客戶端對象
3、通過客戶端對象創(chuàng)建informer,并添加對應(yīng)的GVR
4、添加監(jiān)聽事件處理函數(shù)
5、啟動(dòng)informer
Client-go客戶端對象
Client-go提供了4種類型的客戶端對象,分別是RESTClient、DiscoveryClient、ClientSet、DynamicClient。
1、RESTClient:最基礎(chǔ)的客戶端,主要是對HTTP請求進(jìn)行了封裝,支持json和protobuf格式的數(shù)據(jù)
2、DiscoveryClient:發(fā)現(xiàn)客戶端,負(fù)責(zé)發(fā)現(xiàn)APIServer支持的資源組、資源版本和資源信息
3、ClientSet:負(fù)責(zé)操作Kubernetes內(nèi)置的資源對象,如Pod、Service
4、DynamicClient:動(dòng)態(tài)客戶端,可以對任意的Kubernetes資源進(jìn)行通用操作,包括CRD
它和ClientSet主要區(qū)別是,ClientSet是嚴(yán)格結(jié)構(gòu)化定義的,更加安全,DynamicClient是寬松的非結(jié)構(gòu)化的,更加靈活。其返回的對象是map[string]interface{}
RESTClient
RESTClient是其他三個(gè)類型的客戶端的父類,是最基礎(chǔ)的客戶端
提供了對RESTful對應(yīng)方法的封裝,通過這些方法與APIServer進(jìn)行交互,可以操作Kubernetes內(nèi)置的所有類型以及CRD
使用起來比較復(fù)雜,需要配置的參數(shù)過于繁瑣。需要進(jìn)一步封裝
RESTClient請求過程
GET定義請求方式,返回了一個(gè)Request結(jié)構(gòu)體對象,用來構(gòu)建APIServer請求用的
依次執(zhí)行了Namespace、Resource、VersionParams構(gòu)建參數(shù)
Do方法通過Request發(fā)起請求,通過Response解析請求返回?cái)?shù)據(jù)
request先檢查是否有可用的client,沒有使用默認(rèn)的,然后調(diào)用net/http包的功能
ClientSet
一組資源對象客戶端的集合,對內(nèi)置對象進(jìn)行操作
ClientSet請求過程
CoreV1返回Core V1Client實(shí)例對象
Pods調(diào)用了newPods函數(shù),返回PodInterface對象,實(shí)現(xiàn)了對pod對象相關(guān)所有方法。
并將RESTClient賦值給Client對象
List使用RESTClient與Apiserver交互
DynamicClient
動(dòng)態(tài)客戶端,通過動(dòng)態(tài)指定資源組、資源版本和資源等信息,來操作任意的K8s資源對象的客戶端。不僅可以操作內(nèi)置對象,也可以操作CRD
ClientSet種版本與類型緊密耦合,DynamicClient使用嵌套map[string]interface{}結(jié)構(gòu)存儲(chǔ)Apiserver返回值,使用反射機(jī)制,運(yùn)行時(shí),進(jìn)行數(shù)據(jù)綁定。這種方式更靈活,但是無法獲取強(qiáng)數(shù)據(jù)類型的檢查和驗(yàn)證。
DynamicClient請求過程
Resource返回基于gvr生成一個(gè)對應(yīng)資源的資源對象客戶端
Namespace,指定一個(gè)可操作的命名空間
List通過RESTClient調(diào)用k8s Apiserver接口返回?cái)?shù)據(jù),格式是二進(jìn)制,然后轉(zhuǎn)換為對應(yīng)的未結(jié)構(gòu)對象。
DiscoveryClient
前面的對象都是針對資源對象管理的,DiscoveryClient針對GVR的。用于查看當(dāng)前集群支持的資源鉆,資源版本、資源信息。
DiscoveryClient請求過程
ServerGroupResources
ServerGroups負(fù)責(zé)獲取gv數(shù)據(jù),然后通過調(diào)用fetchGroupVersionResources,
接著調(diào)用ServerResourceForGroupVersion方法獲取GV對應(yīng)的Resource數(shù)據(jù)即資源數(shù)據(jù)。
同時(shí)返回一個(gè)map[gv]resourceList數(shù)據(jù)格式,最后做數(shù)據(jù)轉(zhuǎn)換
將GVR緩存到本地
kubernetes本地緩存地址.kube/cache/discovery/master_ip_port/
NewCachedDiscoveryClientForConfig創(chuàng)建一個(gè)客戶端
ServerGroupsAndResource獲取數(shù)據(jù)并緩存。從緩存文件中找,有直接返回,沒有調(diào)用APIServer獲取GVR數(shù)據(jù),將獲取到的數(shù)據(jù)緩存到本地,返回給客戶端
Informer

informer負(fù)責(zé)與Kubernetes APIServer進(jìn)行Watch操作。資源可以是內(nèi)置對象也可以是CRD
informer是一個(gè)帶有本地緩存以及索引機(jī)制的核心工具包,當(dāng)請求為查詢操作時(shí),優(yōu)先從本地緩存中查找數(shù)據(jù),而創(chuàng)建、更新、刪除這類操作,根據(jù)事件通知寫入到隊(duì)列DeltaFIFO,同時(shí)對應(yīng)事件處理過后,更新本地緩存,使本地緩存與ETCD數(shù)據(jù)保持一致。
Informer組件
Reflector:使用List-Watch來保證本地緩存數(shù)據(jù)的準(zhǔn)確性、順序性和一致性。List對應(yīng)資源的全量列表數(shù)據(jù),Watch負(fù)責(zé)變化部分的數(shù)據(jù)。監(jiān)聽對應(yīng)的事件并將資源對象變化存放到本地隊(duì)列DeltaFIFO中
DeltaFIFO:增量隊(duì)列,記錄資源變化的過程。Reflector是生產(chǎn)者。
Indexer:用來存儲(chǔ)資源對象并自帶索引功能的本地存儲(chǔ)。Reflector從DeltaFIFO中將消費(fèi)出來的資源對象存儲(chǔ)到Indexer,Indexer數(shù)據(jù)與etcd保持一致。從而client-go可以本地讀取,減少APIServer數(shù)據(jù)交互壓力。
Reflector
List-Watch
List負(fù)責(zé)調(diào)用資源對應(yīng)的RESTfulAPI接口獲取全局?jǐn)?shù)據(jù)列表,并同步到本地緩存中。是短鏈接
Watch負(fù)責(zé)監(jiān)聽資源的變化,并調(diào)相應(yīng)事件處理函數(shù)進(jìn)行處理,同時(shí)更新本地緩存,使本地緩存與etcd數(shù)據(jù)保持一致。是長鏈接。
定時(shí)同步
定時(shí)器定時(shí)觸發(fā)同步機(jī)制,定時(shí)更新緩存數(shù)據(jù)
Reflector組件對于數(shù)據(jù)更新同步,都是基于ResourceVersion進(jìn)行的,數(shù)據(jù)變化時(shí),會(huì)遞增更新。保證事件順序性
ResourceVersion根據(jù)需求,進(jìn)行配置
未設(shè)置,從最新版本開始監(jiān)聽
設(shè)置為0,從任意版本開始監(jiān)聽,首選可用最新的,但不是必須,可能返回陳舊數(shù)據(jù)
從指定版本監(jiān)聽
DeltaFIFO
1、FIFO:是一個(gè)隊(duì)列,擁有隊(duì)列基本方法
2、Delta:是一個(gè)資源對象本地緩存,保存存儲(chǔ)對象的消費(fèi)類型,如Added,Updated、Deleted等,包括Type即事件類型,Object資源對象數(shù)據(jù)
indexer
本身是一個(gè)存儲(chǔ),在存儲(chǔ)基礎(chǔ)上擴(kuò)展了索引功能
Reflector通過DeltaFIFO系列操作后,更新存儲(chǔ)到Indexer中。數(shù)據(jù)與etcd完全一致
IndexFunc:索引器函數(shù),用于計(jì)算資源對象索引值列表,可以自定義
Index:存儲(chǔ)數(shù)據(jù),查找某個(gè)命名空間下pod,就讓pod按照命名空間進(jìn)行索引
Indexers:存儲(chǔ)索引器,key為索引器名稱,value為IndexFunc
Indices:存儲(chǔ)緩存器,key為索引器名稱,value為緩存數(shù)據(jù)
Indexers是存儲(chǔ)索引,Indices是存儲(chǔ)數(shù)據(jù)
threadSafeMap并發(fā)安全存儲(chǔ)
Cache
SharedInformer
一個(gè)資源收到多個(gè)控制器管理,可以通過SharedInformer來創(chuàng)建一份供多個(gè)控制器共享的緩存
SharedInformer是一個(gè)接口,包含添加事件,當(dāng)有資源變化時(shí),會(huì)回調(diào)通知使用者,啟動(dòng)函數(shù)以及獲取全量對象是否已經(jīng)同步到本地存儲(chǔ)中。
擴(kuò)展
Watch事件通知模式
Etcd v2 輪詢
Etcd v2 Watch機(jī)制采用HTTP/1.x實(shí)現(xiàn),每個(gè)Watcher對應(yīng)一個(gè)TCP連接。Client通過HTTP/1.x長連接定時(shí)輪詢Server,獲取最新的數(shù)據(jù)變化事件。Watcher數(shù)量很多時(shí),大量輪詢也會(huì)導(dǎo)致Server消耗大量的Socket,內(nèi)存等資源,導(dǎo)致Etcd的擴(kuò)展性和穩(wěn)定性變差;
Etcd v3 流式推送
Etcd v3基于HTTP/2的gRPC協(xié)議,雙向流的Watch API設(shè)計(jì),實(shí)現(xiàn)了連接多路復(fù)用。同時(shí)事件通知模式也從client輪詢優(yōu)化為server流式推送
如何實(shí)現(xiàn)
消息可靠性
消息實(shí)時(shí)性
消息順序性
高性能
1、可靠性
通過list調(diào)用獲取所有資源數(shù)據(jù),watch獲取增量數(shù)據(jù),兩者結(jié)合保證可靠性。
2、實(shí)時(shí)性
list-watch機(jī)制下,每當(dāng)apiserver的資源產(chǎn)生狀態(tài)變更事件,都會(huì)將事件及時(shí)的推送給客戶端,從而保證消息的實(shí)時(shí)性
3、順序性
K8S在每個(gè)資源的事件中都帶一個(gè)resourceVersion的標(biāo)簽,這個(gè)標(biāo)簽是遞增的數(shù)字,所以當(dāng)客戶端并發(fā)處理同一個(gè)資源的事件時(shí),它就可以對比resourceVersion來保證最終的狀態(tài)和最新的事件所期望的狀態(tài)保持一致。
4、高性能
List-watch通過異步通知達(dá)到高性能的特點(diǎn)。watch作為異步消息通知機(jī)制,復(fù)用一條長鏈接,保證實(shí)時(shí)性的同時(shí)也保證了性能。
異常重試機(jī)制
etcd中watcher的channel緩沖區(qū)滿了之后,會(huì)將其標(biāo)記為slow watcher,然后通過異步機(jī)制重試保證事件可靠性。失敗則加到隊(duì)列。成功,根據(jù)版本號對比決定將slower watcher轉(zhuǎn)化為unsynced watcher或者synced watcher。
不斷遍歷unsynced watcher,批量找出某個(gè)key的一批watcher監(jiān)聽的最小版本,遍歷獲取key歷史版本轉(zhuǎn)化為事件發(fā)送給對應(yīng)watcher的channel。
推送完成后將unsynced watcher轉(zhuǎn)換為synced watcher
如果客戶端的最新版本號小于緩沖區(qū)最小版本號,說明部分?jǐn)?shù)據(jù)丟失了,需要list重新獲取最新的數(shù)據(jù),然后再次watch。