K8S教程:使用kubebuilder开发简单的Operator
云原生技術通過方法論、工具集和最佳實踐重塑著整個軟件技術棧和生命周期,云原生對云計算服務方式與互聯網架構進行整體性升級, 深刻改變著整個 IT 領域。云原生的核心是 kubernetes,圍繞 kubernetes 構建滿足自身需求的 PaaS 平臺(應用中心)是絕大數企業的訴求, 但是不同企業自身場景往往存在一定的差異,Operator 是最常見 kubernetes 拓展方式。本片博文,我將會給大家理清 Operator 的來龍去脈, 同時介紹如何通過 kubebuilder 快速開發一個簡單的 Operator。
Operator 誕生的背景
kubernetes 無法做到真正意義的開箱即用的,它與傳統的 PaaS 平臺不同,它僅僅只提供核心的基礎設施功能,但是還無法滿足用戶的最終需求,這里用戶主要指業務開發和業務運維, 比如說業務開發需要 CI/CD 工具實現 Devops 的功能,原生 kubernetes 是不提供支持的,但是我們可以通過tekton這一個第三方工具實現 DevOps 相關功能, 這也正是 kubernetes 區別傳統PaaS平臺的真正強大之處,其提供完善的擴展機制以及基于此而發展出來的海量的第三方工具和豐富的生態。
Operator pattern首先由 CoreOS 提出,通過結合 CRD 和 custom controller 將特定應用的運維知識轉換為代碼,實現應用運維的自動化和智能化。Operator 允許 kubernetes 來管理復雜的,有狀態的分布式應用程序,并由 kubernetes 對其進行自動化管理,例如,etcd operator 能夠創建并管理一組 etcd 集群, 定制化的 controller 組件了解這些資源,知道如何維護這些特定的應用。
隨著 kubernetes 的功能越來越復雜,其需要管理的資源在高速增長,對應的 API 和 controller 的數量也愈發無法控制, kubernetes 變得很臃腫,很多不必要的 API 和功能將出現在每次安裝的集群中。
為了解決這個問題,CRD 應運而生,CRD 由 TPR(Third Part Resource v1.2 版本引入)演化而來,v1.7 進入 beta,v1.8 進入穩定, 通過 CRD,kubernetes 可以動態的添加并管理資源。CRD 解決了結構化數據存儲的問題,Controller 則用來跟蹤這些資源, 保證資源的狀態滿足期望值。CRD+Controller=decalartive API,聲明式 API 設計是 kubernetes 重要的設計思想, 該設計保證能夠動態擴展 kubernetes API,這種模式也正是 Operator pattern。
kubernetes 本身也在通過 CRD 添加新功能,我們有什么理由不使用呢?
使用場景總結及舉例
CRD+custom controller 已經被廣泛地使用,按使用場景可劃分為以下兩種:
通用型 controller 往往是 kubernetes 平臺側用戶,如各大云廠商和 kubernetes 服務提供商,Operator 則是各種軟件服務提供商, 他們設計時面向單一應用,很多開源的應用的 operator 可以在 operator hub 中獲取。我列舉一些示例供大家參考:
通用型 Controller
Operator
通用型Controller與kubernetes自帶的幾個controller類似,旨在解決一些通用的應用模型,而Operator則更加面向單個特定應用, 這兩者沒有本質的區別。
如何開發 CRD
作為kubernetes開發者,如何開發 CRD+Custom cntroller 呢?其實官方提供示例項目sample-controller供開發者參考,開發流程大致有以下幾個過程:
其中步驟 2,5 是核心業務邏輯,其余步驟完全可以通過自動生成的方式省略,到目前,社區有兩個成熟的腳手架工具用于簡化開發,一個是有 kube-sig 維護的 kubebuilder, 另一個是由 redhat 維護的 operator-sdk,這兩個工具都是基于 controller-runtime 項目而實現,用戶可自行選擇,筆者用的是 kubebuilder。使用 kubebuilder 能夠幫助我們節省以下工作:
如果你想要快速構建 CRD 和 Custom controller,腳手架工具是個不錯的選擇,如果是學習目的,建議結合 sample-controller 和 kubernetes controller 相關 源碼。
kubebuilder 詳解
kubebuilder 是一個幫助開發者快速開發 kubernetes API 的腳手架命令行工具,其依賴庫 controller-tools 和 controller-runtime, controller-runtime 簡化 kubernetes controller 的開發,并且對 kubernetes 的幾個常用庫進行了二次封裝, 以簡化開發者使用。controller-tool 主要功能是代碼生成。下圖是使用 kubebuilder 的工作流程圖:
文章后面會結合一個簡單示例來介紹開發流程。
“
kubebuilder 有非常良好的文檔,包括一個從零開始的示例,您應該以文檔為主。
”
使用 kubebuilder 開發一個 CRD
本次示例創建一個通用的Application資源,Application 包含一個子資源 Deployment 以及一個 Count 資源, 每當 Application 進行被重新協調Reconcil,Count 會進行自增。
“
全部代碼請參考代碼倉
”
前提(你需要提前了解的)
開發步驟及主要代碼展示
首先,根據你的開發環境安裝 kubebuilder 工具,mac 下通過 homebrew 安裝命令如下:
BASH ? ~ brew install kubebuilder ? ~ kubebuilder version Version: version.Version{KubeBuilderVersion:"unknown", KubernetesVendor:"unknown", GitCommit:"$Format:%H$", BuildDate:"1970-01-01T00:00:00Z", GoOs:"unknown", GoArch:"unknown"}安裝完畢后,首先創建項目目錄custom-controller并使用go mod初始化項目
BASH ? cd custom-controllers ? ls ? go mod init controllers.happyhack.io接著,使用 kubebuilder 初始化項目,生成相關文件和目錄,并創建 CRD 資源
BASH # 使用kubebuilder初始化項目 ? custom-controllers kubebuilder init --domain controller.daocloud.io --license apache2 --owner "Holder" # 創建CRD資源 ? custom-controllers kubebuilder create api --group controller --version v1 --kind Application Create Resource [y/n] y Create Controller [y/n] y Writing scaffold for you to edit... api/v1/application_types.go controllers/application_controller.go Running make: $ make /Users/donggang/Documents/Code/golang/bin/controller-gen object:headerFile="hack/huilerplate.go.txt" paths="./..." go fmt ./... go vet ./... go build -o bin/manager main.go到目前,該項目就已經能夠運行了,不過我們需要添加我們自己業務代碼,主要包括修改 CRD 定義和添加 controller 邏輯兩部分。首先修改 API 資源定義即 CRD 定義,Application 包含一個 Deployment,我們可以參考 kubernetes Deployment 與 Pod 這兩個類型之間的關系設計 Application 和 Deployment, Deployment 通過字段spec.template來描述如何創建 Pod,DeploymentTemplateSpec描述了該如何創建 Deployment,
GOLANG // PodTemplateSpec describes the data a deployment should have when created from a template type DeploymentTemplateSpec struct {// Standard object's metadata.// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata// +optionalmetav1.ObjectMeta `json:"metadata,omitempty"`// Specification of the desired behavior of the pod.// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-statusSpec v12.DeploymentSpec `json:"spec,omitempty"` }API 描述定義完成了,接下來需要我們來進行具體業務邏輯實現了,編寫具體 controller 實現,首先我們簡單梳理 controller 的主要邏輯
- 當一個 application 被創建時,需要創建對應的 deployment,當 application 被刪除或更新時,對應 Deployment 也需要被刪除或更新
- 當 application 對應的子資源 deployment 被其他客戶端刪除或更新時,controller 需要重建或恢復它
- 最后一步更新 application 的 status,這里即 count 加 1
我們在方法func(r *ApplicationReconciler) Reconcile(req ctrl.Request)(ctrl.Result,error)實現相關邏輯, 當然當業務邏輯比較復雜時,可以拆分為多個方法。
GOLANG func (r *ApplicationReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {ctx := context.Background()log := r.Log.WithValues("application", req.NamespacedName)var app controllerv1.Applicationif err := r.Get(ctx, req.NamespacedName, &app); err != nil {log.Error(err, "unable to fetch app")return ctrl.Result{}, client.IgnoreNotFound(err)}selector, err := metav1.LabelSelectorAsSelector(app.Spec.Selector)if err != nil {log.Error(err, "unable to convert label selector")return ctrl.Result{}, err}var deploys v12.DeploymentListif err := r.List(ctx, &deploys, client.InNamespace(req.Namespace), client.MatchingLabelsSelector{Selector: selector}); err != nil {if errors.IsNotFound(err) {deploy, err := r.constructDeploymentForApplication(&app)if err != nil {log.Error(err, "unable to construct deployment")return ctrl.Result{RequeueAfter: time.Second * 1,}, err}if err = r.Create(ctx, deploy); err != nil {return ctrl.Result{RequeueAfter: time.Second * 1}, err}}}... }完成Reconcile方法后,我們可以修改config目錄的示例yaml,來進行本地測試了。
官方開發自定義 Controller 的指導
kubernetes開箱自帶了多個controller,這些controller在我們開發時具有非常重要的參考價值,同時社區也總結了的 controller 開發所需要遵循十一條原則, 但是請大家結合實際場景靈活運用這些原則:
img
總結及展望
本文簡單介紹了 CRD 以及如何使用腳手架工具 kubebuilder 幫助我們開發自定義 controller,當然這個 controller 示例的邏輯比較簡單, 在實際場景中,我們會遇到很多的挑戰,比如controller 的邏輯會比較復雜、需要通過多個controller等。作為kubernetes開發者, Controller開發是一項必不可少的技能。
參考鏈接:https://blog.happyhack.io/2020/10/12/kubernetes-crd-day1/
總結
以上是生活随笔為你收集整理的K8S教程:使用kubebuilder开发简单的Operator的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通过operator部署redis集群(
- 下一篇: Dockerfile常见指令优化