Kubernetes 多集羣項目介紹

Kubernetes 從 1.8 版本起就聲稱單集羣最多可支持 5000 個節點和 15 萬個 Pod,實際上應該很少有公司會部署如此龐大的一個單集羣,很多情況下因爲各種各樣的原因我們可能會部署多個集羣,但是又想將它們統一起來管理,這時候就需要用到集羣聯邦(Federation)。

集羣聯邦的一些典型應用場景:

Federation v1

最早的多集羣項目,由 K8s 社區提出和維護。

Federation v1 在 K8s v1.3 左右就已經着手設計(Design Proposal),並在後面幾個版本中發佈了相關的組件與命令行工具(kubefed),用於幫助使用者快速建立聯邦集羣,並在 v1.6 時,進入了 Beta 階段;但 Federation v1 在進入 Beta 後,就沒有更進一步的發展,由於靈活性和 API 成熟度的問題,在 K8s v1.11 左右正式被棄用。

v1 的基本架構如上圖,主要有三個組件:

在 v1 版本中我們要創建一個聯邦資源的大致步驟如下:把聯邦的所有配置信息都寫到資源對象 annotations 裏,整個創建流程與 K8s 類似,將資源創建到 Federation API Server,之後 Federation Controller Manager 會根據 annotations 裏面的配置將該資源創建到各子集羣;下面是一個 ReplicaSet 的示例:

這種架構帶來的主要問題有兩個:

Federation v2

有了 v1 版本的經驗和教訓之後,社區提出了新的集羣聯邦架構:Federation v2;Federation 項目的演進也可以參考 Kubernetes Federation Evolution 這篇文章。

v2 版本利用 CRD 實現了整體功能,通過定義多種自定義資源(CR),從而省掉了 v1 中的 API Server;v2 版本由兩個組件構成:

在 v2 版本中要創建一個聯邦資源的大致流程如下:

將 Federated Resource 創建到 Host 集羣的 API Server 中,之後 controller-manager 會介入將相應資源分發到不同的集羣,分發的規則等都寫在了這個 Federated Resource 對象裏面。

在邏輯上,Federation v2 分爲兩個大部分:configuration(配置)和 propagation(分發);configuration 主要包含兩個配置:Cluster Configuration 和 Type Configuration。

Cluster Configuration

用來保存被聯邦託管的集羣的 API 認證信息,可通過 kubefedctl join/unjoin 來加入 / 刪除集羣,當成功加入時,會建立一個 KubeFedCluster CR 來存儲集羣相關信息,如 API Endpoint、CA Bundle 和 Token 等。後續 controller-manager 會使用這些信息來訪問不同 Kubernetes 集羣。

apiVersion: core.kubefed.io/v1beta1
kind: KubeFedCluster
metadata:
  creationTimestamp: "2019-10-24T08:05:38Z"
  generation: 1
  name: cluster1
  namespace: kube-federation-system
  resourceVersion: "647452"
  selfLink: /apis/core.kubefed.io/v1beta1/namespaces/kube-federation-system/kubefedclusters/cluster1
  uid: 4c5eb57f-5ed4-4cec-89f3-cfc062492ae0
spec:
  apiEndpoint: https://172.16.200.1:6443
  caBundle: LS....Qo=
  secretRef:
    name: cluster1-shb2x
status:
  conditions:
  - lastProbeTime: "2019-10-28T06:25:58Z"
    lastTransitionTime: "2019-10-28T05:13:47Z"
    message: /healthz responded with ok
    reason: ClusterReady
    status: "True"
    type: Ready
  region: ""

Type Configuration

定義了哪些 Kubernetes API 資源要被用於聯邦管理;比如說想將 ConfigMap 資源通過聯邦機制建立在不同集羣上時,就必須先在 Host 集羣中,通過 CRD 建立新資源 FederatedConfigMap,接着再建立名稱爲 configmaps 的 Type configuration(FederatedTypeConfig)資源,然後描述 ConfigMap 要被 FederatedConfigMap 所管理,這樣 Kubefed controller-manager 才能知道如何建立 Federated 資源,一個示例如下:

apiVersion: core.kubefed.k8s.io/v1beta1
kind: FederatedTypeConfig
metadata:
  name: configmaps
  namespace: kube-federation-system
spec:
  federatedType:
    group: types.kubefed.k8s.io
    kind: FederatedConfigMap
    pluralName: federatedconfigmaps
    scope: Namespaced
    version: v1beta1
  propagation: Enabled
  targetType:
    kind: ConfigMap
    pluralName: configmaps
    scope: Namespaced
    version: v1

Federated Resource CRD

其中還有一個關鍵的 CRD:Federated Resource,如果想新增一種要被聯邦託管的資源的話,就需要建立一個新的 FederatedXX 的 CRD,用來描述對應資源的結構和分發策略(需要被分發到哪些集羣上);Federated Resource CRD 主要包括三部分:

一個示例如下:

apiVersion: types.kubefed.k8s.io/v1beta1
kind: FederatedDeployment
metadata:
  name: test-deployment
  namespace: test-namespace
spec:
  template: # 定義 Deployment 的所有內容,可理解成 Deployment 與 Pod 之間的關聯。
    metadata:
      labels:
        app: nginx
    spec:
      ...
  placement:
    clusters:
    - name: cluster2
    - name: cluster1
  overrides:
  - clusterName: cluster2
    clusterOverrides:
    - path: spec.replicas
      value: 5

這些 FederatedXX CRD 可以通過 kubefedctl enable <target kubernetes API type> 來創建,也可以自己生成 / 編寫對應的 CRD 再創建。

結合上面介紹了的 Cluster Configuration、Type Configuration 和 Federated Resource CRD,再來看 v2 版本的整體架構和相關概念就清晰很多了:

Scheduling

Kubefed 目前只能做到一些簡單的集羣間調度,即手工指定,對於手工指定的調度方式主要分爲兩部分,一是直接在資源中制定目的集羣,二是通過 ReplicaSchedulingPreference 進行比例分配。

直接在資源中指定可以通過 clusters 指定一個 cluster 列表,或者通過 clusterSelector 來根據集羣標籤選擇集羣,不過有兩點要注意:

spec:
  placement:
    clusters:
    - name: cluster2
    - name: cluster1
    clusterSelector:
      matchLabels:
        foo: bar

如果需要在多個集羣間進行區別調度的話就需要引入 ReplicaSchedulingPreference 進行按比例的調度了:

apiVersion: scheduling.kubefed.io/v1alpha1
kind: ReplicaSchedulingPreference
metadata:
  name: test-deployment
  namespace: test-ns
spec:
  targetKind: FederatedDeployment
  totalReplicas: 9
  clusters:
    A:
      minReplicas: 4
      maxReplicas: 6
      weight: 1
    B:
      minReplicas: 4
      maxReplicas: 8
      weight: 2

totalReplicas 定義了總副本數,clusters 描述不同集羣的最大 / 最小副本以及權重。

目前 ReplicaSchedulingPreference 只支持 deployments 和 replicasets 兩種資源。

Karmada

Karmada 是由華爲開源的多雲容器編排項目,這個項目是 Kubernetes Federation v1 和 v2 的延續,一些基本概念繼承自這兩個版本。

Karmada 主要有三個組件:

和 Federation v1 類似,我們下發一個資源也是要寫入到 Karmada 自己的 API Server 中,之前 controller-manager 根據一些 policy 把資源下發到各個集羣中;不過這個 API Server 是 K8s 原生的,所以支持任何資源,不會出現之前 Federation v1 版本中的問題,然後聯邦託管資源的分發策略也是由一個單獨的 CRD 來控制的,也不需要配置 v2 中的 Federated Resource CRD 和 Type Configure。

Karmada 的一些基本概念:

Cluster

Cluster 資源記錄的內容和 Federation v2 類似,就是訪問被納管集羣的一些必要信息:API Endpoint、CA Bundle 和訪問 Token。

spec:
  apiEndpoint: https://172.31.165.66:55428
  secretRef:
    name: member1
    namespace: karmada-cluster
  syncMode: Push

但是有一個不一樣的點是,Karmada 的 Cluster 資源有兩種 sync 模式:PushPullPush 就是最普通、最常見的方式,host 集羣的 Karmada 組件會負責同步並更新這類集羣的狀態;Pull 模式的 member 集羣上會運行一個 karmada-agent 組件,這個組件會負責收集自己的狀態並且更新 host 集羣的相應的 Cluster 資源狀態。

Propagaion Policy

在 Karmada 中分發資源到 member 集羣需要配置這個單獨 PropagationPolicy CR;以下面的 nginx 應用爲例,首先是 Resource Template,這個就是普通的 K8s Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx

之後配置一個 PropagationPolicy 來控制這個 nginx Deployment 資源的分發策略即可,在下面的示例中,會將 nginx 應用按 1:1 的權重比分發到 member1 和 member2 集羣中:

apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
  name: nginx-propagation
spec:
  resourceSelectors:
    - apiVersion: apps/v1
      kind: Deployment
      name: nginx
  placement:
    clusterAffinity:
      clusterNames:
        - member1
        - member2
    replicaScheduling:
      replicaDivisionPreference: Weighted
      replicaSchedulingType: Divided
      weightPreference:
        staticWeightList:
          - targetCluster:
              clusterNames:
                - member1
            weight: 1
          - targetCluster:
              clusterNames:
                - member2
            weight: 1

在 Karmada API Server 中創建這兩個資源後,可以通過 Karmada API Server 查詢到該資源的狀態:

$ kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   2/2     2            2           51s

但是注意,這並不代表應用運行在 Karmada API Server 所在的集羣上,實際上這個集羣上沒有任何工作負載,只是存儲了這些 Resource Template,實際的工作負載都運行在上面 PropagationPolicy 配置的 member1 和 member2 集羣中,切換到 member1/member2 集羣中可以看到:

$ kubectl get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           6m26s

$ kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6799fc88d8-7cgfz   1/1     Running   0          6m29s

分發策略除了上面最普通的指定集羣名稱外也支持 LabelSelectorFieldSelectorExcludeClusters,如果這幾個篩選項都設置了,那只有全部條件都滿足的集羣纔會被篩選出來;除了集羣親和性,還支持 SpreadConstraints:對集羣動態分組,按 regionzoneprovider 等分組,可以將應用只分發到某類集羣中。

針對有 replicas 的資源(比如原生的 DeploymentStatefulSet),支持在分發資源到不同集羣的時候按要求更新這個副本數,比如 member1 集羣上的 nginx 應用我希望有 2 個副本,member2 上的只希望有 1 個副本;策略有很多,首先是 ReplicaSchedulingType,有兩個可選值:

而這個 ReplicaDivisionPreference 又有兩個可選值:

完整和詳細的結構可以參考 Placement 的 API 定義。

Override Policy

Override Policy 就很簡單了,通過增加 OverridePolicy 這個 CR 來配置不同集羣的差異化配置,直接看一個例子:

apiVersion: policy.karmada.io/v1alpha1
kind: OverridePolicy
metadata:
  name: example-override
  namespace: default
spec:
  resourceSelectors:
    - apiVersion: apps/v1
      kind: Deployment
      name: nginx
  targetCluster:
    clusterNames:
      - member1
    labelSelector:
      matchLabels:
        failuredomain.kubernetes.io/region: dc1
  overriders:
    plaintext:
      - path: /spec/template/spec/containers/0/image
        operator: replace
        value: 'dc-1.registry.io/nginx:1.17.0-alpine'
      - path: /metadata/annotations
        operator: add
        value:
          foo: bar

 參考鏈接

原文鏈接:https://xinzhao.me/posts/kubernetes-multi-cluster-projects/

k8s 技術圈 專注容器、專注 kubernetes 技術......

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/laMfFgre8PrbC2SayxBFRQ