做者 | 夙興 阿里巴巴高級工程師node
本文整理自《CNCF x Alibaba 雲原生技術公開課》第 24 講,點擊「閱讀原文」直達課程頁面。git
關注「阿里巴巴雲原生」公衆號,回覆關鍵詞「入門」,便可下載從零入門 K8s 系列文章 PPT。github
導讀:本文將從實踐出發,結合案例來講明,如何藉助 Operator 開發框架來擴展 Kubernetes API。內容主要分爲三個部分:首先會簡單介紹一下 Operator 相關的知識;而後會介紹 Operator 開發框架並結合案例來詳細說明整個開發過程;最後會結合案例的工做流程來從新說明 Operator 是如何工做的。web
首先介紹一下本文內容所涉及到的基本概念。數據庫
按照處理類型的不一樣,通常能夠將其分爲兩類:一類可能會修改傳入對象,稱爲 mutating webhook;一類則會只讀傳入對象,稱爲 validating webhook。api
工做流程:app
這裏是從 High-Level 大概介紹一下,後面會結合案例從新梳理。框架
在開始以前,首先介紹一下 operator framework。 它實際上給用戶提供了 webhook 和 controller 的框架,它的主要意義在於幫助開發者屏蔽了一些通用的底層細節,不須要開發者再去實現消息通知觸發、失敗從新入隊等,只需關注被管理應用的運維邏輯實現便可。less
主流的 operator framework 主要有兩個:kubebuilder 和 operator-sdk。 運維
二者實際上並無本質的區別,它們的核心都是使用官方的 controller-tools 和 controller-runtime。不過細節上稍有不一樣,好比 kubebuilder 有着更爲完善的測試與部署以及代碼生成的腳手架等;而 operator-sdk 對 ansible operator 這類上層操做的支持更好一些。
這裏的實戰選用的是 kuberbuilder。案例選用的是阿里雲對外開放的 kruise 項目下的 SidercarSet。
SidercarSet 的功能就是負責給 Pod 插入 sidecar 容器(也稱爲輔助容器),例如能夠插入一些監控,日誌採集來豐富這個 Pod 的功能,而後根據插入的狀態、Pod 的狀態反過來更新 SidercarSet 以記錄這些輔助容器的狀態。
操做:新建一個 gitlab 項目,運行 "kubebuilder init --domain=kruise.io"。
參數解讀:domain 指定了後續註冊 CRD 對象的 Group 域名。
效果解讀:拉取依賴代碼庫、生成代碼框架、生成 Makefile/Dockerfile 等工具文件。
咱們來看一下它具體生成的內容_(爲了方便演示,實際生成文件作了部分刪減):
具體的內容你們能夠在實戰的時候本身進行詳細的確認。
操做:運行 "kubebuilder create api --group apps --version v1alpha1 --kind SidecarSet --namespace=false"
實際上不只會建立 API,也就是 CRD,還會生成 Controller 的框架。
參數解讀:- group 加上以前的 domian 即此 CRD 的 Group: apps.kruise.io;
version 通常分三種,按社區標準:
它的參數基本能夠分爲兩類。group, version, kind 基本上對應了 CRD 元信息的三個重要組成部分。這裏給出了一些常見的標準,你們實際使用的時候能夠參考一下。namespaced 則用於指定咱們剛剛建立的 CRD 時全局惟一的(如 node)仍是 namespace 惟一的(如 Pod)。這裏用了 false,即指定 SidecarSet 爲全局惟一的。
效果解讀:
生成了 CRD 和 controller 的框架,後面須要手工填充代碼。
實際結果以下圖所示:
咱們重點關注是圖中藍色字體部分。sidecarset_types.go 就是定義 CRD 的地方,須要咱們填充。sidecarset_controller.go 則用於定義 controller,一樣須要進行填充。
1. 生成的 CRD 位於 "pkg/apis/apps/v1alpha1/sidecarset_types.go",一般須要進行以下兩個操做:
(1) 調整註釋
code generator 依賴註釋生成代碼,所以有時須要調整註釋。如下列出了本次實戰中 SidecarSet 須要調整的註釋:
+genclient:nonNamespaced: 生成非 namespace 對象;
+kubebuilder:subresource:status: 生成 status 子資源;
+kubebuilder:printcolumn:name="MATCHED",type='integer',JSONPath=".status.matchedPods",description="xxx": kubectl get sidecarset: 後續展現相關。
(2) 填充字段
填充字段是令用戶的 CRD 實際生效、實際有意義的重要部分。
2. 填充完運行 make 從新生成代碼便可
須要注意的是,研發人員無需參與 CRD 的 grpc 接口、編解碼等 controller 的底層實現。
實際的填充以下圖所示:
SidecarSet 的功能是給 Pod 注入 Sidecar,爲了完成該功能,咱們在 SidecarSetSpec(左圖) 定義了兩個主要信息:一個是用於選擇哪些 Pod 須要被注入的 Selector;一個是定義 Sidecar 容器的 Containers。
在 SidecarSetStatus(右圖)中定義了狀態信息,MatchedPods 反映的是該 SidecarSet 實際匹配了多少 Pod,UpdatedPods 反映的是已經注入了多少,ReadyPods 反映的則是有多少 Pod 已經正常工做了。
完整的內容能夠參考該文檔。
1. 生成 mutating webhook,運行:
"kubebuilder alpha webhook --group apps --version v1alpha1 --kind SidecarSet --type=mutating --operations=create"
"kubebuilder alpha webhook --group core --version v1 --kind Pod --type=mutating --operations=create"
2. 生成 validating webhook,運行:
"kubebuilder alpha webhook --group apps --version v1alpha1 --kind SidecarSet --type=validating --operations=create,update"
參數解讀:
效果解讀:
實際生成結果以下圖所示:
咱們執行了三條命令,分別生成了三個不一樣的須要填充的 handler 中(上圖藍色字體部分)。這裏先不提,在下一步填充操做中再對其詳細講解。
生成的 webhook handler 分別位於:
須要改寫、填充的通常包括如下兩個部分:
咱們來看一下實際的填充結果。
由於第四步咱們定義了三個:sidecarset mutating、sidecarset mutaing、pod mutating。
先來看上圖左側的 sidecarset mutating,首先是 setDefaultSidecarSet 把默認值設置好,這也是 mutaing 最常作的事情。
上圖右側 validating 也是很是的標準,也是對 SidecarSet 一些字段進行校驗。
關於 pod mutaing 這裏沒有作展現,這裏面有些不一樣,這裏面的 mutaingSidecarSetFn 不是進行默認值設置,而是獲取 setDefaultSidecarSet 的數值,而後注入到 Pod 裏面。
生成的 controller 框架位於 pkg/controller/sidecarset/sidecarset_controller.go。主要有三點須要進行修改:
咱們來看一下 SidecarSet 的 Controller 的填充結果:
addPod 中先取回該 Pod 對應的 SidecarSet 並將其加入隊列以便 Reconcile 進行處理。
Reconcile 將 SidercarSet 取出以後,根據 Selector 選擇匹配的 Pod,最後根據 Pod 當前的狀態信息計算出集羣的狀態,而後回填到 CRD 的狀態中。
最後咱們再來從新梳理一下 SidecarSet 的工做流程以便咱們理解 operator 是如何工做的。
以上就是 SidecarSet 前期一個簡單的功能實現。
這裏咱們再補充一個問題。通常的 webhook 由 controller 來完成業務邏輯、狀態更新,但這個不是必定的,二者之一能夠不是必須的。在以上的示例中就是由 webhook 完成主要的業務邏輯,無需 controller 的參與。
本文的主要內容就到此爲止了,這裏爲你們簡單總結一下:
「 阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的技術圈。」