技術漫談 | 自己動手寫Kubernetes Operator
在本文中,我們將瞭解如何使用Operator SDK構建和部署您的第一個Kubernetes operator。
Kubernetes是一個流行的開源平臺,用於管理容器化工作負載和服務。隨著1.7版本中自定義資源定義(CRD)的引入,該平臺也變得可擴充套件:例如,管理員可以定義自己的資源型別,並提供比deployment或service更適合特定領域的模式。但請放心,這並不一定需要更長的YAML!
但CRD只定義了配置,群集仍需要控制器來監視其狀態並協調資源以匹配宣告。這便是operator發揮作用的地方。
Operator是與自定義資源相關聯的控制器,以執行那些需要“人工操作”的任務。設想部署一套資料庫叢集,需要設定節點數量、升級和執行備份操作。通過自定義資源可以指定資料庫版本、要部署的節點、備份頻率以及後端儲存。而控制器將執行這些操作所需的業務邏輯。例如,etcd-operator。
然而,編寫CRD及其附帶控制器是一項艱鉅的任務。值得慶幸的是,operator SDK隨時為您提供幫助。讓我們看看如何用它構建一個可以指定pod映象並實現擴縮容的operator。換句話說,讓我們編寫一個基本的Kubernetes ReplicaSet!
請注意,在撰寫本文時,Operator SDK的版本為v0.4.0,因此之後可能會發生變化。我們將構建一個Go Operator,但operator也可以開發成Ansible playbooks或Helm chart。
一、一級資源和二級資源在深入瞭解Operator SDK和原始碼之前,我們再討論一下operator。正如前面所見,operator是CRD相關的控制器,它觀察並根據配置變化或叢集狀態變化來採取行動。但實際上控制器需要監測兩種資源,一級資源和二級資源。
對於ReplicaSet,一級資源是ReplicaSet本身,指定執行的Docker映象以及pod的副本數。二級資源則是pod。當ReplicaSet 的定義發生改變(例如映象版本或pod數量)或者其中的pod發生改變時(例如某個pod被刪除),控制器則會通過推出新版本來協調叢集狀態,或是對pod數量擴縮容。
對於DaemonSet,一級資源是DaemonSet本身,而二級資源是pod和node。不同之處在於,控制器也會監測叢集node變化,以便在群集增大或縮小時新增或刪除pod。
明確識別出Operator的主要和二級資源是至關重要的,因為他們將決定其控制器的行為。
二、構建Potset Operator
講了足夠的理論,現在深入程式碼構建一個名叫PodSet的operator,它啟動busybox容器執行sleep 3600,並管理pod數量的擴容和縮容。樣例並不複雜,因為本文的重點是教大家構建operator,而不是深入某個應用複雜的設定。
1、安裝Operator SDK
首先下載並安裝SDK:
$ mkdir -p $GOPATH/src/github.com/operator-framework $ cd $GOPATH/src/github.com/operator-framework $ git clone https://github.com/operator-framework/operator-sdk $ cd operator-sdk $ git checkout v0.4.0 $ make dep $ make install
2、初始化GO專案
接下來使用operator-sdk初始化專案:
# bootstrap the project and run "deps ensure" and "git init" $ operator-sdk new podset-operator
check the project structure
$ tree -I vendor
.
├── Gopkg.lock
├── Gopkg.toml
├── build
│ └── Dockerfile
├── cmd
│ └── manager
│ └── main.go
├── deploy
│ ├── operator.yaml
│ ├── role.yaml
│ ├── role_binding.yaml
│ └── service_account.yaml
├── pkg
│ ├── apis
│ │ └── apis.go
│ └── controller
│ └── controller.go
└── version
└── version.go
完成後,我們有了專案的基本佈局,它不僅包含執行operator的go程式碼(cmd/manager/main.go),還包含將二進位制檔案打包成Docker映象的Dockerfile,以及一組YAML清單:
1)部署podset-operator的deployment;
2)Operator操作所需的Service Account以及role和role bindings(比如新增或刪除pod等);
3、新增CRD和控制器
現在,讓我們為PodSet Operator建立一個CRD和一個關聯控制器。由於這是Operator的第一個版本,因此將版本設定為v1alpha1:
# Add a new API for the custom resource PodSet $ operator-sdk add api --api-version=app.example.com/v1alpha1 --kind=PodSet
Add a new controller that watches for PodSet
$ operator-sdk add controller --api-version=app.example.com/v1alpha1 --kind=PodSet
這兩條命令會生成另一組YAML檔案和GO程式碼,最明顯的變化如下:
1、新生成的deploy/crds包含PodSet的CRD和CR樣例:
$ cat deploy/crds/app_v1alpha1_podset_crd.yaml apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: podsets.app.example.com spec: group: app.example.com names: kind: PodSet listKind: PodSetList plural: podsets singular: podset scope: Namespaced version: v1alpha1 $ cat deploy/crds/app_v1alpha1_podset_cr.yaml apiVersion: app.example.com/v1alpha1 kind: PodSet metadata: name: example-podset spec: # Add fields here size: 3
CRD的完整名稱是podsets.app.example.com,但也有與之相關聯的名稱(PodSet, PodSetList, podsets, podset)。它們將成為擴充套件叢集API的一部分,並在kubectl命令列中提供。我們稍後在部署和執行Operator時會看到。
2、pkg/apis/app/v1alpha1/podset_types.go定義了PodSet預期狀態的結構體,該結構體由前面所講的deploy/crds/app_v1alpha1_podset_cr.yaml檔案中指定。它還定義了在執行kubectl describe檢視狀態時,PodSetStatus的結構體。稍後會詳細介紹。
3、腳手架檔案
pkg/controller/podset/podset_controller.go是放置控制器的業務邏輯的地方。
其餘的更改是註冊CRD和控制器所必需的。
4、實現控制器的業務邏輯
開箱即用的方式,如果不存在給定app標籤的pod,則由SDK生成的控制器程式碼會自動建立一個。雖然這不是我們想要的,但它仍然是一個很好的起點,因為它展示瞭如何使用k8s API,無論是列出pod還是建立新的。我們要做的第一件事是通過新增欄位來儲存PodSetSpec的副本數量和PodSetStatus的pod名稱:
type PodSetSpec struct { Replicas int32 `json:"replicas"` } type PodSetStatus struct { PodNames []string `json:"podNames"` }
每次對結構體進行更改後,都需要執行operator-sdk generate k8s命令來相應地更新
pkg/apis/app/v1alpha1/zz_generated.deepcopy.go檔案。
之後,我們需要配置控制器在namespace中監測的一級資源和二級資源。對於podset Operator,一級資源是podset,二級資源是namespace中的pod。我們無需做任何事情,因為已經在生成的程式碼中實現了。預設情況下,控制器在podset資源上執行並建立一個pod。
最後,我們需要實現擴縮容和通過pod名稱更新自定義資源狀態的邏輯。所有這些都發生在控制器的Reconcile函式中。
在協調期間,控制器獲取當前名稱空間中的PodSet資源,並將其Replica欄位的值與匹配標籤的實際Pod數進行比較,以確定是否需要建立或刪除pod。想深入瞭解控制器Reconcile函式細節,請檢視程式碼
https://github.com/xcoulon/pod ... 23L86讓我們專注記住的幾個關鍵點:
1、每次更改PodSet資源或在屬於PodSet的pod中發生更改時,都會呼叫reconcile函式。
2、如果需要Reconcile新增或刪除pod,則該功能應該一次只新增或刪除一個pod,返回並等待下一次呼叫(因為它將在建立或刪除pod後被呼叫)。
3、使用controllerutil.SetControllerReference()函式確保PodSet一級資源“擁有”pod 。擁有從屬關係意味著刪除PodSet資源時,其所有“從屬”pod也將被刪除。
三、 構建併發布Operator讓我們使用Operator SDK構建包含控制器的Docker映象,然後將其推到映象倉庫。我們將使用Quay.io,但其他映象倉庫也一樣可以使用:
# build the Docker image using the Operator SDK $ operator-sdk build quay.io/xcoulon/podset-operator
login to Quay.io
$ docker login -u xcoulon quay.io
push the image to Docker Hub
$ docker push quay.io/xcoulon/podset-operator
此外,我們需要更新operator.yaml以使用Quay.io上的新Docker映象:
# On Linux: $ sed -i 's|REPLACE_IMAGE|quay.io/xcoulon/podset-operator|g' deploy/operator.yaml
On OSX:
$ sed -i "" 's|REPLACE_IMAGE|quay.io/xcoulon/podset-operator|g' deploy/operator.yaml
1、配置Minishift
安裝Minishift並開啟admin-user外掛:
# create a new profile to test the operator $ minishift profile set operator
enable the admin-user add-on
$ minishift addon enable admin-user
optionally, configure the VM
$ minishift config set cpus 4
$ minishift config set memory 8GB
$ minishift config set vm-driver virtualbox
start the instance
$ minishift start
login with the admin account
$ oc login -u system:admin
2、在Minishift上部署Operator
在部署Operator控制器之前,我們需要建立service account併為其分配一個具有適當管理許可權的role:
# Setup Service Account $ oc create -f deploy/service_account.yaml
Setup RBAC
$ oc create -f deploy/role.yaml
$ oc create -f deploy/role_binding.yaml
完成後,我們可以建立CRD並部署opertaor控制器:
# Setup the CRD $ oc create -f deploy/crds/app_v1alpha1_podset_crd.yaml
Deploy the podset-operator
$ oc create -f deploy/operator.yaml
建立CRD後,它不僅可以通過叢集API端點訪問,還可以從命令列工具訪問。如前所述,這就是Kubernetes作為可擴充套件平臺的亮點:
# check the CRD $ oc get crd podsets.app.example.com NAME podsets.app.example.com
check the operator controller
$ oc get pods
NAME READY STATUS
podset-operator-685bbbc858-d4gf7 1/1 Running
check if there's a CR using the CRD fullname...
$ oc get podsets.app.example.com
No resources found.
... or one of its aliases
$ oc get podsets
No resources found.
在CRD和Operator控制器都建立好之後,終於可以建立3副本的PodSet資源了:
$ echo "apiVersion: app.example.com/v1alpha1 kind: PodSet metadata: name: example-podset spec: replicas: 3" | oc create -f -
現在檢視一下namespace中的pod:
$ oc get pods -l app=example-podset NAMEREADYSTATUS example-podset-podc2ckn1/1Running example-podset-podjnqqr1/1Running example-podset-podlx55r1/1Running
正如我們對Operator控制器的期望,當刪除一個pod時,新的pod會被建立,當擴容或者縮容時,pod數量也會相應增加或減少:
# let's delete a pod $ oc delete pod example-podset-podlx55r pod "example-podset-podlx55r" deleted
let's check the pods again - a new pod was created to replace
the one we just deleted
$ oc get pods -l app=example-podset
NAME READY STATUS RESTARTS AGE
example-podset-pod85zf5 1/1 Running 0 46s
example-podset-podc2ckn 1/1 Running 0 8m
example-podset-podjnqqr 1/1 Running 0 8m
let's scale down the pod set
$ echo "apiVersion: app.example.com/v1alpha1
kind: PodSet
metadata:
name: example-podset
spec:
replicas: 2" | oc apply -f -
let's check the pods
$ oc get pods -l app=example-podset
NAME READY STATUS RESTARTS AGE
example-podset-pod85zf5 1/1 Terminating 0 39m
example-podset-podc2ckn 1/1 Running 0 46m
example-podset-podjnqqr 1/1 Running 0 46m
let's scale up the pod set
$ echo "apiVersion: app.example.com/v1alpha1
kind: PodSet
metadata:
name: example-podset
spec:
replicas: 4" | oc apply -f -
let's check the pods again
$ oc get pods -l app=example-podset
NAME READY STATUS RESTARTS AGE
example-podset-pod5hj4r 1/1 Running 0 8s
example-podset-podc2ckn 1/1 Running 0 49m
example-podset-podjnqqr 1/1 Running 0 49m
example-podset-podlf7xm 1/1 Running 0 8s
此外,自定義資源狀態會顯示pod的名稱:
$ oc describe podset/example-podset Name:example-podset Namespace:myproject Labels:<none> Annotations:kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"app.example.com/v1alpha1","kind":"PodSet","metadata":{"annotations":{},"name":"example-podset","namespace":"myproject"},"spec":{"replica... API Version:app.example.com/v1alpha1 Kind:PodSet Metadata: ... Spec: Replicas:4 Status: Pod Names: example-podset-pod5hj4r example-podset-podc2ckn example-podset-podjnqqr example-podset-podlf7xm Events:<none>
最後,當我們刪除PodSet資源時,所有關聯的(即“從屬”)pod也會被刪除:
# let's delete the PodSet resource $ oc delete podset example-podset podset.app.example.com "example-podset" deleted
let's check the pods are deleted as well
$ oc get pods -l app=example-podset
NAME READY STATUS
example-podset-pod5hj4r 1/1 Terminating
example-podset-podc2ckn 1/1 Terminating
example-podset-podjnqqr 1/1 Terminating
example-podset-podzdzrn 1/1 Terminating
至此,我們建立並部署了我們的第一個Kubernetes Operator!
有關Operator SDK的更多資訊,請檢視GitHub倉庫和官網上的概述。
GitHub倉庫:
https://github.com/operator-fr ... -sdk/
CoreOS官網上:
本文中開發的opertaor程式碼也在GitHub上。
GitHub :
https://github.com/xcoulon/podset-operator
原文連結:
https://medium.com/devopslinks ... 53234
關於睿雲智合
深圳睿雲智合科技有限公司成立於2012年,總部位於深圳,並分別在成都、深圳設立了研發中心,北京、上海設立了分支機構,核心骨幹人員全部為來自金融、科技行業知名企業資深業務專家、技術專家。早期專注於為中國金融保險等大型企業提供創新技術、電子商務、CRM等領域專業諮詢服務。
自2016年始,在率先將容器技術引進到中國保險行業客戶後,公司組建了專業的容器技術產品研發和實施服務團隊,旨在幫助中國金融行業客戶將容器創新技術應用於企業資訊科技支援業務發展的基礎能力改善與提升,成為中國金融保險行業容器技術服務領導品牌。
此外,憑藉多年來在呼叫中心領域的業務經驗與技術積累,睿雲智合率先在業界推出基於開源軟交換平臺FreeSwitch的微服務架構多媒體數字化業務平臺,將語音、視訊、webchat、微信、微博等多種客戶接觸渠道整合,實現客戶統一接入、精準識別、智慧路由的CRM策略,並以容器化治理來支援平臺的全應用生命週期管理,顯著提升了數字化業務處理的靈活、高效、彈性、穩定等特性,為幫助傳統企業向“以客戶為中心”的數字化業務轉型提供完美的一站式整體解決方案。