1. 寫在前面
個人主頁: https://gzh.readthedocs.io
關注容器技術、關注
Kubernetes
。問題或建議,請公眾號留言。
本系列內容都是基於這個版本的client-go進行講解,不同版本的略有差異。
[root@77DDE94FF07FCC1-wsl /ACode/client-go] git rev-parse HEAD
becbabb360023e1825a48b4db85f454e452ae249
下面簡單羅列一下本文中可能會用提到的一些常用縮寫,詳細的介紹請參考后面的文章(TODO)談起k8s中的GVR我們實際在講什么。
說明
看一下k8s的資源模型:
apiVersion: extensions/v1beta1
kind: ReplicaSet
對於Resource我們可以將之類比於編程語言中的“包”的概念,主要用於區分不同的API,這樣可以有效避免Kinds重名的問題。通常會使用公司的域名等具有獨特明顯區分的字符串作為Resource的值,如:alibaba-inc.com
Version用於區分不同API的穩定程度及兼容性,如:v1beta1, v1
Kind即為API所對應的名字,如:Deployment, Service
2. 代碼結構
從這個包的名字可以很明顯的知道,client-go
其實主要是提供了用戶與k8s交互時使用客戶端,方便大家編程。
個別目錄已過濾掉。
[root@77DDE94FF07FCC1-wsl /ACode/client-go] tree -d -L 1 -I "testing|examples|*_test*|Godeps|third_party|metadata|deprecated|restmapper"
.
├── discovery # 定義DsicoveryClient客戶端。作用是用於發現k8s所支持GVR(Group, Version, Resources)。
├── dynamic # 定義DynamicClient客戶端。可以用於訪問k8s Resources(如: Pod, Deploy...),也可以訪問用戶自定義資源(即: CRD)。
├── informers # k8s中各種Resources的Informer機制的實現。
├── kubernetes # 定義ClientSet客戶端。它只能用於訪問k8s Resources。每一種資源(如: Pod等)都可以看成是一個客端,而ClientSet是多個客戶端的集合,它對RestClient進行了封裝,引入了對Resources和Version的管理。通常來說ClientSet是client-gen來自動生成的。
├── listers # 提供對Resources的獲取功能。對於Get()和List()而言,listers提供給二者的數據都是從緩存中讀取的。
├── pkg
├── plugin # 提供第三方插件。如:GCP, OpenStack等。
├── rest # 定義RestClient,實現了Restful的API。同時會支持Protobuf和Json格式數據。
├── scale # 定義ScalClient。用於Deploy, RS, RC等的擴/縮容。
├── tools # 定義諸如SharedInformer、Reflector、DealtFIFO和Indexer等常用工具。實現client查詢和緩存機制,減少client與api-server請求次數,減少api-server的壓力。
├── transport
└── util # 提供諸如WorkQueue、Certificate等常用方法。
12 directories
3. 代碼使用簡單示例
在對每一部分進行講解前,先用一個圖來講解各部分之間的關系:
對於圖中的每一個帶有標號的部分,下面給出簡單的代碼使用展示, 如果暫時不明白下面的代碼可以先進行下一章節的學習。
3.1 獲取kubeconfig及context
這一部分對應於序號1---tools/clientcmd。
func main() {
var kubeconfig *string
// 默認會從~/.kube/config路徑下獲取配置文件
if home := homeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional)absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()
// 使用k8s.io/client-go/tools/clientcmd生成config的對象
if config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig); err != nil {
panic(err.Error())
}
}
3.2 創建ClientSet
這一部分對應於序號2---ClientSet。
// 使用k8s.io/client-go/kubernetes生成一個ClientSet的客戶端,客戶端生成后,就可以使用這個客戶端與k8s API server進行交互了,如獲取資源列表、Create/Update/Delete資源等
clientset, err := kubenetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
3.3 使用ClientSet獲取集群中的pods
這一部分對應於序號2/3/4---RestClient。
for {
// 使用ClientSet客戶端獲取集群中所有的Pods。其中:ListOptions的結構如下:
// type ListOptions struct {
// TypeMeta `json:",inline"`
// LabelSelector string `json:"labelSelector,omitempty"`
// FieldSelector string `json:"fieldSelector,omitempty"`
//}
pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("Number of pods are: %d\n", len(pods.Items))
}
3.4 使用ClientSet獲取指定的pod
這一部分對應於序號2/3/4---tools/clientcmd。
for {
// 在這里我們從default這個namespace中獲取了名為my-pod的Pod對象
pod, err := clientset.CoreV1().Pods("default").Get("my-pod", metav1.GetOptions{})
if err != nil {
painc(err.Error())
}
fmt.Printf("%v\n\n\n\n", pod.spec)
}
4. 各種Clients詳解
client-go中定義的比較重要的client有:
其中,RestClient是所有客戶端的基礎,后三者都是對RestClient的封裝。RestClient它通過kubeconfig與k8s-api-server進行交互。詳細結構如下圖:
ClientSets使用預生成的API對象
, 這樣的好處是當本地的API對象與k8s-api-server進行交互時會變得比較方便,方便的同時,隨之也帶來了版本與類型強耦合的問題。
DynamicClient則使用unstructured.Unstructured
表示來自API Server的所有對象值。Unstructured
類型是一個嵌套的map[string]inferface{}
值的集合來創建一個內部結構,這一點類似於RESTful API中的Json數據,這樣可以解決ClientSet中出現的強耦合的問題,換句話說,當客戶端的API發生變化時,DynamicClient無需重新編譯。DynamicClient使所有數據實現延時綁定,即只有到運行時才會實現綁定,這意味着程序運行之前,使用DynamicClient
的程序將不會對對象進行Validation,這也是本client的一個缺點。
5. 其它組件
client-go中除了上面提到比較重要的客戶端外, 本庫還包含了各種機制(tools/cache
)。
下圖比較直觀的展示了client-go與customer controller及client-go各組件之間的交互關系,是我們在開發自定義控制器時經常需要使用的機制,了解這個圖有助於我們更好的理解client-go及controller背后的實現邏輯。
如果您對client-go之前就比較了解,建議您移步sample-controller看一下控制器實現的具體代碼。
5.1 Reflector
refelector是定義在包緩存里面的Reflector結構體,可以用於監視指定資源類型(kind)的Kubernetes API。
實現這個功能的函數是ListAndWatch
。監視的對象可以是一個內置的資源,也可以是一個自定義的資源(CRD)。
當reflector通過watch API接收到關於新資源實例存在的通知時,它會使用相應的listing API獲取新創建的對象,並將其放在watchHandler
函數里面的DeltaFIFO
隊列中。
5.2 Informer
它是定義在包緩存中的一個基礎控制器,它可以w使用函數processLoop
從DeltaFIFO
隊列中取出對象。
這個基礎控制器的工作是保存對象以便以后檢索,並調用我們的控制器將對象傳遞給它。
5.3 Indexer
提供對對象的索引功能。它被定義在tools/cache
包中的Indexer
類型中。
一個典型的索引用例是基於對象標簽創建一個索引。Indexer可以基於幾個索引函數來維護索引。Indexer使用一個線程安全的數據存儲來存儲對象和它們的鍵值。
在tools/cache
內的Store
類型中定義了一個名為MetaNamespaceKeyFunc
的默認函數,該函數為該對象生成一個對象的鍵,作為<namespace>/<name>
組合。
5.4 WorkQueue
這是在控制器代碼中創建的隊列,用於將對象的分發與處理解耦。編寫 Resource Event Handler
函數來提取所分發對象的鍵值並將其添加到工作隊列中。
歡迎關注我的微信公眾號: