什么是Operator
引用官網的話,“An Operator is a method of packaging, deploying and managing a Kubernetes application.” Operator是一種打包、部署、管理K8S應用的方式。
很明顯,Operator天生就是面向交付及運維的。在常見的環境中,對于無狀態的K8S應用,借助于容器的健康檢查機制通過自啟可以解決絕大部分問題(雖然一定程度上也掩蓋了自身確實存在的問題),對這些應用,使用Operator的必要性不足,所以通常的Operator,都是針對于有狀態應用/中間件來做具體實現的。可以參考當前一些成熟的或正在孵化中的Operator項目:https://github.com/operator-framework/awesome-operators
Operator應用場景
在傳統運維環境中,中間件都是基于非容器部署,我們往往會面對各種部署及運維需求:
1. 備份&數據恢復。備份分為冷備和熱備。冷備通常可以通過定時任務執行,對于即時的備份需求,大公司內部往往有成熟的平臺支撐,但中小企業往往是運維人員手動執行操作,數據恢復也是如此
2. 擴容。又分scaleup、scaleout。對于數據庫,如果只是scaleout,增加從節點,相對較容易;但是如果是scaleup,升級主節點cpu、內存呢?往往涉及比較復雜的一系列運維操作,且風險極大
3. 故障恢復。對于特定中間件,通常都有比較成熟的高可用集群部署方案,但對于運維而言,依然存在諸多問題。對于異常節點,如何恢復?對于不同中間件之間的依賴,如何處理?(比如斷電重啟中,hadoop對zk的依賴,hbase對hadoop的依賴等)
4. 聲明式部署。對于POC環境,單節點即可;對于生產環境,使用集群方式,節點數多少等等,都使用聲明式地配置,通過helm/ansible方式一鍵安裝
5. 安全。網絡訪問限制、加密協議及秘鑰管理等
6. 版本升級。如何平滑升級,一直是部署運維人員面對有狀態系統頭疼的問題,所以通常這些系統比較穩定,一方面是自身問題,另一方面是升級困難風險高,不得不壓住升級需求。
以上場景都是可以通過Operator解決,使用方式上,只需要創建指定格式的K8S CRD即可,至于Operator內部如何執行具體的部署/運維邏輯,交付人員無需關心。
Operator作用域
Operator比運維人員的人工判斷要敏捷的多,它可以觀測集群/應用的當前狀態并在若干毫秒之內作出合理的運維決定。
Operator遵循如下成熟度模型:
Helm通常用于Charts的部署于升級,Ansible則可以觸及到應用的生命周期管理,而高級的Operator可以實現無縫升級、自動處理故障,真正達到Auto-pilot,自運維、自巡航。
Operator與K8S Controller的關系
幾個tips:
- 所有的Operator都是用了Controller模式,但并不是所有Controller都是Operator。只有當它滿足: controller模式 + API擴展 + 專注于某個App/中間件時,才是一個Operator。
- Operator就是使用CRD實現的定制化的Controller. 它與內置K8S Controller遵循同樣的運行模式(比如 watch, diff, action)
- Operator是特定領域的Controller實現
所以要了解Operator的工作原理,首先要先了解K8S controller的原理。控制器是一個永不終止的控制循環,它持續管理著集群的狀態,通過apiserver獲取系統的狀態,并且不斷嘗試以達到預期狀態,比如副本控制器,namespace控制器,service-accounts控制器,Ingress也是一個典型的Controller實現
Informer和workqueue是兩個核心組件。Controller可以有一個或多個informer來跟蹤某一個resource。Informter跟API server保持通訊獲取資源的最新狀態并更新到本地的cache中,一旦跟蹤的資源有變化,informer就會調用callback。把關心的變更的Object放到workqueue里面。然后woker執行真正的業務邏輯,計算和比較workerqueue里items的當前狀態和期望狀態的差別,然后通過client-go向API server發送請求,直到驅動這個集群向用戶要求的狀態演化。
Operator具體應用舉例
1)mysql-operator 如何進行定時數據備份:
2)etcd-operator如何rolling-upgrade
如何開發一個Operator
Operator Framework
通常對運維人員越友好,隱藏的邏輯就越多,這些邏輯不會憑空消失,而是下沉給開發者實現,這也符合Devops的核心理念,開發者自運維。但是從0開發一個Operator有很高的門檻,因此coreos提供了一個Operator Framework加速開發,包含以下幾個組件:
Operator SDK。集成controller-runtime,提供了:編寫運維邏輯的高階API,快速構建Operator項目及代碼生成的腳手架工具,覆蓋常見Operator用例的擴展。Operator SDK是Operator Framework中最核心的工程。
Operator Lifecycle Manager:K8S集群內所有Operator(及其關聯服務)的生命周期管理( installation, updates, and management )
Getting Started
借用官網Helm例子,實現一個nginx-operator
1. 安裝 Operator SDK CLI
Operator SDK CLI 可以幫助開發快速創建、構建、部署一個新的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. 創建一個新項目
使用CLI創建一個基于Helm的Operator項目:
operator-sdk new nginx-operator --api-version=example.com/v1alpha1 --kind=Nginx --type=helm
cd nginx-operator
這樣就創建出了一個監聽Nginx資源(即K8S中的CRD)的nginx-operator項目
目錄結構如下:
$ 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/ # 標準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內容如下:
$ 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進行部署。
在生成的nginx-operator中,helm-charts/nginx是一個標準的Helm Chart模板,Helm格式的具體參考見:Helm Chart developer documentation.
Nginx Helm Chart
Helm使用 values 提供自定義默認值配置的能力, 見 helm-charts/nginx/values.yaml
覆蓋這些默認值就像在CR規范中設置所需的值一樣簡單。我們以副本數量為例。
首先,檢查helm-charts/nginx/values.yaml,我們看到Chart有一個名為replicaCount的值,默認設置為1。如果我們想要在部署中使用2個nginx實例,我們需要確保我們的CR規范包含replicaCount:2
更新deploy/crds/example_v1alpha1_nginx_cr.yaml如下:
apiVersion: example.com/v1alpha1
kind: Nginx
metadata:
name: example-nginx
spec:
replicaCount: 2
同樣,我們看到默認服務端口設置為80,但我們想使用8080,因此我們將通過添加服務端口覆蓋來再次更新deploy/crds/example_v1alpha1_nginx_cr.yaml:
apiVersion: example.com/v1alpha1
kind: Nginx
metadata:
name: example-nginx
spec:
replicaCount: 2
service:
port: 8080
該CR文件其實就是Helm Chart的標準values.yaml文件,使用kubectl create創建該CR后,operator內部邏輯就像使用helm install -f ./overrides.yaml一樣,所有需要修改的變量都要在這個文件中配置。
Build and run the operator
在run operator之前,Kubernetes需要知道要watch的CRD資源是什么。
部署CRD(如果創建operator前沒有創建CRD,operator會啟動失敗):
kubectl create -f deploy/crds/example_v1alpha1_nginx_crd.yaml
在k8s集群中運行operator,首先要構建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就成功創建出來了:
到這一步只是將operator創建成功,需要創建我們上面提到的CR文件,才能將我們最終需要的nginx pod創建出來,當然可以編寫多個CR文件,這樣就能創建多個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
環境鏟除:
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化
什么意思?
我們已經用operator部署了一個helm chart,什么叫operator helm化?
其實很好理解,觀察下我們上述的部署操作,如果我們把CRD、role_binding、service_account等等這些放到一個Chart里面,則通過helm install的方式可以直接安裝operator,再通過create特定的cr,創建對應的資源。
可以參考jaeger-operator
注:遇到一個坑,刪除不掉CR和CRD
運行kubectl delete -f deploy/crds/example_v1alpha1_nginx_cr.yaml
之后,nginx pod沒有按預期被刪除掉。發現資源仍然存在,所以operator監聽不到資源的銷毀
# 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方式目前僅適用于創建、更新,對于備份、恢復之類的操作,沒有顯式的擴展支持。