雲原生多雲應用利器 -- Karmada 控制器

語言: CN / TW / HK

在上一篇 《雲原生多雲應用利器--Karmada總覽篇》 中已經介紹了多雲的相關簡介的內容和架構。 接下來,在這一篇中來一起看看 Karmada 中有哪些 Controllers 來協調完成多雲的控制邏輯。

本文作者: 「Dao Cloud 道客」技術合夥人& 雲原生技術專家 熊中祥

Controller (控制器) 在 Kubernetes 中是邏輯能力的主要體現所在,根據資源物件的狀態來完成調和工作,讓資源物件逐步接近期待的狀態,這個就是 Kubernetes 的申明式特性。

在 Karmada 中,同樣需要對 Karmada 自己的資源物件,實現對應的申明式特性,這就需要實現對應的 Controller。在Karmada 中目前的版本中有 11 個 Controllers,接下來就從每一個控制器所負責的資源物件,以及原理來分析一下,在 Karmada 中是怎樣完成多雲能力的。

Karmada Controllers一覽表及原理分析

01

Cluster Controller

Cluster controller 主要就是處理 Cluster 資源物件的邏輯,負責處理 Cluster 對應需要的關聯資源。

相關資源物件:Cluster

  • 建立 Cluster 的時候,需要在 Karmada 中建立對應的 execution namespace,這個 namespace 中會儲存所有這個叢集相關的 Work 物件。

  • 刪除Cluster的時候,需要在 Karmada 中刪除對應的execution namespace。

  • Cluster 資源物件儲存在 karmada-cluster 這個 namespace 中,這個 namespace  中儲存了所有叢集對應的 Cluster 資源物件。

02

Cluster status controller

cluster status controller 主要就是處理 cluster status 資源物件的邏輯,用來收集 Cluster 的狀態,儲存到 Cluster 的 status 欄位中,同步上報到 Karmada 的控制平面中。

相關資源物件:Cluster

  • watch Cluster 物件,然後執行 sync 方法,同步上報叢集的狀態給Karmada 控制平面 (也就是 Karmada 叢集中,karmada-cluster 這個 namespace 中的某一個 cluster 物件)。

  • 收集當前 agent 所在叢集的狀態資訊,這些資訊包含 Nodes 統計,Pods 相關的資源統計,Kubernetes 版本,以及 Kubernetes 叢集支援的資源物件的型別的 GVR,其中包含 CRD 的支援資訊等,然後同步更新到 Karmada 控制平面 Cluster 物件的 status 中。具體的狀態包含哪些資訊,請檢視 《雲原生多雲應用利器—Karmada總覽篇》

03

namespace sync controller

namespace sync controller 主要就是處理 namespace 資源物件的邏輯,負責將 Karmada 控制平面建立的 namespace 在叢集中同步創建出來。

相關資源物件:namespace

  • namespace sync controller 就是為了將在 Karmada 中建立的 namespace 在所有的工作叢集中也去創建出來。

  • namespace 是 “karmada-cluster”,或者是 “karmada-system”,或者是 “default”, 或者 namespace 是 “karmada-es-<xxx>”, 或者是 “kube-<xxx>” 這樣 namespace 是不需要處理的。以及被包含在 SkippedPropagatingNamespaces 配置中的 namespace,也不需要處理。

04

Resourse Template controller

detector 模組中包含了通用 controller 負責 resource template 的 Kubernetes 資源物件的調和處理邏輯,以及匹配 PropagationPolicy。主要就是處理 PropagationPolicy 資源物件的邏輯,來派生出資源物件對應的 ResourceBinding 物件。

相關資源物件:PropagationPolicy, Kubernetes 支援的所有的資源物件 (包括 CRD)

  • 定義處理 PropagationPolicy / ClusterPropagationPolicy 的 informer,event handler,以及對應的 reconciler 方法。

  • 定義處理 ResourceBinding / ClusterResourceBinding 的 informer,event handler,以及對應的 reconciler 方法。

  • 定義處理所有原生 Kubernetes 資源物件的 informer,event handler,以及對應的 reconciler 方法,然後為其建立對應的 ResourceBinding 物件用於排程。

  • 根據 Kubernetes 的物件定義以及 PropagationPolicy 構建 ResourceBinding 物件,同時這個 ResourceBinding 的 OwnerReferences 設定了這個 Kubernetes 的物件,這樣就會在刪除 Kubernetes 物件的時候刪除這個 ResourceBinding,這個也是目前 ResourceBinding 會被刪除的唯一邏輯了。

  • 所以雖然 ResourceBinding 是因為 PropagationPolicy 的建立而被派生出來,但是不會因為 PropagationPolicy 的刪除而刪除。

  • 在刪除 PropagationPolicy 刪除的時候,只會去除 PropagationPolicy 和 Kubernetes 物件的關係,這個關係體現在,Kubernetes object 會在匹配到 PropagationPolicy 的時候在自己的 label 上增加 PropagationPolicy 相關的 label。

  • ResourceBinding 中不會包含 Kubernetes 資源物件的詳細資訊,只會包含型別,namespace,name,版本,副本數,cpu/memory 請求,節點親和性,真正詳細的 Kubernetes 物件的處理是在  controller 的syncbinding() 方法中完成,其中是通過workload, err := helper.FetchWorkload (c.DynamicClient,c.InformerManager,c.RESTMapper, binding.Spec.Resource) 去拿到真正的 Kubernetes 資源物件的定義的。

  • 每隔 30s 去發現新的 Kubernetes 的資源物件型別,只要這些資源物件支援 list,watch,delete 方法,當然也包括 crd 型別。

05

Binding controller

binding controller 主要就是處理 ResourceBinding 資源物件的增刪改邏輯,ResourceBinding 的調和能力是派生出 work 物件,work 物件是和特定叢集關聯的。一個 work 只能屬於一個叢集,代表一個叢集的資源物件的模型封裝。

相關資源物件:ResourceBinding 和 ClusterResourceBinding

  • 負責 ResourceBinding 的處理,根據 binding 去建立對應的 Work 物件到叢集對應的 execution space 中。

  • 在生成 Work 的時候,會處理 OverridePolicy,將需要覆蓋的資料更新到 Work 對應的 manifest 中。目前支援的 override 的方式主要是 4 種,包括:PlaintextOverrider,mageOverrider,CommandOverrider,ArgsOverrider。

apiVersion: policy.karmada.io/v1alpha1 
kind: OverridePolicy
metadata:
name: nginx-propagation
spec:
resourceselectors:
一 apiVersion: apps/v1
kind: Deployment name: nginx
targetcluster:
clusterNames:
-10-23-20-93
overriders:
plaintext:
一 path: "/spec/template/spec/containers/O/image"
operator: replace value: "nginx:test"
  • 根據排程器計算好的每一個叢集負責的副本數,如果排程器計算出來的所有叢集的對應的副本數是 0,說明沒有找合適的叢集,就用 ReplicaSchedulingPolicy 根據權重去計算每一個叢集應該負責的副本數,這個 ReplicaSchedulingPolicy 的計算副本分配的方式是用 static weight。

  • 收集每一個 binding 的狀態,一個 binding 會包含多個 Work,因為同一個資源物件,在每一個叢集中就需要一個 Work,所有 binding 的狀態是所有工作叢集中 Work 的狀態的彙總,彙總之後將這個狀態設定到 binding 的 status 中去。

備註: 原理圖參見第 4 部分的圖

06

execution controller

execution controller 主要就是處理 Work 資源物件的增刪改邏輯,用於處理 Work,將 Work 負責的 Kubernetes 資源物件在對應的叢集上創建出來。

相關資源物件:Work

  • watch Karmada 控制平面的 execution namespace 中的所有 Work 物件,當有新的 Work 物件被建立了之後會在對應的工作叢集中建立 Work 負責的資源物件。

  • watch Karmada 控制平面的 execution namespace 中的所有 Work 物件,當有 Work 物件被刪除的時候,會在工作叢集中,刪除 Work 物件負責的資源物件。watch Karmada 控制平面的 execution namespace 中的所有 Work 物件,當有 Work 物件被修改了之後,會在工作叢集中,修改 Work 物件負責的資源物件。

備註: 原理圖參見第 4 部分的圖

07

work status controller

work status controller 主要就是處理 Work 資源物件的狀態邏輯,負責收集 Work 的狀態,也就是 Work 對應的資源物件的狀態,只是這個狀態是儲存在 Work 的 status 欄位裡的。

相關資源物件:Work,以及 Work 負責的資源物件。

  • watch Work 物件為指定計算叢集包含的所有的 Work 物件所負責的資源物件的型別建立對應的 informer 物件,同時呼叫 informer 的 WaitForCacheSync,當 WaitForCacheSync 結束了之後,也就是 list 結束了,接下來就是 watch 的任務了。這個就是 list and watch 的核心機制。

  • 在 watch 所有 Work 負責的資源物件的時候,設定了一個事件處理器,這個事情處理器會負責處理所有相關資源物件的 Add,Update,Delete 事件。這些事件存放在 queue 中。

  • 啟動一個非同步的 AsyncWorker, 設定一定的 WorkerNumber 數量的 goroutines 去處理 queue 裡的資料,這裡的資料是帶有叢集資訊的 fedkey。 

  • 從 queue 中獲取 fedkey,判斷這個 fedkey 的對應的叢集中的資源物件,如果這個 Work 負責的資源物件在工作叢集中被非法刪除了,會重新在工作叢集中創建出對應的資源物件。

  • 從 queue 中獲取 fedkey,判斷這個 fedkey 的對應的叢集中的資源物件,如果這個 Work 負責的資源物件被修改了之後是不是修改被修改回去。如果是的話,會重新 sync 回資源物件,防止直接從工作叢集中直接修改資源物件。 

  • 收集 Work 物件對應的資源物件在 Worload 叢集中的執行狀態,然後更新到到控制平面的 Work 的 status 中。

  • watch Karmada 控制平面的 execution namespace 中的所有 Work 物件,當有新的 Work 物件被建立了之後會在對應的工作叢集中建立  Work 負責的資源物件。

08

serviceexport controller

serviceexport controller 主要就是處理 serviceexport 資源物件的狀態邏輯,將需要被其它叢集發現的服務暴露出來。

相關資源物件:ServiceExport

  • 當控制平面建立 ServiceExport 物件的時候,會對應的創建出 Work 物件,以及在對應的工作叢集中創建出 ServiceExport 物件。 

  • 查找出 ServiceExport 物件對應的 service 物件的 EndpointSlice 物件,將這些 EndpointSlice 物件封裝成 work 物件建立到控制平面中。 

  • 當在控制平面刪除 ServiceExport 物件的時候,會找到對應的 work 物件,將其刪除。這裡刪除的時候也會一起刪除由 ServiceExport 關聯上報上來的 EndpointSlice 物件對應的 Work 物件。因為查詢要刪除的 Work 的時候是根據服務名查詢的,而 ServiceExport 和 Serivce 對應的 EndpointSlice 的 Work 都是用服務名來建立的,所以查詢的時候會一起查詢到。

  • 當工作叢集的 EndpointSlice 發生變化的時候,也會同步去更新控制平面的 EndpointSlice 物件,因為 ServiceExport controller 是 watch 了每一個叢集的 ServiceExport 的 add 事件以及 EndpointSlice 的 add 和 update 事件的。只要 EndpointSlice 變化,就會同步到控制平面。這樣會觸發 PropagationPolicy 關聯的物件發生變化,就會觸發更新 EndpointSlice 對應的 Work,也就會同步更新 ServiceImport 叢集中由於 ServiceImport 而級聯出來的 EndpointSlice 了。

09

endpointslice controller

endpointslice controller 主要根據 serviceexport 資源物件對應到處的 Service,Service 對應的 endpointslice 上報到 Karmada 的控制面。

相關資源物件:EndpointSlice 相關的 Work

  • 負責將 work 中的 manifest 是 EndpointSlice 的 work 中的 EndpointSlice 物件,在 Karmada 控制平面中建立對應的 EndpointSlice 的物件。

  • 其中 Karmada 控制平面中的 EndpointSlice 的 namespace 就是和 work 中 manifest 中的 EndpointSlice 的 namespace 一樣。但是 Karmada 控制平面中的 EndpointSlice 的 name 不一樣,格式為:“imported-<cluster name>-<endpointslice name>”。

備註: 原理圖參見第 8 部分的圖

10

serviceimport controller

serviceimport controller 主要負責根據 ServiceExport 暴露出來的 Service,在自己負責的叢集中建立對應的 service,注意 service 的名稱不是完全一樣的,同時在自己負責的叢集中也建立對應的 EndpointSlice,這個 EndpointSlice 的資料就是來源於 EndpointSlice controller 中上報到 karmada 控制平面的 EndpointSlice 物件,具體是通過在 karmada-webhook 中給 ServiceImport 的 PropagationPolicy 中增加了 EndpointSlice 的下發能力。

相關資源物件:ServiceImport

  • 根據在 karmada 控制平面中建立的 ServiceImport ,去建立對應的 Service,這個 Service 是建立在 Karmada 控制平面的。

  • 如果控制平面中的 ServiceImport,也會刪除控制平面中的由這個 ServiceImport 派生出來的 Service。

  • 由於 ServiceImport 的 controller 中會在控制平面中建立 Service,同時由於 ServiceExport 的 controller 中,會建立一個被 export 的 Service 的 EndpointSlice 的 work 在控制平面中,這個 work 會被 EndpointSlice controller 控制,同時 EndpointSlice controller 在控制平面中建立對應的 EndpointSlice 物件,EndpointSlice 中的每一個 Endpoint 的 IP 都是 Pod 的 IP 地址。

  • 在建立 ServiceImport 需要的 PropagationPolicy 的時候會在 karmada-webhook 中修改 PropagationPolicy 的 resource selector,在其中增加 Service 和 EndpointSlice 的部分,helper.GetFollowedResourceSelectorsWhenMatchServiceImport(policy.Spec.ResourceSelectors)。 最後會隨著 detector 和 binding controller 中的邏輯,在對應的叢集的 execution 的 space 中建立對應 Service 和 EndpointSlice 的 work,然後由 execution controller 去對應的工作叢集去建立真正的資源物件。這樣在 ServiceImport 的叢集中,就可以通過派生出來的 Service,進行訪問遠端被 export 出來的服務。前提是兩個叢集之間的 Pod 網路是互通的。  

  • 由 ServiceImport 派生出來的 service 的 name 為 :“derived-<service name>”。

備註: 原理圖參見第 8 部分的圖

11

hpa controller

hpa controller 主要負責將 Karmada 控制面中建立的 HPA 物件通過建立 Work 的方式下發到對應的叢集中。

相關資源物件:HPA

  • 首先根據 HPA 的定義,獲取需要被 HPA 控制的資源物件物件,這裡主要就是指的像 Deployment 這種需要計算資源的物件。

  • 根據 HPA 控制的資源物件,去查詢這些資源物件對應的 ResourceBinding 的 cr 物件,因為 ResourceBinding 是最終反應 Deployment 被排程到哪些叢集的實時的,最終的狀態。

  • 根據找到的叢集,在這些叢集中建立每個叢集對應的 Work 物件,這個 Work 物件負責的資源物件就是 HPA 物件。

  • 通過這樣的實現,保證了 HPA 被建立的叢集一定是和真正的工作負載是在一個叢集中的,保證了 HPA 的正確的排程。

文章來源:道客船長

原文地址:http://mrw.so/6fI2XU

附:Karmada社群技術交流地址

專案地址:

https://github.com/karmada-io/karmada

Slack地址:

https://karmada-io.slack.com

掃描二維碼 | 加入 Karmada 技術交流群

社群專家入駐,技術問題隨時答疑