KubeSphere 閘道器的設計與實現(解讀)

語言: CN / TW / HK

作者:泓舟子,KubeSphere 後端研發工程師,雲原生愛好者,現專注於雲原生微服務方向。

KubeSphere 中為什麼需要閘道器?

如果需要將 K8s 叢集內的服務暴露到外部訪問有那些方式呢?可以通過將 Service 設定成 NodePort 方式暴露出去或者通過 Ingress 方式。另外使用 Ingress 方式可以實現將請求分發到一個或多個 Service,可以同一個 IP 地址下暴露多個服務等優勢。

但是對於 Ingress 方式而言,在 K8s 中只是內建了 Ingress CRD(可以建立 Ingress 資源),沒有內建 Ingress Controller,必須部署了 Ingress Controller 才能為 Ingress 資源提供外部訪問叢集內部服務的能力。而 KubeSphere 中的閘道器就是 Ingress Controller 。

閘道器的設計

KubeSphere v3.2 對閘道器進行了重構,在保留了原有閘道器功能的基礎上增加了以下幾點新功能:

  1. 啟用叢集和專案級別的閘道器:可以根據業務上的需求靈活選擇不同粒度的閘道器。
  2. 增減閘道器副本數:靈活調整副本數達到更高的可用性。
  3. 靈活配置 Ingress Controller 配置選項。
  4. 可指定閘道器應用負載安裝的位置:可選擇將閘道器應用負載安裝的位置指定某固定名稱空間或分別讓其位於各自專案名稱空間下。結合 KubeSphere 中的許可權管理,若讓資源位於各個專案名稱空間下,擁有該專案許可權的使用者也能檢視到閘道器資源。
  5. 閘道器日誌:集中查詢閘道器日誌,將分佈在各個副本的閘道器日誌集中起來查詢。
  6. 閘道器監控指標:監控閘道器中的一些指標,包括請求總量/成功率/延遲 等指標。

閘道器的實現

目前 K8s 支援和維護 AWSGCENginx Ingress 控制器,KubeSphere 使用 Ingress Nginx Controller 作為預設的閘道器實現,沒有做任何程式碼修改。

各個功能點的實現思路

  • 叢集和專案級別的閘道器:這個通過傳入引數覆蓋預設的 Helm Chart Values 來實現並在程式碼邏輯裡控制,如果啟用了叢集閘道器就不能啟用專案網關了;若啟用了專案閘道器又啟用了叢集閘道器,那麼通過兩個閘道器入口都可以訪問,只是這樣會有兩個 Ingress Controller 同時 Watch 相同的 Ingress 物件。
  • 增減閘道器副本數&配置 Ingress Controller 配置選項:這個通過傳入引數覆蓋預設的 Helm Chart Values 來實現,實現過程用到的 Helm Operator 將在後面重點介紹。
  • 可指定閘道器應用負載安裝的位置:可選擇將閘道器應用負載安裝的位置指定某固定名稱空間或分別讓其位於各自專案名稱空間下。這個在程式碼邏輯中控制,並做成了配置項,預設將所有資源安裝在 kubesphere-controls-system 下。

  • 閘道器日誌:使用到了 KubeSphere 中日誌元件,日誌元件會採集日誌資料然後儲存在 Elasticsearch 中,閘道器在查詢日誌過程就根據引數在 Elasticsearch 中查詢日誌。

  • 閘道器監控指標:使用到了 KubeSphere 中監控元件,KubeSphere 內部配置了 Prometheus 相關的引數採集 Ingress 相關指標,查詢監控資訊過程就根據監控元件中的 API 查詢相關資料。

下面重點介紹設計實現過程抽象出的 CRD 和如何巧妙地用 Helm Operator 整合。

抽象出 Gateway CRD 做適配

在設計上抽象了一個 Gateway CRD 來適配不同的 Ingress Controller,Gateway CRD 中包含設定 Ingress Controller 所需的公共屬性。KubeSphere API 和 UI 只與 Gateway CRD 互動。

```yaml

Gateway sample

apiVersion: gateway.kubesphere.io/v1alpha1 kind: Gateway metadata: name: kubesphere-router-proj1 namespace: kubesphere-controls-system # all Gateway workload will be created in the kubesphere-controls-system namespace by default. However, it's configurable in kubesphere-config when calling KubeSphere API. spec: controller: # controlpanel replicas. For ingress Controler that has controlpanel and workers. Reserved field. Changing on UI isn't supported yet. replicas: 1 # annotations of the controlpanel deployment. Reserved field. Changing on UI isn't supported yet. annotations: {}

# Watching scope, # enabled =true, watching for the project only. The user needs to specify the watching namespace. # enabled =false, Global gateway, watching for all namespaces. scope: enabled: false namespace: "" # defaults to .Release.Namespace

# gateway configurations. only key-value pair supported currently. config: max-bucket: 1m

# worker workload deployment configuration deployment: annotations: "servicemesh.kubesphere.io/enabled": "false" replicas: 1

# service: # Cloud LoadBalancer configurations for service annotations: "service.beta.kubernetes.io/qingcloud-load-balancer-eip-ids": "test-ip-id" # Service Type, only LoadBalancer and NodePort are supported type: LoadBalancer

```

整合 Nginx Ingress Controller

KubeSphere 使用 Nginx Ingress Controller 作為預設的閘道器實現。為了簡化部署步驟,我們集成了 Helm-operator-plugins 作為 Helm Operator

在 Helm Operator 中主要有以下關鍵點:

根據 watch.yaml 中配置的監聽指定 CRD 下的 CR 來建立或更新 Chart 資源。其中可以根據 CR spec 中的值覆蓋預設 Helm Chart 中的值,這是由 Helm Operator 中的機制決定的,詳見官方說明

如下的含義是需要 Watch gateway.kubesphere.io/v1alpha1 的 Nginx CR,如果有變化就觸發 Reconcile ,根據 chart 中配置的地址建立或更新對應的資源。

yaml - group: gateway.kubesphere.io version: v1alpha1 kind: Nginx chart: /var/helm-charts/ingress-nginx

在 KubeSphere 中的使用:

watchs.yaml 中就做了如下配置:

yaml - group: gateway.kubesphere.io version: v1alpha1 kind: Nginx chart: /var/helm-charts/ingress-nginx - group: gateway.kubesphere.io version: v1alpha1 kind: Gateway chart: /var/helm-charts/gateway

其中對 chart 而言:

  • Nginx 是用的官方的 Helm Chart,在打包 ks-controller-manager 時下載的官方 Helm Chart。詳見:https://github.com/kubesphere/kubesphere/blob/v3.2.0/build/ks-controller-manager/Dockerfile#L34
  • Gateway 是在 KubeSphere 中定製的 Helm Chart,裡面主要就操作了 Nginx CR 資源。詳見:https://github.com/kubesphere/kubesphere/blob/v3.2.0/config/gateway/templates/nginx-ingress.yaml

整體而言:

Helm Operator Watch 了 Gateway 和 Nginx 2 個 CRD 的資源,當前端發起建立或更新閘道器時是對 Gateway CR 發起建立或更新操作:

  1. 發起請求建立或更新 Gateway CR ;
  2. 根據 watchs.yaml 配置的 Gateway, Helm Operator 監聽到有 Gateway CR 資源變化,將建立或更新 Nginx CR ;
  3. 根據 watchs.yaml 配置的 Nginx,Helm Operator 監聽到 Nginx CR 資源變化後就根據 Nginx CR 中的 spec 中的值來覆蓋預設 Helm Chart 中的值來建立或更新 Nginx Ingress Contoller。

配置項的設計

為了方便更改閘道器的一些引數設計瞭如下配置項:

yaml gateway: watchesPath: /var/helm-charts/watches.yaml repository: kubesphere/nginx-ingress-controller tag: v1.1.0 namespace: kubesphere-controls-system

  • watchesPath:指定 Helm Operator Watch 的配置檔案,如果需要禁用 Helm Operator 就可以刪掉這個配置項。
  • repository:指定 nginx-ingress-controller 的倉庫。
  • tag:指定 nginx-ingress-controller 的 tag。
  • namespace:指定閘道器應用負載安裝的位置位於指定的名稱空間下,若刪掉這個配置項就會安裝在各個專案名稱空間下。

使用過程注意事項

  1. 如果啟用了 servicemesh ,在原有的 Ingress 需要加上額外的註解 nginx.ingress.kubernetes.io/upstream-vhost: [service-name].[service-namespace].svc.cluster.local 流量拓撲/鏈路追蹤可以正常工作,不然入口流量處會有異常。
  2. 修改閘道器相關屬性,比如:副本數、Nginx 配置項等,不能直接在相關的 deploy/configmap 等應用負載裡面修改,需要在閘道器設定中修改(修改的是 Gateway CR)。因為使用的是 Helm Operator 來管理控制閘道器相關資源的狀態,所有值都會以 Gateway CR 中的配置為準,改了閘道器相關應用負載中的值最終都會被 Helm Operator 還原掉。

參考:

  1. https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/
  2. https://github.com/kubesphere/community/blob/master/sig-microservice/concepts-and-designs/KubeSphere-gateway-operator-design.md
  3. https://github.com/kubesphere/kubesphere
  4. https://sdk.operatorframework.io/docs/building-operators/helm/

本文由部落格一文多發平臺 OpenWrite 釋出!