operator簡介

2023-03-15 06:00:40

原理

operator 是一種 kubernetes 的擴充套件形式,利用自定義資源物件(Custom Resource)來管理應用和元件,允許使用者以 Kubernetes 的宣告式 API 風格來管理應用及服務。

  • CRD (Custom Resource Definition): 允許使用者自定義 Kubernetes 資源,是一個型別;
  • CR (Custom Resourse): CRD 的一個具體範例;
  • webhook: 它本質上是一種 HTTP 回撥,會註冊到 apiserver 上。在 apiserver 特定事件發生時,會查詢已註冊的 webhook,並把相應的訊息轉發過去。按照處理型別的不同,一般可以將其分為兩類:一類可能會修改傳入物件,稱為 mutating webhook;一類則會唯讀傳入物件,稱為 validating webhook。
  • 工作佇列: controller 的核心元件。它會監控叢集內的資源變化,並把相關的物件,包括它的動作與 key,例如 Pod 的一個 Create 動作,作為一個事件儲存於該佇列中;
  • controller :它會迴圈地處理上述工作佇列,按照各自的邏輯把叢集狀態向預期狀態推動。不同的 controller 處理的型別不同,比如 replicaset controller 關注的是副本數,會處理一些 Pod 相關的事件;
  • operator:operator 是描述、部署和管理 kubernetes 應用的一套機制,從實現上來說,可以將其理解為 CRD 配合可選的 webhook 與 controller 來實現使用者業務邏輯,即 operator = CRD + webhook + controller。

工作流程

  1. 使用者建立一個自定義資源 (CRD);
  2. apiserver 根據自己註冊的一個 pass 列表,把該 CRD 的請求轉發給 webhook;
  3. webhook 一般會完成該 CRD 的預設值設定和引數檢驗。webhook 處理完之後,相應的 CR 會被寫入資料庫,返回給使用者;
  4. 與此同時,controller 會在後臺監測該自定義資源,按照業務邏輯,處理與該自定義資源相關聯的特殊操作;
  5. 上述處理一般會引起叢集內的狀態變化,controller 會監測這些關聯的變化,把這些變化記錄到 CRD 的狀態中。

構建工具

兩者實際上並沒有本質的區別,它們的核心都是使用官方的 controller-tools 和 controller-runtime。

operator SDK

operator framework,是 CoreOS 公司開發和維護的用於快速建立 operator 的工具,可以幫助我們快速構建 operator 應用。

安裝

#下載operator sdk
wget https://github.com/operator-framework/operator-sdk/releases

建立專案

mkdir -p /root/go/src/github.com/memcached-operator
cd /root/go/src/github.com/memcached-operator
operator-sdk init --domain example.com --repo github.com/memcached-operator

建立API

operator-sdk create api --group cache --version v1alpha1 --kind Memcached --resource --controller

專案結構

# tree
.
├── api
│   └── v1alpha1
│       ├── groupversion_info.go
│       ├── memcached_types.go
│       └── zz_generated.deepcopy.go
├── bin
│   └── controller-gen
├── config
│   ├── crd
│   │   ├── kustomization.yaml
│   │   ├── kustomizeconfig.yaml
│   │   └── patches
│   │       ├── cainjection_in_memcacheds.yaml
│   │       └── webhook_in_memcacheds.yaml
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   └── manager_config_patch.yaml
│   ├── manager
│   │   ├── controller_manager_config.yaml
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── manifests
│   │   └── kustomization.yaml
│   ├── prometheus
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   ├── rbac
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── memcached_editor_role.yaml
│   │   ├── memcached_viewer_role.yaml
│   │   ├── role_binding.yaml
│   │   └── service_account.yaml
│   ├── samples
│   │   ├── cache_v1alpha1_memcached.yaml
│   │   └── kustomization.yaml
│   └── scorecard
│       ├── bases
│       │   └── config.yaml
│       ├── kustomization.yaml
│       └── patches
│           ├── basic.config.yaml
│           └── olm.config.yaml
├── controllers
│   ├── memcached_controller.go
│   └── suite_test.go
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
├── main.go
├── Makefile
└── PROJECT

17 directories, 43 files

測試

將 CRD 安裝到k8s叢集中
make install
部署operator
make deploy
安裝CR範例
kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml

解除安裝operator

make undeploy
解除安裝CRD
make uninstall

kubebuilder

安裝

# 下載 kubebuilder
wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.1/kubebuilder_2.3.1_linux_amd64.tar.gz

建立專案

mkdir -p /root/go/src/github.com/testcrd-controller
cd /root/go/src/github.com/testcrd-controller

#--domain 指定了後續註冊 CRD 物件的 Group 域名
kubebuilder init --domain edas.io

建立API

kubebuilder create api --group apps --version v1alpha1 --kind Application 

引數說明:

  • group 加上之前的 domian 即此 CRD 的 Group: apps.edas.io;
  • version 一般分三種,按社群標準:
    • v1alpha1: 此 api 不穩定,CRD 可能廢棄、欄位可能隨時調整,不要依賴;
    • v1beta1: api 已穩定,會保證向後相容,特性可能會調整;
    • v1: api 和特性都已穩定;
  • kind: 此 CRD 的型別,類似於 Service 的概念;

專案結構

# ls
api  bin  config  controllers  Dockerfile  go.mod  go.sum  hack  main.go  Makefile  PROJECT
# tree
.
├── api
│   └── v1alpha1
│       ├── application_types.go
│       ├── groupversion_info.go
│       └── zz_generated.deepcopy.go
├── bin
│   └── manager
├── config
│   ├── certmanager
│   │   ├── certificate.yaml
│   │   ├── kustomization.yaml
│   │   └── kustomizeconfig.yaml
│   ├── crd
│   │   ├── bases
│   │   │   └── apps.edas.io_applications.yaml
│   │   ├── kustomization.yaml
│   │   ├── kustomizeconfig.yaml
│   │   └── patches
│   │       ├── cainjection_in_applications.yaml
│   │       └── webhook_in_applications.yaml
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   ├── manager_webhook_patch.yaml
│   │   └── webhookcainjection_patch.yaml
│   ├── manager
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── prometheus
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   ├── rbac
│   │   ├── application_editor_role.yaml
│   │   ├── application_viewer_role.yaml
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── role_binding.yaml
│   │   └── role.yaml
│   ├── samples
│   │   └── apps_v1alpha1_application.yaml
│   └── webhook
│       ├── kustomization.yaml
│       ├── kustomizeconfig.yaml
│       └── service.yaml
├── controllers
│   ├── application_controller.go
│   └── suite_test.go
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
├── main.go
├── Makefile
└── PROJECT

測試

將 CRD 安裝到k8s叢集中
make install
本地執行controller
make run
安裝CR範例
kubectl apply -f config/samples/
解除安裝CRD
make uninstall

建立webhook

kubebuilder create webhook --group apps --version v1alpha1 --kind Application --defaulting --programmatic-validation

案例

Mongodb

安裝mongodb operator

安裝mongodb範例

---
apiVersion: mongodbcommunity.mongodb.com/v1
kind: MongoDBCommunity
metadata:
  name: example-mongodb
spec:
  members: 1
  type: ReplicaSet
  version: "4.2.6"
  security:
    authentication:
      modes: ["SCRAM"]
  users:
    - name: my-user
      db: admin
      passwordSecretRef: # a reference to the secret that will be used to generate the user's password
        name: my-user-password
      roles:
        - name: clusterAdmin
          db: admin
        - name: userAdminAnyDatabase
          db: admin
      scramCredentialsSecretName: my-scram
  additionalMongodConfig:
    storage.wiredTiger.engineConfig.journalCompressor: zlib

# the user credentials will be generated from this secret
# once the credentials are generated, this secret is no longer required
---
apiVersion: v1
kind: Secret
metadata:
  name: my-user-password
type: Opaque
stringData:
  password: "123456"

使用mongodb

# kubectl exec -it example-mongodb-0 -n mongodb bash    
I have no name!@example-mongodb-0:/$ mongo
MongoDB shell version v4.2.6
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("51607c54-bc7d-4006-8ef6-a9ff0a2e767a") }
MongoDB server version: 4.2.6
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
	http://docs.mongodb.org/
Questions? Try the support group
	http://groups.google.com/group/mongodb-user
2021-08-23T03:21:29.304+0000 I  STORAGE  [main] In File::open(), ::open for '//.mongorc.js' failed with Permission denied
example-mongodb:PRIMARY> use admin
switched to db admin
example-mongodb:PRIMARY> db.auth('my-user', '123456')
1
example-mongodb:PRIMARY> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
example-mongodb:PRIMARY> exit

ECK

Elastic Cloud on Kubernetes(ECK)是一個 Elasticsearch Operator。 ECK 使用 Kubernetes Operator 模式構建而成,需要安裝在您的 Kubernetes 叢集內,其功能絕不僅限於簡化 Kubernetes 上 Elasticsearch 和 Kibana 的部署工作這一項任務。ECK 專注於簡化所有後期執行工作,例如:

  • 管理和監測多個叢集
  • 輕鬆升級至新的版本
  • 擴大或縮小叢集容量
  • 更改叢集設定
  • 動態調整本地儲存的規模(包括 Elastic Local Volume(一款本地儲存驅動器))
  • 備份

安裝 ECK 對應的 Operator 資源物件

#kubectl apply -f https://download.elastic.co/downloads/eck/1.6.0/all-in-one.yaml

Elasticsearch

建立單節點Elasticsearch 叢集
cat <<EOF | kubectl apply -f -
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: quickstart
spec:
  version: 7.13.2
  nodeSets:
  - name: default
    count: 1
    config:
      node.store.allow_mmap: false
EOF
建立三節點Elasticsearch的叢集

宿主機設定一下sysctl -w vm.max_map_count=262144

---
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: quickstart
spec:
  version: 7.13.2
  http:
    service:
      spec:
        type: NodePort
  nodeSets:
  - name: default
    count: 3
    podTemplate:
      spec:
        volumes:
        - name: elasticsearch-data
          emptyDir: {}
檢視es叢集狀態
# kubectl get elastic 
NAME                                                    HEALTH   NODES   VERSION   PHASE   AGE
elasticsearch.elasticsearch.k8s.elastic.co/quickstart   green    3       7.13.2    Ready   2m4s
# kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
quickstart-es-default-0   1/1     Running   0          2m13s
quickstart-es-default-1   1/1     Running   0          2m13s
quickstart-es-default-2   1/1     Running   0          2m13s
# kubectl get svc
NAME                      TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
kubernetes                ClusterIP   10.43.0.1    <none>        443/TCP    22d
quickstart-es-default     ClusterIP   None         <none>        9200/TCP   2m23s
quickstart-es-http        ClusterIP   10.43.0.51   <none>        9200/TCP   2m24s
quickstart-es-transport   ClusterIP   None         <none>        9300/TCP   2m24s
存取es叢集
# PASSWORD=$(kubectl get secret quickstart-es-elastic-user -o go-template='{{.data.elastic | base64decode}}')
# curl -u "elastic:$PASSWORD" -k "https://xx.xx.xx.xx:port"
{
  "name" : "quickstart-es-default-2",
  "cluster_name" : "quickstart",
  "cluster_uuid" : "_33mFEetTrCjkjKKJlbCCQ",
  "version" : {
    "number" : "7.13.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "4d960a0733be83dd2543ca018aa4ddc42e956800",
    "build_date" : "2021-06-10T21:01:55.251515791Z",
    "build_snapshot" : false,
    "lucene_version" : "8.8.2",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

#### kibana

##### 建立kibana

```yaml
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
  name: testkibana
spec:
  version: 7.13.2
  count: 1
  elasticsearchRef:
    name: quickstart
檢視kibna狀態
# kubectl get kibanas.kibana.k8s.elastic.co 
NAME         HEALTH   NODES   VERSION   AGE
testkibana   green    1       7.13.2    68s
# kubectl get svc|grep kibana
testkibana-kb-http                    ClusterIP   10.43.50.88     <none>        5601/TCP                                87s
存取kibana服務

設定kibana svc代理,將5601埠對映

# echo $(kubectl get secret quickstart-es-elastic-user -o=jsonpath='{.data.elastic}' | base64 --decode)
r0V8YQ1L51UavQOh8St8L913

#存取kibana頁面:
https://xx.xx.xx.xx:5601/

使用者名稱:elastic
密碼:r0V8YQ1L51UavQOh8St8L913