Operator Framework簡介

什么是Operator

引用官網(wǎng)的話,“An Operator is a method of packaging, deploying and managing a Kubernetes application.” Operator是一種打包、部署、管理K8S應(yīng)用的方式。

很明顯,Operator天生就是面向交付及運(yùn)維的。在常見的環(huán)境中,對于無狀態(tài)的K8S應(yīng)用,借助于容器的健康檢查機(jī)制通過自啟可以解決絕大部分問題(雖然一定程度上也掩蓋了自身確實(shí)存在的問題),對這些應(yīng)用,使用Operator的必要性不足,所以通常的Operator,都是針對于有狀態(tài)應(yīng)用/中間件來做具體實(shí)現(xiàn)的??梢詤⒖籍?dāng)前一些成熟的或正在孵化中的Operator項目:https://github.com/operator-framework/awesome-operators

Operator應(yīng)用場景

在傳統(tǒng)運(yùn)維環(huán)境中,中間件都是基于非容器部署,我們往往會面對各種部署及運(yùn)維需求:
1. 備份&數(shù)據(jù)恢復(fù)。備份分為冷備和熱備。冷備通常可以通過定時任務(wù)執(zhí)行,對于即時的備份需求,大公司內(nèi)部往往有成熟的平臺支撐,但中小企業(yè)往往是運(yùn)維人員手動執(zhí)行操作,數(shù)據(jù)恢復(fù)也是如此
2. 擴(kuò)容。又分scaleup、scaleout。對于數(shù)據(jù)庫,如果只是scaleout,增加從節(jié)點(diǎn),相對較容易;但是如果是scaleup,升級主節(jié)點(diǎn)cpu、內(nèi)存呢?往往涉及比較復(fù)雜的一系列運(yùn)維操作,且風(fēng)險極大
3. 故障恢復(fù)。對于特定中間件,通常都有比較成熟的高可用集群部署方案,但對于運(yùn)維而言,依然存在諸多問題。對于異常節(jié)點(diǎn),如何恢復(fù)?對于不同中間件之間的依賴,如何處理?(比如斷電重啟中,hadoop對zk的依賴,hbase對hadoop的依賴等)
4. 聲明式部署。對于POC環(huán)境,單節(jié)點(diǎn)即可;對于生產(chǎn)環(huán)境,使用集群方式,節(jié)點(diǎn)數(shù)多少等等,都使用聲明式地配置,通過helm/ansible方式一鍵安裝
5. 安全。網(wǎng)絡(luò)訪問限制、加密協(xié)議及秘鑰管理等
6. 版本升級。如何平滑升級,一直是部署運(yùn)維人員面對有狀態(tài)系統(tǒng)頭疼的問題,所以通常這些系統(tǒng)比較穩(wěn)定,一方面是自身問題,另一方面是升級困難風(fēng)險高,不得不壓住升級需求。

以上場景都是可以通過Operator解決,使用方式上,只需要創(chuàng)建指定格式的K8S CRD即可,至于Operator內(nèi)部如何執(zhí)行具體的部署/運(yùn)維邏輯,交付人員無需關(guān)心。

Operator作用域

Operator比運(yùn)維人員的人工判斷要敏捷的多,它可以觀測集群/應(yīng)用的當(dāng)前狀態(tài)并在若干毫秒之內(nèi)作出合理的運(yùn)維決定。

Operator遵循如下成熟度模型:

scope

Helm通常用于Charts的部署于升級,Ansible則可以觸及到應(yīng)用的生命周期管理,而高級的Operator可以實(shí)現(xiàn)無縫升級、自動處理故障,真正達(dá)到Auto-pilot,自運(yùn)維、自巡航。

Operator與K8S Controller的關(guān)系

幾個tips:

  • 所有的Operator都是用了Controller模式,但并不是所有Controller都是Operator。只有當(dāng)它滿足: controller模式 + API擴(kuò)展 + 專注于某個App/中間件時,才是一個Operator。
  • Operator就是使用CRD實(shí)現(xiàn)的定制化的Controller. 它與內(nèi)置K8S Controller遵循同樣的運(yùn)行模式(比如 watch, diff, action)
  • Operator是特定領(lǐng)域的Controller實(shí)現(xiàn)

所以要了解Operator的工作原理,首先要先了解K8S controller的原理??刂破魇且粋€永不終止的控制循環(huán),它持續(xù)管理著集群的狀態(tài),通過apiserver獲取系統(tǒng)的狀態(tài),并且不斷嘗試以達(dá)到預(yù)期狀態(tài),比如副本控制器,namespace控制器,service-accounts控制器,Ingress也是一個典型的Controller實(shí)現(xiàn)


controller模型

Informer和workqueue是兩個核心組件。Controller可以有一個或多個informer來跟蹤某一個resource。Informter跟API server保持通訊獲取資源的最新狀態(tài)并更新到本地的cache中,一旦跟蹤的資源有變化,informer就會調(diào)用callback。把關(guān)心的變更的Object放到workqueue里面。然后woker執(zhí)行真正的業(yè)務(wù)邏輯,計算和比較workerqueue里items的當(dāng)前狀態(tài)和期望狀態(tài)的差別,然后通過client-go向API server發(fā)送請求,直到驅(qū)動這個集群向用戶要求的狀態(tài)演化。

Operator具體應(yīng)用舉例

1)mysql-operator 如何進(jìn)行定時數(shù)據(jù)備份:

image

2)etcd-operator如何rolling-upgrade

image

如何開發(fā)一個Operator

Operator Framework

通常對運(yùn)維人員越友好,隱藏的邏輯就越多,這些邏輯不會憑空消失,而是下沉給開發(fā)者實(shí)現(xiàn),這也符合Devops的核心理念,開發(fā)者自運(yùn)維。但是從0開發(fā)一個Operator有很高的門檻,因此coreos提供了一個Operator Framework加速開發(fā),包含以下幾個組件:

Operator SDK。集成controller-runtime,提供了:編寫運(yùn)維邏輯的高階API,快速構(gòu)建Operator項目及代碼生成的腳手架工具,覆蓋常見Operator用例的擴(kuò)展。Operator SDK是Operator Framework中最核心的工程。

Operator Lifecycle Manager:K8S集群內(nèi)所有Operator(及其關(guān)聯(lián)服務(wù))的生命周期管理( installation, updates, and management )

Getting Started

借用官網(wǎng)Helm例子,實(shí)現(xiàn)一個nginx-operator

1. 安裝 Operator SDK CLI

Operator SDK CLI 可以幫助開發(fā)快速創(chuàng)建、構(gòu)建、部署一個新的Operator工程

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 master
make dep
make install

operator-sdk工具會安裝在 $GOPATH/bin路徑下
可以將此工具cp到bin目錄,方便使用:cp operator-sdk /usr/local/bin/

2. 創(chuàng)建一個新項目

使用CLI創(chuàng)建一個基于Helm的Operator項目:

operator-sdk new nginx-operator --api-version=example.com/v1alpha1 --kind=Nginx --type=helm
cd nginx-operator

這樣就創(chuàng)建出了一個監(jiān)聽Nginx資源(即K8S中的CRD)的nginx-operator項目

目錄結(jié)構(gòu)如下:

$ tree -F nginx-operator/
nginx-operator/
├── build/ #Contains scripts that the operator-sdk uses for build and initialization.
│   └── Dockerfile
├── deploy/  #ontains a generic set of Kubernetes manifests for deploying this operator on a Kubernetes cluster.
│   ├── crds/
│   │   ├── example_v1alpha1_nginx_cr.yaml
│   │   └── example_v1alpha1_nginx_crd.yaml
│   ├── operator.yaml
│   ├── role.yaml
│   ├── role_binding.yaml
│   └── service_account.yaml
├── helm-charts/ # 標(biāo)準(zhǔn)charts格式
│   └── nginx/
│       ├── Chart.yaml
│       ├── charts/
│       ├── templates/
│       │   ├── NOTES.txt
│       │   ├── _helpers.tpl
│       │   ├── deployment.yaml
│       │   ├── ingress.yaml
│       │   ├── service.yaml
│       │   └── tests/
│       │       └── test-connection.yaml
│       └── values.yaml
└── watches.yaml #Contains Group, Version, Kind, and Helm chart location.

3. 定制Operator邏輯

Nginx CR

生成的watches.yaml內(nèi)容如下:

$ cat watches.yaml
---
- version: v1alpha1
  group: example.com
  kind: Nginx
  chart: /opt/helm/helm-charts/nginx

它表示我們的Operator會watch Nginx這個資源的事件(create,update,delete等),部署時使用 /opt/helm/helm-charts/nginx這個chart進(jìn)行部署。
在生成的nginx-operator中,helm-charts/nginx是一個標(biāo)準(zhǔn)的Helm Chart模板,Helm格式的具體參考見:Helm Chart developer documentation.

Nginx Helm Chart

Helm使用 values 提供自定義默認(rèn)值配置的能力, 見 helm-charts/nginx/values.yaml
覆蓋這些默認(rèn)值就像在CR規(guī)范中設(shè)置所需的值一樣簡單。我們以副本數(shù)量為例。

首先,檢查helm-charts/nginx/values.yaml,我們看到Chart有一個名為replicaCount的值,默認(rèn)設(shè)置為1。如果我們想要在部署中使用2個nginx實(shí)例,我們需要確保我們的CR規(guī)范包含replicaCount:2

更新deploy/crds/example_v1alpha1_nginx_cr.yaml如下:

apiVersion: example.com/v1alpha1
kind: Nginx
metadata:
  name: example-nginx
spec:
  replicaCount: 2

同樣,我們看到默認(rèn)服務(wù)端口設(shè)置為80,但我們想使用8080,因此我們將通過添加服務(wù)端口覆蓋來再次更新deploy/crds/example_v1alpha1_nginx_cr.yaml:

apiVersion: example.com/v1alpha1
kind: Nginx
metadata:
  name: example-nginx
spec:
  replicaCount: 2
  service:
    port: 8080

該CR文件其實(shí)就是Helm Chart的標(biāo)準(zhǔn)values.yaml文件,使用kubectl create創(chuàng)建該CR后,operator內(nèi)部邏輯就像使用helm install -f ./overrides.yaml一樣,所有需要修改的變量都要在這個文件中配置。

Build and run the operator

在run operator之前,Kubernetes需要知道要watch的CRD資源是什么。
部署CRD(如果創(chuàng)建operator前沒有創(chuàng)建CRD,operator會啟動失敗):
kubectl create -f deploy/crds/example_v1alpha1_nginx_crd.yaml

在k8s集群中運(yùn)行operator,首先要構(gòu)建operator鏡像并將鏡像push到我們的集群倉庫中:

operator-sdk build quay.io/example/nginx-operator:v0.0.1
docker push quay.io/example/nginx-operator:v0.0.1

然后把deploy/operator.yaml中的REPLACE_IMAGE替換為我們剛才push的鏡像:
sed -i 's|REPLACE_IMAGE|quay.io/example/nginx-operator:v0.0.1|g' deploy/operator.yaml

部署nginx-operator:

kubectl create -f deploy/service_account.yaml
kubectl create -f deploy/role.yaml
kubectl create -f deploy/role_binding.yaml
kubectl create -f deploy/operator.yaml

至此,一個nginx-operator就成功創(chuàng)建出來了:


image.png

到這一步只是將operator創(chuàng)建成功,需要創(chuàng)建我們上面提到的CR文件,才能將我們最終需要的nginx pod創(chuàng)建出來,當(dāng)然可以編寫多個CR文件,這樣就能創(chuàng)建多個nginx deployment
kubectl apply -f deploy/crds/example_v1alpha1_nginx_cr.yaml

$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example-nginx-b9phnoz9spckcrua7ihrbkrt1 2 2 2 2 1m

環(huán)境鏟除:

kubectl delete -f deploy/crds/example_v1alpha1_nginx_cr.yaml
kubectl delete -f deploy/operator.yaml
kubectl delete -f deploy/role_binding.yaml
kubectl delete -f deploy/role.yaml
kubectl delete -f deploy/service_account.yaml
kubectl delete -f deploy/crds/example_v1alpha1_nginx_crd.yaml

operator helm化

什么意思?
我們已經(jīng)用operator部署了一個helm chart,什么叫operator helm化?
其實(shí)很好理解,觀察下我們上述的部署操作,如果我們把CRD、role_binding、service_account等等這些放到一個Chart里面,則通過helm install的方式可以直接安裝operator,再通過create特定的cr,創(chuàng)建對應(yīng)的資源。
可以參考jaeger-operator

注:遇到一個坑,刪除不掉CR和CRD

運(yùn)行kubectl delete -f deploy/crds/example_v1alpha1_nginx_cr.yaml之后,nginx pod沒有按預(yù)期被刪除掉。發(fā)現(xiàn)資源仍然存在,所以operator監(jiān)聽不到資源的銷毀

# kubectl get Nginx
NAME                 AGE
example-nginx        1m

解決:

# kubectl patch nginx/example-nginx -p '{"metadata":{"finalizers":[]}}' --type=merge
nginx "example-nginx" patched

另外CRD刪不掉的情況:

kubectl patch crd/nginxes.example.com -p '{"metadata":{"finalizers":[]}}' --type=merge
kubectl create -f deploy/crds/example_v1alpha1_nginx_crd.yaml
kubectl patch nginx/emas-default-nginx -p '{"metadata":{"finalizers":[]}}' --type=merge

https://github.com/kubernetes/kubernetes/issues/60538

helm方式目前僅適用于創(chuàng)建、更新,對于備份、恢復(fù)之類的操作,沒有顯式的擴(kuò)展支持。

Ref

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容