玩轉Kubernetes Operator就是這麼簡單!


衆所周知,在Kubernetes中管理有狀態的服務是困難的。操做器(Operator)模式就是爲了處理這個問題而建立的,可是現有的框架要求用戶熟悉Go和Kubernetes控制器模式。mysql


大約一年前,咱們開啓了新的開源項目KUDO,即Kubernetes通用聲明性框架Operator(Kubernetes Universal Declarative Operator)。KUDO是Kubernetes Operator的開發工具和運行時,經過幾行YAML的聲明性方式,取代了數萬行的複雜代碼庫,使編寫操做器變得高效和簡單,容許Operator開發者和最終用戶使用他們已知的工具來管理有狀態服務。KUDO提供了基於DC/OS Commons SDK的一致性生命週期運維方式,而且基於大規模集羣的分佈式有狀態應用生產運行經驗,尤爲適用於企業生產運營。git


雖然KUDO的目標是解決在Kubernetes運行有狀態應用時所出現的問題,但它同時適用於你想在集羣上面運行的任何應用——從一個簡單的收尾工做直至服務的生產就緒安裝,例如Apache Kafka。github


自開發KUDO到如今已有一年時間,本文着重對KUDO的實際操做進行介紹,尤爲對Operator開發者以及服務部署和管理負責人有所助益。web



Part 1sql

基於Kubernetes的有狀態應用shell


Kubernetes等容器編排引擎(COE)的工做原理是聲明狀態,您能夠定義一個目標,如服務等,明確參數(parameters),剩下就交給COE了,它會對你的要進行編排,並保證明現。這是專爲有狀態應用設計的,效果很好。這一類應用不管是否在運行都是二進制且短暫的,它們不須要在磁盤或網絡中保留數據,也無需向其它應用事例分享狀態信息。


這種方式強化了微服務架構模式,用戶能夠自由支配在容器中運行的應用數量,以知足容量和彈性的須要。無狀態應用功能也被包含在這一範式參數中,由COE決定工做負載的位置以及爲什麼使用。
 
然而,這個環境可能對二級應用即有狀態工做負載很是不友好。Kubernetes調度程序的一個基本特質就是它能夠將Pod轉移至它認爲合適的位置,但有狀態應用在運維過程當中不適合被改變磁盤或網絡的接入路徑,保障數據的一致性和服務的可用性至少須要一系列的複雜步驟。不只如此,在不一樣服務中,部署、擴展等標準任務的步驟也徹底不一樣,好比,Kafka就與Cassandra或HDFS部署不一樣。

Part 2json

StatefulSetsapi


爲了運行有狀態應用服務,Kubernetes引入StatefulSets。StatefulSets的功能包括一致且特有的網絡和存儲識別,以及對獨特性和特定部署和拓展順序的約束。
 
不過,SetfulSet不是萬能的。因爲其控制器的通用性,SetfulSet對Pod沒有任何洞察,也不可觀測。所以,這樣的運維是很粗糙的,即便順序可被定義,但它不能處理特殊狀況,好比沒法識別複製狀態、集羣狀態等,更不用提在這些狀態的基礎上採起什麼行動了。然而,有狀態應用幾乎都是獨一無二的,進一步加重了這一問題。


Part 3微信

Operator網絡


Kubernetes從設計上就是高度模塊化的,其離散的基礎架構組件(即Controller,控制器)封裝了目標相關邏輯,如ReplicaSets和DaemonSets,由replica-controller和daemon-controller分別管理。 Kubernetes在靈活性和延展性方面有強大的優點; 同時,它還能夠在基礎功能上繼續發展,經過編寫自定義控制器來定製資源定義(CRD),以呈現新功能。 這兩個功能相結合就能夠支撐起新的模式,解決在管理及編排有狀態應用(即Kubernetes Operators)時出現的上述問題。
 
KubernetesOperator是由定製化的控制器和一套CRD組成的,其中控制器包含了管理特定運維所須要的知識,CRD則提供了API原語,這是在與集羣中運行的應用程序互動時所須要的。 也就是說,應用管理員無需與COE糾纏,就能夠將複雜的運維工做委託給已在Operator控制器編譯好的邏輯。
 
這種模式的成功,促使Kubernetes Operator被大規模使用,使得基礎架構師和應用管理員的工做變得格外輕鬆。 不過,若是您想本身手動編寫呢? 若是您使用的Kubernetes Operator功能或覆蓋範圍還不能知足您的需求呢?
 
首先,Kubernetes Operator要作到生產就緒是很複雜的,必須處理邊緣用例以及綜合測試,這就要完成大量的軟件工程工做。 好比,官方Elastic operator的代碼已經超過了5萬行,不少企業沒法承受這樣的工做量。 其次,Kubernetes Operator缺少一致性。 每一個Operator都是獨特的,管理員如何與它的CRD互動是不一樣的。 第三,Kubernetes項目開發和發佈變化的速度以及的速度之快使人驚歎。 反過來,這意味着Operator開發人員必須時刻關注這些最新的開發成果,這進一步加重了在公司內部進行這項工做所須要的工程工做量。


爲了解決上述全部的問題,KUDO應運而生


0 1
KUDO簡介


KUDO並不從無到有地開發一個Operator,而是提供一個標準方法,讓用戶專一於高水平的基礎架構與應用資源的協調。


02
KUDO概念


KUDO是由不少構件組成的——一個通用的控制器、一套CRD和KUDO CLI。 前兩個組件已部署在已有的Kubernetes集羣,CLI則能夠簡化經各類源代碼的Operator安裝。 這些KUDO Operator使KUDO具有了成爲咱們應用或服務Kubernetes Operator的全部條件; KUDO能夠被視爲「meta-operator」。 這些構件是這樣組合在一塊兒的:



在具體分析範例以前,咱們先看看KUDO帶來的概念,首先是經過它的CRD。

0 1
Plan


KUDO壓縮一個運維任務的方式就是Plan,相似於運行手冊。 在整個運維生命週期中,它保障了應用管理的一致性。 爲了改善構成並提升再利用率,Plan的結構通過了精心設計,它由多個Phase(階段)組成,Phase又由多個Step(步驟)組成。 KUDO讓您爲Phase(階段)和Tasks(任務)選擇串行或並行的策略。 好比,在部署ZooKeeper集羣時,您能夠並行啓動集羣中全部的Pod,它們最終會融合。 至於Kafka, 在Pod中運行的Brokers須要被連續建立,等到一個活性環境出現時再轉移至他處。


02
Operator 及OperatorVersion CRD


KUDO Operator是對可部署服務的高水平描述。 如上所述,它可能就像您管理批量做業同樣簡單,或者是一個服務,像分佈式有狀態應用同樣複雜的服務,就如Apache Cassandra和Apache Kafka。
 
Operator Version是Operator的具體實現。 正是經過CRD, KUDO Operator的開發人員可使用其爲KUDO提供所有的所需信息,從而成爲用戶的應用程序Operator。 OperatorVersion包含StatefulSets、poddisruptionbudget、PersistentVolumeClaims等全部模板化資源。
 
一個給定的KUDO Operator能夠有多個OperatorVersions。 這意味着KUDO可以捕獲並記錄運維細節,即便不一樣版本之間存在大量實例,也不會致使衝突。 例如,參考對現有數據進行備份的過程; 這種方法可能會在應用程序的特定版本之間發生變化,可是在給定的OperatorVersion中能夠捕捉其中的細微差異。 管理員能夠針對任何支持的版本觸發備份,由於他知道底層的KUDO Operator會作正確的事情。


03

Instance CRD


KUDO CRD實例表示應用程序的實例化,並綁定到OperatorVersion。 一旦實例被建立,KUDO將處理Operator Plan中的相關Phase,默認狀況下這會被看做是「Deploy」操做。
 
您能夠經過Instance CR建立應用程序的多個實例,並結合擁有多個OperatorVersions的能力,這讓管理員可以更輕鬆地跨版本運行,而不會形成應用程序自動化和運維方面的問題。

使用KUDO部署和管理服務


爲了將以上內容結合在一塊兒,咱們會把KUDO和一個Operator一塊兒安裝到Kubernetes集羣。 在本例中,我使用了一個經Konvoy部署的集羣,您也可使用KinD或Minikube之類的工具自行測試。


01

將KUDO部署到集羣


首先咱們要安裝KUDO CLI。 雖然KUDO只是Kubernetes——沒有專用API,也沒有DSL須要學習——可是KUDO CLI kubectl擴展使得與KUDO提供的CRD交互時變得更加容易。 要安裝CLI,您可使用Homebrew,獲取最新版本的二進制文件,或者從源代碼安裝。 在本次示例中我使用的是macOS,因此我能夠經過brew安裝:
 
*注意: 對於下面的示例,以$爲前綴的輸出表示個人shell提示符,並顯示示例輸出。 沒有$的部分能夠直接複製和粘貼使用。


brew tap kudobuilder/tap

brew install kudo-cli


如今個人$PATH中有一個kubectl-kudo二進制文件,我能夠運行kubectl kudo子命令:


$ kubectl kudo --version

kubectl-kudo version 0.6.0


有了這些先決條件,我如今可使用kubectl kudo init命令來將KUDO控制器以及CRD和其餘須要的對象部署到個人集羣中,並驗證這些都是部署都是恰當的:


$ kubectl kudo init
$KUDO_HOME has been configured at /Users/nick/.kudo
$ kubectl api-resources --api-group kudo.dev
NAME               SHORTNAMES APIGROUP   NAMESPACED KIND
instances                       kudo.dev true Instance
operators                       kudo.dev true Operator
operatorversions                kudo.dev true OperatorVersion
planexecutions                  kudo.dev true PlanExecution
$ kubectl get pods -n kudo-system
NAME                        READY STATUS RESTARTS AGE
kudo-controller-manager-0   1/1 Running 0 23m


02
安裝ZooKeeper KUDO Operator


在這一點上,咱們能夠與上面描述的KUDO CRD進行交互。 當前咱們尚未安裝Operator,因此讓咱們先經過安裝KUDO ZooKeeper Operator來糾正這個問題:


$ kubectl get operators
No resources found.
$ kubectl get instances
No resources found.
$ kubectl kudo install zookeeper --instance zk
operator.kudo.dev/v1alpha1/zookeeper created
operatorversion.kudo.dev/v1alpha1/zookeeper-0.1.0 created
instance.kudo.dev/v1alpha1/zk created
$ kubectl get pods
NAME             READY STATUS           RESTARTS AGE
zk-zookeeper-0   0/1 ContainerCreating   0 3s
zk-zookeeper-1   0/1 ContainerCreating   0 3s
zk-zookeeper-2   0/1 ContainerCreating   0 3s
# And then after a minute or so, depending>$ kubectl get pods
NAME             READY STATUS RESTARTS   AGE
zk-zookeeper-0   1/1 Running 0          54s
zk-zookeeper-1   1/1 Running 0          54s
zk-zookeeper-2   1/1 Running 0          54s


這樣,咱們就擁有了一個正在工做的ZooKeeper集羣。 太棒了!
 
讓咱們詳細分析一下到底發生了什麼,咱們經過kubectl kudo安裝了zookeeper——那麼instance zk command都爲咱們作了什麼?
  • 從KUDO Operator社區資源庫中安裝處理ZooKeeper Operator (若是尚未的話);
  • 默認狀況下,安裝觸發部署Plan,從而建立咱們的ZooKeeper Instance。 注意,能夠經過——skip-instance選項跳過這一步;
  • KUDO會爲咱們建立一個3節點的ZooKeeper集羣。 默認狀況下是3節點集羣,所以這裏不須要指定任何其餘內容;
  • instance zk option選項容許咱們命名Instance。 全部Instance必須有一個惟一名稱; 若是咱們不指定一個,那麼KUDO會自動爲咱們建立一個,但爲了方便,我在這個演示中選擇本身命名。
 
另外須要注意的是,全部3個ZooKeeper pods都是在同一時間出現的。 這是由於部署階段的相關策略被設置爲parallel(並行)。
 
爲了進一步驗證咱們的ZooKeeper實例,咱們能夠運行更多的命令,好比:


$ kubectl get instances
NAME   AGE
zk     9m18s
$ kubectl kudo plan status --instance zk
Plan(s) for "zk" in namespace "default":
.
└── zk (Operator-Version: "zookeeper-0.1.0" Active-Plan: "zk-deploy-554891141")
   ├── Plan deploy (serial strategy) [COMPLETE]
   │  ├── Phase zookeeper (parallel strategy) [COMPLETE]
   │  │ └── Step everything (COMPLETE)
   │  └── Phase validation (parallel strategy) [COMPLETE]
   │     └── Step validation (COMPLETE)
   └── Plan validation (serial strategy) [NOT ACTIVE]
       └── Phase connection (parallel strategy) [NOT ACTIVE]
           └── Step connection (parallel strategy) [NOT ACTIVE]
               └── connection [NOT ACTIVE]
$ kubectl get events --field-selector involvedObject.name=zk
LAST SEEN   TYPE REASON                OBJECT MESSAGE
37m         Normal CreatePlanExecution   instance/zk Creating "deploy" planExecution execution
37m         Normal PlanCreated           instance/zk PlanExecution "zk-deploy-554891141" created
36m         Normal PlanComplete          instance/zk PlanExecution zk-deploy-554891141 completed


第二個命令展現了KUDO CLI如何以對用戶更便捷的方式解釋和設計Kubernetes API的輸出。


03
安裝Apache Kafka KUDO Operator


成功部署ZooKeeper以後,咱們就能夠把注意力轉移到Kafka上了。 和ZooKeeper同樣,KUDO讓這一切變得很是簡單:


$ kubectl kudo install kafka --instance=kafka -p BROKER_MEM=1024m
operator.kudo.dev/v1alpha1/kafka created
operatorversion.kudo.dev/v1alpha1/kafka-0.2.0 created
instance.kudo.dev/v1alpha1/kafka created
$ kubectl get pods
NAME             READY STATUS           RESTARTS AGE
kafka-kafka-0    0/1 ContainerCreating   0 4s
# [..]
$ kubectl get pods
NAME             READY STATUS           RESTARTS AGE
kafka-kafka-0    1/1 Running           0 39s
kafka-kafka-1    1/1 ContainerCreating   0 18s
# [..]
$ kubectl get pods
NAME             READY STATUS RESTARTS   AGE
kafka-kafka-0    1/1 Running 0          96s
kafka-kafka-1    1/1 Running 0          75s
kafka-kafka-2    1/1 Running 0          58s
# [..]


這裏咱們作了一些不一樣的事情; 咱們將覆蓋其中一個默認參數BROKER_MEM,並將其值下降到1024Mb。 在上面的輸出中,我嘗試展現的另外一件事是Kafka部署計劃有不一樣的策略——串行,所以KUDO負責依次部署每一個代理的Pod。
 
如今,我將爲個人Kafka集羣生成一些負載,並經過Grafana監控資源的使用狀況。 Konvoy提供了全部您須要的東西來監控Kubernetes自己以及您部署的服務,因此在這個例子中,只需點擊Konvoy門戶中的「Grafana Dashboard」按鈕:



爲了得到Kafka的度量數據,咱們須要執行兩個額外的步驟。 咱們將經過PrometheusOperator添加一個ServiceMonitor對象:


$ kubectl apply -f - << EOF
heredoc> apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
 labels:
   app: prometheus-operator
   release: prometheus-kubeaddons
 name: kafka-cluster-monitor
spec:
 endpoints:
 - interval: 30s
   port: metrics
 selector:
   matchLabels:
     kudo.dev/servicemonitor: "true"
heredoc> EOF
servicemonitor.monitoring.coreos.com/kafka-cluster-monitor created


*注意: Prometheus Operator是預先安裝在Konvoy集羣上的; 若是您部署到另外一個Kubernetes集羣,那麼您首先須要本身安裝這個Operator,以便從咱們的KUDO Kafka Operator默認提供的監控端點收集信息。
 
如今我能夠安裝定製的Kafka Dashboard( https://github.com/kudobuilder/operators/blob/master/repository/kafka/docs/latest/resources/grafana-dashboard.json ),它是由KUDO Kafka Operator提供的,幫助我觀測個人集羣:



如今讓咱們經過增長代理計數和同時分配更多內存來擴展部署:


$ kubectl kudo update --instance kafka -p BROKER_MEM=4096m -p BROKER_COUNT=5
Instance kafka was updated.
$ kubectl describe instance kafka | grep -A5 Spec
Spec:
 Operator Version:
   Name:  kafka-0.2.0
 Parameters:
   BROKER_COUNT:  5
   BROKER_MEM:    4096m
$ kubectl get pods | grep kafka
kafka-kafka-0                                   1/1 Running 0 13m
kafka-kafka-1                                   1/1 Running 0 13m
kafka-kafka-2                                   1/1 Running 0 12m
kafka-kafka-3                                   0/1 Pending 0 64s
# [..]
kafka-kafka-0                                   1/1 Running 0 30m
kafka-kafka-1                                   1/1 Running 0 30m
kafka-kafka-2                                   0/1 ContainerCreating 0 10s
kafka-kafka-3                                   1/1 Running 0 18m
kafka-kafka-4                                   1/1 Running 0 55s


只需一小會兒,KUDO將負責添加額外的代理,並從新啓動那些改變了Pod內存分配的代理。 如今,若是觀察個人Grafana Dashboard,我能夠看到個人集羣中有5個活躍的代理:



04
自建一個KUDO Operator


正如先前的演示中您看到的,經過Operator使用KUDO部署和管理應用程序很是簡單。 應用程序和基礎設施的管理員可使用相同的操做流程,不論他們須要管理什麼樣的服務。
 
可是,自建一個KUDO Operator會怎麼樣呢? 這也很簡單,讓咱們經過MySQL Operator的例子來理解它所涉及的內容。
 
KUDO Operator有一個簡單的文件夾架構:


$ pwd
/Users/nick/src/kudo-mysql-operator/operator
$ tree
.
├── operator.yaml
├── params.yaml
└── templates
   ├── backup-pv.yaml
   ├── backup.yaml
   ├── init.yaml
   ├── mysql.yaml
   ├── param.yaml
   └── restore.yam


在Operator文件夾的根目錄中有兩個文件: operator.yaml和params.yaml。 而後是一個模板子目錄,其中包含咱們但願從Plan中引用的任何模板化的yaml文件。 Plan的組成以下:


Plan foo
├─ Phase bar
│  ├─ Step qux
│  └─ Step quux
└─ Phase baz
  ├─ Step quuz
  ├─ Step corge
  └─ Step grault


因此一個Plan能夠有多個Phase,每一個Phase都有一組相關的步驟。 對於給定的步驟,咱們定義任務,這些任務引用保存Kubernetes對象的模板化YAML文件。 當KUDO執行一個Plan時,它會根據策略編譯全部這些內容並呈現任何模板化參數。 咱們一塊兒來看一段MySQL Operator的operator.yaml文件:


plans:
 deploy:
   strategy: serial
   phases:
     - name: deploy
       strategy: serial
       steps:
         - name: deploy
           tasks:
             - deploy
         - name: init
           tasks:
             - init
         - name: cleanup
           tasks:
             - init
           delete: true


咱們的Plan中有一個Phase被簡稱爲「deploy」(部署),它引用了一系列步驟——deploy部署、init初始化和cleanup清理。 若是在此文件中進一步操做這個例子任務:


tasks:
 deploy:
   resources:
     - mysql.yaml
 init:
   resources:
     - init.yaml


deploy任務只列出一個資源,即mysql.yaml。 init也有一個與它相關聯的資源- init.yaml。 這些文件的內容對於在Kubernetes運行過服務的任何人來講都應該很熟悉。 例如,mysql.yaml 包含三個對象: 服務定義、PersistentVolumeClaim和定義MySQL容器的部署。
 
這些模板文件中的參數是什麼? 這些參數就是params.yaml。 這個基本的MySQL Operator只有幾個定義:


BACKUP_FILE:
 description: "Filename to save the backups to"
 default: "backup.sql"
 displayName: "BackupFile"
 trigger: backup
PASSWORD:
 default: "password"


以後咱們會在資源模板中使用它們,這是來自backup.yaml的資源模板:


apiVersion: batch/v1
kind: Job
metadata:
 namespace: default
 name: {{ .PlanName }}-job
spec:
 template:
   metadata:
     name: {{ .PlanName }}-job
   spec:
     restartPolicy: OnFailure
     containers:
     - name: bb
       image: mysql:5.7
       imagePullPolicy: IfNotPresent
       command:
       - /bin/sh
       - -c
       - "mysqldump -u root -h {{ .Name }}-mysql -p{{ .Params.PASSWORD }} kudo > /backups/{{ .Params.BACKUP_FILE }}"
       volumeMounts:
       - name: backup-pv
         mountPath: /backups
     volumes:
     - name: backup-pv
       persistentVolumeClaim:
         claimName: {{ .Name }}-backup-pv


KUDO使用Go模板和Sprig來提供各類功能,這爲模板值的派生提供了很大的靈活性,同時使用起來很是簡單。
 
MySQLOperator僅是一個POC,所以功能還遠遠不夠完善。 要得到更全面的示例,請查看KUDO KafkaOperator:
https://github.com/kudobuilder/operators/tree/master/repository/kafka/docs/latest
 
還有一個比較詳細的指南來幫助您構建屬於本身的KUDO Operator,那就是以ElasticSearch爲例進行構建:
https://github.com/realmbgl/kudo-tutorial


KUDO的社區及其將來發展


首先,KUDO是一個開源的、社區主導的項目。 全部的開發都是公開進行的,你們會在KubernetesSlack上的#kudo頻道進行討論,GitHub上也有一些關於開發的相關報道。 若是您對KUDO感興趣,如今正是時候,您能夠在不少領域大展身手。 而KUDO自己也正在申請CNCF的Sandbox項目,您也能夠參與其中。
 
雖然KUDO做爲一個項目還處於早期階段,但它已經足夠全面,可以構建隨時能夠投入生產的Operator。 KUDO的路線圖上有許多使人興奮的特性,將有助於加速企業應用速度,激發雲原生社區關注度。 這些特性包括:
  • 使用KUDO提供的編排功能擴展Helm charts和Cloud Native Application Bundles(CNAB)
    詳見: https://github.com/kudobuilder/kudo/blob/master/keps/0013-external-specs.md
  • 動態CRD: 爲基礎設施和應用程序管理員提供一種擴展方式,或是添加現有KUDO Operator的操做功能,而無需安裝新版本
  • Operator擴展: 擴展機制將爲管理員提供一種不須要上一級的Operator幫助,便可添加或修改現有功能的簡單方法,不用承受維護的負擔
    詳見: https://github.com/kudobuilder/kudo/blob/master/keps/0012-operator-extensions.md
  • Operator相關性——這包括現有實例之間的相關性,能夠基於前一階段的輸出來構建綜合管道。 (所以在上面的Kafka和ZooKeeper示例中,前者將默認須要並做爲依賴項安裝後者)
    詳見: https://github.com/kudobuilder/kudo/blob/master/keps/0017-pipe-tasks.md
  • Operator工具包: 使KUDO Operator的開發更加容易,包括「skeleton」模板生成、linting等功能。
    詳見: https://github.com/kudobuilder/kudo/blob/master/keps/0009-operator-toolkit.md
 
若是您有興趣讓KUDO成長的更加完善,咱們的官網上有一個入門指南,能讓您以最快速度開始使用和開發:
https://kudo.dev/docs/#getting-started
 
若是您有任何問題或反饋,或者您對KUDO的發展路線有哪些建議,歡迎您與咱們聯繫:
https://github.com/orgs/kudobuilder/projects/2


在明天的D2iQ北京雲原生會議中,咱們將爲您現場演示和講解KUDO,最後報名機會,精彩不容錯過!



活動信息


D2iQ首期雲原生主題論壇(北京站)


時間:10月25日(星期五)


地點: 北京市東城區金魚衚衕5-15號華爾道夫酒店,2層宴會廳;
活動福利: 會議當天咱們除了爲來賓準備精美的午飯外,還將設置現場抽獎環節,多種好禮等您來拿;
報名方式: 長按識別下方二維碼,進入報名頁面。



往期精彩文章

「劇透」10月25日北京D2iQ雲原生主題論壇演講陣容

技術分享與實踐經驗左右開弓,助力企業雲原生落地


CNCF網絡研討會:介紹Kubernetes通用聲明操做器:KUDO(視頻+PDF)

講者:Gerred Dillon,員工工程師@D2iQ


Webinar丨利用Konvoy加速雲原生Kubernetes部署分享

D2iQ首期雲原生大講堂乾貨內容分享

「閱讀原文」瞭解更多信息

本文分享自微信公衆號 - D2iQ(d2iq_apac)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索