kubebuilder實戰之三:基礎知識速覽

程式設計師欣宸發表於2021-08-27

歡迎訪問我的GitHub

https://github.com/zq2599/blog_demos

內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等;

系列文章連結

  1. kubebuilder實戰之一:準備工作
  2. kubebuilder實戰之二:初次體驗kubebuilder
  3. kubebuilder實戰之三:基礎知識速覽
  4. kubebuilder實戰之四:operator需求說明和設計
  5. kubebuilder實戰之五:operator編碼
  6. kubebuilder實戰之六:構建部署執行
  7. kubebuilder實戰之七:webhook
  8. kubebuilder實戰之八:知識點小記

本篇概覽

  • 作為《kubebuilder實戰》系列的第三篇,本該進入真槍實彈的operator開發環節,卻突然發現kubebuilder涉及的知識點太多太零散,如果現在就敲命令寫程式碼去實戰,即便完成了一次operator開發,但缺失大量資訊(例如操作順序怎麼安排、步驟之間如何關聯等),不但《kubebuilder實戰》系列失去參考價值,過幾個月就連我自己都看不懂這些內容了,因此,本篇暫緩實戰,我們們一起對kubebuilder開發過程中的知識點做一次速記,再從容的啟動開發工作;
  • 特別說明:webhook是operator中的重要功能,其理論和實戰都需要大量篇幅,因此後面會有這方面專門的文章,本文不會涉及webhook的知識點;
  • 接下來,大串講開始;

知識儲備

  • 能看懂kubebuilder官方demo的程式碼、會用client物件操作kubernetes資源,以上兩點是勝任operator開發的最基本要求,否則在開發過程中會有種寸步難行的感覺,達到這些條件需要少量的知識儲備,現在欣宸已經為您準備好了,希望您能簡單瀏覽一下:
  1. 《Kubernetes的Group、Version、Resource學習小記》
  2. 《client-go實戰之一:準備工作》
  3. 《client-go實戰之二:RESTClient》
  4. 《client-go實戰之三:Clientset》
  5. 《client-go實戰之四:dynamicClient》
  6. 《client-go實戰之五:DiscoveryClient》

初始化相關知識點

mkdir -p $GOPATH/src/helloworld
cd $GOPATH/src/helloworld
kubebuilder init --domain com.bolingcavalry
  • 在用上module之後,大家已經脫離了$GOPATH的束縛,像上面那樣中規中矩的去$GOPATH/src下面操作就略有些彆扭了,來試試不用$GOPATH的初始化方式;
  1. 隨處新建一個目錄(路徑中不要有中文和空格),例如/Users/zhaoqin/temp/202102/15/elasticweb
  2. 在目錄中用go mod init elasticweb命令新建名為elasticweb的工程;
  3. 再執行kubebuilder init --domain com.bolingcavalry,即可新建operator工程;

基礎設施

  • operator工程新建完成後,會新增不少檔案和目錄,以下幾個是官方提到的基礎設施
  1. go.mod:module的配置檔案,裡面已經填充了幾個重要依賴;
  2. Makefile:非常重要的工具,前文我們們也用過了,編譯構建、部署、執行都會用到;
  3. PROJECT:kubebuilder工程的後設資料,在生成各種API的時候會用到這裡面的資訊;
  4. config/default:基於kustomize製作的配置檔案,為controller提供標準配置,也可以按需要去修改調整;
  5. config/manager:一些和manager有關的細節配置,例如映象的資源限制;
  6. config/rbac:顧名思義,如果像限制operator在kubernetes中的操作許可權,就要通過rbac來做精細的許可權配置了,這裡面就是許可權配置的細節;

main.go

  • main.go是kubebuilder自動生成的程式碼,這是operator的啟動程式碼,裡面有幾處值得注意:
  1. 兩個全域性變數,如下所示,setupLog用於輸出日誌無需多說,scheme也是常用的工具,它提供了Kind和Go程式碼中的資料結構的對映,:
var (
	scheme   = runtime.NewScheme()
	setupLog = ctrl.Log.WithName("setup")
)
  1. 另外還有些設定,例如監控指標相關的,以及管理controller和webhook的manager,它會一直執行下去直到被外部終止,關於這個manage還有一處要注意的地方,就是它的引數,下圖是預設的引數,如果您想讓operator在指定namespace範圍內生效,還可以在下午的地方新增Namespace引數,如果要指定多個nanespace,就使用cache.MultiNamespacedCacheBuilder(namespaces)引數:

在這裡插入圖片描述

  • main.go的內容在大多數場景無需改動,瞭解即可,接下來的API是重頭戲;

API相關(資料核心)

  • API是operator的核心,當您決定使用operator時,就應該從真實需求出發,開始設計整個CRD,而這些設計最終體現在CRD的資料結構,以及對真實值和期望值的處理邏輯中;
  • 在《kubebuilder實戰之二:初次體驗kubebuilder》我們們建立過API,當時的命令是:
kubebuilder create api \
--group webapp \
--version v1 \
--kind Guestbook
    • kubebuilder自動新增了很多內容,如下圖,都是為了這個CRD服務的:

在這裡插入圖片描述

    • 新增的內容中,最核心的當然是CRD了,也就是上圖中Guestbook資料結構所在的guestbook_types.go檔案,這個最重要的資料結構如下:
type Guestbook struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   GuestbookSpec   `json:"spec,omitempty"`
	Status GuestbookStatus `json:"status,omitempty"`
}
  1. metav1.TypeMeta:儲存了資源的Group、Version、Kind
  2. metav1.ObjectMeta:儲存了資源物件的名稱和namespace
  3. Spec:期望狀態,例如deployment在建立時指定了pod有三個副本
  4. Status:真實狀態,例如deployment在建立後只有一個副本(其他的還沒有建立成功),大多數資源物件都有此欄位,不過ConfigMap是個例外(想想也是,配置資訊嘛,配成啥就是啥,沒有什麼期望值和真實值的說法);
  • 還有一個資料結構,就是Guestbook對應的列表GuestbookList,就是單個資源物件的集合;
  • guestbook_types.go所在目錄下還有兩個檔案:groupversion_info.go定義了Group和Version,以及註冊到scheme時用到的例項SchemeBuilder,zz_generated.deepcopy.go用於實現例項的深拷貝,它們都無需修改,瞭解即可;

controller相關(業務核心)

  • 前面聊過了資料核心,接下來要討論如何實現業務需求了,在operator開發過程中,儘管業務邏輯各不相同,但有兩個共性:
  1. Status(真實狀態)是個資料結構,其欄位是業務定義的,其欄位值也是業務程式碼執行自定義的邏輯算出來的;
  2. 業務核心的目標,是確保Status與Spec達成一致,例如deployment指定了pod的副本數為3,如果真實的pod沒有三個,deployment的controller程式碼就去建立pod,如果真實的pod超過了三個,deployment的controller程式碼就去刪除pod;
  • 以上就是我們們的controller要做的事情,接下來看看程式碼的細節,kubebuilder建立的guestbook_controller.go就是controller,我們們的業務程式碼都寫在這個檔案中,來看看kubebuilder幫我們準備了什麼:
  1. 資料結構定義,如下所示,操作資源物件時用到的客戶端工具client.Client、日誌工具、Kind和資料結構的關係Scheme,這些都幫我們準備好了,真貼心:
type GuestbookReconciler struct {
	client.Client
	Log    logr.Logger
	Scheme *runtime.Scheme
}
  1. SetupWithManager方法,在main.go中有呼叫,指定了Guestbook這個資源的變化會被manager監控,從而觸發Reconcile方法:
func (r *GuestbookReconciler) SetupWithManager(mgr ctrl.Manager) error {
	return ctrl.NewControllerManagedBy(mgr).
		For(&webappv1.Guestbook{}).
		Complete(r)
}
  1. 如下圖,Reconcile方法前面有一些+kubebuilder:rbac字首的註釋,這些是用來確保controller在執行時有對應的資源操作許可權,例如紅框中就是我自己新增的,這樣controller就有權查詢pod資源物件了:

在這裡插入圖片描述

  • guestbook_controller.go是operator的業務核心,而controller的核心是其Reconcile方法,將來我們們的大部分程式碼都是寫在這裡面的,主要做的事情就是獲取status,然後讓status和spec達成一致;
  • 關於status,官方的一段描述值得重視,如下圖紅框,主要是說資源物件的狀態應該是每次重新計算出來的,這裡以deployment為例,想知道當前有多少個pod,有兩種方法,第一種準備個欄位記錄,每次對pod的增加和刪除都修改這個欄位,於是讀這個欄位就知道pod數量了,第二種方法是每次用client工具去實時查詢pod數量,目前官方明確推薦使用第二種方法

在這裡插入圖片描述

  • 至此,基礎知識串講就完成了,我們們按照官方資料的順序把知識點過了一遍,接下來,就是按照官方資料的順序去實戰了,讓大家久等了,下一篇,operator實戰;

你不孤單,欣宸原創一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 資料庫+中介軟體系列
  6. DevOps系列

歡迎關注公眾號:程式設計師欣宸

微信搜尋「程式設計師欣宸」,我是欣宸,期待與您一同暢遊Java世界...
https://github.com/zq2599/blog_demos