K8S教程:使用kubebuilder开发简单的Operator
云原生技術(shù)通過(guò)方法論、工具集和最佳實(shí)踐重塑著整個(gè)軟件技術(shù)棧和生命周期,云原生對(duì)云計(jì)算服務(wù)方式與互聯(lián)網(wǎng)架構(gòu)進(jìn)行整體性升級(jí), 深刻改變著整個(gè) IT 領(lǐng)域。云原生的核心是 kubernetes,圍繞 kubernetes 構(gòu)建滿足自身需求的 PaaS 平臺(tái)(應(yīng)用中心)是絕大數(shù)企業(yè)的訴求, 但是不同企業(yè)自身場(chǎng)景往往存在一定的差異,Operator 是最常見(jiàn) kubernetes 拓展方式。本片博文,我將會(huì)給大家理清 Operator 的來(lái)龍去脈, 同時(shí)介紹如何通過(guò) kubebuilder 快速開(kāi)發(fā)一個(gè)簡(jiǎn)單的 Operator。
Operator 誕生的背景
kubernetes 無(wú)法做到真正意義的開(kāi)箱即用的,它與傳統(tǒng)的 PaaS 平臺(tái)不同,它僅僅只提供核心的基礎(chǔ)設(shè)施功能,但是還無(wú)法滿足用戶的最終需求,這里用戶主要指業(yè)務(wù)開(kāi)發(fā)和業(yè)務(wù)運(yùn)維, 比如說(shuō)業(yè)務(wù)開(kāi)發(fā)需要 CI/CD 工具實(shí)現(xiàn) Devops 的功能,原生 kubernetes 是不提供支持的,但是我們可以通過(guò)tekton這一個(gè)第三方工具實(shí)現(xiàn) DevOps 相關(guān)功能, 這也正是 kubernetes 區(qū)別傳統(tǒng)PaaS平臺(tái)的真正強(qiáng)大之處,其提供完善的擴(kuò)展機(jī)制以及基于此而發(fā)展出來(lái)的海量的第三方工具和豐富的生態(tài)。
Operator pattern首先由 CoreOS 提出,通過(guò)結(jié)合 CRD 和 custom controller 將特定應(yīng)用的運(yùn)維知識(shí)轉(zhuǎn)換為代碼,實(shí)現(xiàn)應(yīng)用運(yùn)維的自動(dòng)化和智能化。Operator 允許 kubernetes 來(lái)管理復(fù)雜的,有狀態(tài)的分布式應(yīng)用程序,并由 kubernetes 對(duì)其進(jìn)行自動(dòng)化管理,例如,etcd operator 能夠創(chuàng)建并管理一組 etcd 集群, 定制化的 controller 組件了解這些資源,知道如何維護(hù)這些特定的應(yīng)用。
隨著 kubernetes 的功能越來(lái)越復(fù)雜,其需要管理的資源在高速增長(zhǎng),對(duì)應(yīng)的 API 和 controller 的數(shù)量也愈發(fā)無(wú)法控制, kubernetes 變得很臃腫,很多不必要的 API 和功能將出現(xiàn)在每次安裝的集群中。
為了解決這個(gè)問(wèn)題,CRD 應(yīng)運(yùn)而生,CRD 由 TPR(Third Part Resource v1.2 版本引入)演化而來(lái),v1.7 進(jìn)入 beta,v1.8 進(jìn)入穩(wěn)定, 通過(guò) CRD,kubernetes 可以動(dòng)態(tài)的添加并管理資源。CRD 解決了結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)的問(wèn)題,Controller 則用來(lái)跟蹤這些資源, 保證資源的狀態(tài)滿足期望值。CRD+Controller=decalartive API,聲明式 API 設(shè)計(jì)是 kubernetes 重要的設(shè)計(jì)思想, 該設(shè)計(jì)保證能夠動(dòng)態(tài)擴(kuò)展 kubernetes API,這種模式也正是 Operator pattern。
kubernetes 本身也在通過(guò) CRD 添加新功能,我們有什么理由不使用呢?
使用場(chǎng)景總結(jié)及舉例
CRD+custom controller 已經(jīng)被廣泛地使用,按使用場(chǎng)景可劃分為以下兩種:
通用型 controller 往往是 kubernetes 平臺(tái)側(cè)用戶,如各大云廠商和 kubernetes 服務(wù)提供商,Operator 則是各種軟件服務(wù)提供商, 他們?cè)O(shè)計(jì)時(shí)面向單一應(yīng)用,很多開(kāi)源的應(yīng)用的 operator 可以在 operator hub 中獲取。我列舉一些示例供大家參考:
通用型 Controller
Operator
通用型Controller與kubernetes自帶的幾個(gè)controller類似,旨在解決一些通用的應(yīng)用模型,而Operator則更加面向單個(gè)特定應(yīng)用, 這兩者沒(méi)有本質(zhì)的區(qū)別。
如何開(kāi)發(fā) CRD
作為kubernetes開(kāi)發(fā)者,如何開(kāi)發(fā) CRD+Custom cntroller 呢?其實(shí)官方提供示例項(xiàng)目sample-controller供開(kāi)發(fā)者參考,開(kāi)發(fā)流程大致有以下幾個(gè)過(guò)程:
其中步驟 2,5 是核心業(yè)務(wù)邏輯,其余步驟完全可以通過(guò)自動(dòng)生成的方式省略,到目前,社區(qū)有兩個(gè)成熟的腳手架工具用于簡(jiǎn)化開(kāi)發(fā),一個(gè)是有 kube-sig 維護(hù)的 kubebuilder, 另一個(gè)是由 redhat 維護(hù)的 operator-sdk,這兩個(gè)工具都是基于 controller-runtime 項(xiàng)目而實(shí)現(xiàn),用戶可自行選擇,筆者用的是 kubebuilder。使用 kubebuilder 能夠幫助我們節(jié)省以下工作:
如果你想要快速構(gòu)建 CRD 和 Custom controller,腳手架工具是個(gè)不錯(cuò)的選擇,如果是學(xué)習(xí)目的,建議結(jié)合 sample-controller 和 kubernetes controller 相關(guān) 源碼。
kubebuilder 詳解
kubebuilder 是一個(gè)幫助開(kāi)發(fā)者快速開(kāi)發(fā) kubernetes API 的腳手架命令行工具,其依賴庫(kù) controller-tools 和 controller-runtime, controller-runtime 簡(jiǎn)化 kubernetes controller 的開(kāi)發(fā),并且對(duì) kubernetes 的幾個(gè)常用庫(kù)進(jìn)行了二次封裝, 以簡(jiǎn)化開(kāi)發(fā)者使用。controller-tool 主要功能是代碼生成。下圖是使用 kubebuilder 的工作流程圖:
文章后面會(huì)結(jié)合一個(gè)簡(jiǎn)單示例來(lái)介紹開(kāi)發(fā)流程。
“
kubebuilder 有非常良好的文檔,包括一個(gè)從零開(kāi)始的示例,您應(yīng)該以文檔為主。
”
使用 kubebuilder 開(kāi)發(fā)一個(gè) CRD
本次示例創(chuàng)建一個(gè)通用的Application資源,Application 包含一個(gè)子資源 Deployment 以及一個(gè) Count 資源, 每當(dāng) Application 進(jìn)行被重新協(xié)調(diào)Reconcil,Count 會(huì)進(jìn)行自增。
“
全部代碼請(qǐng)參考代碼倉(cāng)
”
前提(你需要提前了解的)
開(kāi)發(fā)步驟及主要代碼展示
首先,根據(jù)你的開(kāi)發(fā)環(huán)境安裝 kubebuilder 工具,mac 下通過(guò) 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"}安裝完畢后,首先創(chuàng)建項(xiàng)目目錄custom-controller并使用go mod初始化項(xiàng)目
BASH ? cd custom-controllers ? ls ? go mod init controllers.happyhack.io接著,使用 kubebuilder 初始化項(xiàng)目,生成相關(guān)文件和目錄,并創(chuàng)建 CRD 資源
BASH # 使用kubebuilder初始化項(xiàng)目 ? custom-controllers kubebuilder init --domain controller.daocloud.io --license apache2 --owner "Holder" # 創(chuàng)建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到目前,該項(xiàng)目就已經(jīng)能夠運(yùn)行了,不過(guò)我們需要添加我們自己業(yè)務(wù)代碼,主要包括修改 CRD 定義和添加 controller 邏輯兩部分。首先修改 API 資源定義即 CRD 定義,Application 包含一個(gè) Deployment,我們可以參考 kubernetes Deployment 與 Pod 這兩個(gè)類型之間的關(guān)系設(shè)計(jì) Application 和 Deployment, Deployment 通過(guò)字段spec.template來(lái)描述如何創(chuàng)建 Pod,DeploymentTemplateSpec描述了該如何創(chuàng)建 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 描述定義完成了,接下來(lái)需要我們來(lái)進(jìn)行具體業(yè)務(wù)邏輯實(shí)現(xiàn)了,編寫(xiě)具體 controller 實(shí)現(xiàn),首先我們簡(jiǎn)單梳理 controller 的主要邏輯
- 當(dāng)一個(gè) application 被創(chuàng)建時(shí),需要?jiǎng)?chuàng)建對(duì)應(yīng)的 deployment,當(dāng) application 被刪除或更新時(shí),對(duì)應(yīng) Deployment 也需要被刪除或更新
- 當(dāng) application 對(duì)應(yīng)的子資源 deployment 被其他客戶端刪除或更新時(shí),controller 需要重建或恢復(fù)它
- 最后一步更新 application 的 status,這里即 count 加 1
我們?cè)诜椒╢unc(r *ApplicationReconciler) Reconcile(req ctrl.Request)(ctrl.Result,error)實(shí)現(xiàn)相關(guān)邏輯, 當(dāng)然當(dāng)業(yè)務(wù)邏輯比較復(fù)雜時(shí),可以拆分為多個(gè)方法。
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,來(lái)進(jìn)行本地測(cè)試了。
官方開(kāi)發(fā)自定義 Controller 的指導(dǎo)
kubernetes開(kāi)箱自帶了多個(gè)controller,這些controller在我們開(kāi)發(fā)時(shí)具有非常重要的參考價(jià)值,同時(shí)社區(qū)也總結(jié)了的 controller 開(kāi)發(fā)所需要遵循十一條原則, 但是請(qǐng)大家結(jié)合實(shí)際場(chǎng)景靈活運(yùn)用這些原則:
img
總結(jié)及展望
本文簡(jiǎn)單介紹了 CRD 以及如何使用腳手架工具 kubebuilder 幫助我們開(kāi)發(fā)自定義 controller,當(dāng)然這個(gè) controller 示例的邏輯比較簡(jiǎn)單, 在實(shí)際場(chǎng)景中,我們會(huì)遇到很多的挑戰(zhàn),比如controller 的邏輯會(huì)比較復(fù)雜、需要通過(guò)多個(gè)controller等。作為kubernetes開(kāi)發(fā)者, Controller開(kāi)發(fā)是一項(xiàng)必不可少的技能。
參考鏈接:https://blog.happyhack.io/2020/10/12/kubernetes-crd-day1/
總結(jié)
以上是生活随笔為你收集整理的K8S教程:使用kubebuilder开发简单的Operator的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 通过operator部署redis集群(
- 下一篇: Dockerfile常见指令优化