karmada作为集群资源同步工具在灾备系统中的实践

karmada是一个kubernetes多集群管理系统,它可以保持原有使用apiserver的方式,将资源分布到多个集群中。提供了跨云多集群多模式管理、多策略的多集群调度、应用的跨集群故障转移、全局统一资源视图、多集群的服务发现和FederatedHPA能力。它的设计思路继承了集群联邦v2,目前是cncf的sandbox开源项目。

详细请访问官网https://karmada.io/

这篇文章使用的karmada版本为v1.6.2

集群容灾方案:一个集群作为生产集群对外提供服务,另一个集群作为standby集群。当生产集群发生故障时候,流量切换到standby集群。

同时为了节省成本,standby集群使用云厂商的无服务器集群,非启用时间workload的replicas为0(或没有运行的pod),启用时候调整replicas不为0。由于使用云厂商的无服务器原因,需要添加一些annotation到pod中,以修改一些运行时配置,同时需要容忍一些污点。

需要满足以下需求:

  1. 需要考虑扩展性,新添加CRD,无需修改或少改代码

  2. 需要支持资源的白名单和黑名单,进行资源的过滤

  3. 需要提供灵活配置方式来进行资源修改

  4. 提供观测功能,能监控同步失败和成功资源数量

优点:代码可控,功能可以定制,锻炼编码能力

缺点:重复造轮子,费时费力

velero是集群资源和数据的备份工具。备份时候将数据保存在对象存储中,进行恢复时候从对象存储中下载备份,然后进行资源和数据恢复。

velero的restore resource modifiers功能可以完成资源修改。

优点:操作简单和方便

缺点:备份和恢复需要一定时间,备份有延迟,导致集群无法做到准实时状态。

ClusterPropagationPolicy和PropagationPolicy能够将资源分发到多个集群中,ClusterOverridePolicy和OverridePolicy进行资源的覆盖。

命名空间级别的黑名单和API资源类型的黑名单

优点:功能丰富,能够保证准集群间资源的准实时

缺点:架构复杂,进行多层资源抽象,有一定上手门槛。

  1. 能够保证准集群间资源的准实时,保证集群故障切换流量时,尽可能减少集群间的差异。
  2. 不需要重复造轮子

karmada设计架构是karmada组件部署在一个control plane集群中,包括单独的apiserver,组成一个独立的kubernetes集群,类似kubernetes in kubernetes。

使用karmada管理已有的集群的资源,需要将资源迁移到karmada control plane集群中。使用karmadactl promote命令进行迁移,但是它只能支持一个资源,不能支持批量迁移。已有集群有大量的资源,迁移非常麻烦。

同时原先连接到已有apisever,需要切换到karmada control plane集群apisever。

使用已有集群的apiserver做为karmada control plane集群apisever,那么就无需进行资源的迁移,也不需要进行apiserver地址的切换。实现系统无需改造情况下,使用karmada能力。

相关文档:Can I install Karmada in a Kubernetes cluster and reuse the kube-apiserver as Karmada apiserver

/post/practice-of-karmada-as-cluster-resource-synchronization-in-disaster-recovery-systems/karmada-nomal.png

使用proxy代理

编辑cluster资源,添加代理地址到spec.proxyURL

1
2
3
4
5
6
7
8
9
apiVersion: cluster.karmada.io/v1alpha1
kind: Cluster
metadata:
  finalizers:
  - karmada.io/cluster-controller
  generation: 3
  name: test-cluster
spec:
  proxyURL: http://proxy-address #添加代理地址

karmada-proxy

独立部署karmada controller manager(只保证资源同步功能正常)

将karmada-controller-manager进行独立部署到cluster C,cluster C都能访问这两个集群。

karmada-stand-alone-controller-manager

集群中的监控、日志、ingress等组件不需要同步,kubernetes内部的命名空间下的资源不要同步

karmada-controller-manager添加--skipped-propagating-namespaces忽略这些命名空间下的资源

1
--skipped-propagating-namespaces=velero,prometheus,default,kube-system,kube-public,kube-node-lease

由于karmada的设计原因,在standby集群里的创建workload时会添加label,key为 resourcebinding.karmada.io/name,value为{workload name}-{workload kind}。而label的key和value的长度最大63字符。

比如deployment资源,value后缀为"-deployment",长度为11字符,所以deployment资源名字长度必须小于等于52个字符。

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

https://docs.google.com/document/d/1b-5EHUAQf8wIoCnerKTHiyiSIzsypqCNz0CWUzvUhnI/

在测试同步规则时候,为了删除standby集群里的同步资源,执行删除PropagationPolicy和OverridePolicy。但是standby集群里的workload并没有被移除,反而workload的属性变成跟product集群一样。

另外一个case,集群从karmada中移除后再加入,在没有PropagationPolicy情况下,集群资源又被同步到standby集群。

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

同步成功的workload,在product集群的workload的status会被karmada-controller-manager修改,这导致一系列的异常情况。比如pvc的status.capacity字段被移除,导致pod的挂载失败。

解决方法:karmada-controller-manager里禁用bindingStatus controller

1
--controllers=-bindingStatus,*

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

同步到standby集群的wokload,都需要在spec.template.metadata.annotation添加一些annotation,但是有一些workload里没有spec.template.metadata.annotation,导致workload同步失败。

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

提供一下我的最终配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
apiVersion: policy.karmada.io/v1alpha1
kind: ClusterPropagationPolicy
metadata:
  name: workload
spec:
  resourceSelectors:
    - apiVersion: apps/v1
      kind: Deployment
    - apiVersion: apps/v1
      kind: StatefulSet
  propagateDeps: true
  placement:
    clusterAffinity:
      clusterNames:
        - test
---
apiVersion: policy.karmada.io/v1alpha1
kind: ClusterOverridePolicy
metadata:
  name: workload
spec:
  resourceSelectors:
    - apiVersion: apps/v1
      kind: Deployment
    - apiVersion: apps/v1
      kind: StatefulSet
  overrideRules:
  - overriders:
      plaintext:
      - path: /spec/replicas
        operator: replace
        value: 0
      - path: /spec/template/spec/tolerations
        operator: add
        value:
        - key: "eks.tke.cloud.tencent.com/eklet"
          operator: "Exists"
          effect: "NoSchedule"
      - path: /spec/template/spec/schedulerName
        operator: add
        value: "tke-scheduler"
      - path: /spec/template/spec/schedulerName
        operator: replace
        value: "tke-scheduler"
      - path: /spec/template/metadata/annotations/AUTO_SCALE_EKS
        operator: add
        value: "true"
      - path: /spec/template/metadata/annotations/eks.tke.cloud.tencent.com~1resolv-conf
        operator: add
        value: |
          nameserver 10.10.248.248
          nameserver 10.10.249.249
---
apiVersion: policy.karmada.io/v1alpha1
kind: ClusterOverridePolicy
metadata:
  name: pvc
spec:
  resourceSelectors:
    - apiVersion: v1
      kind: PersistentVolumeClaim
  overrideRules:
  - overriders:
      plaintext:
      - path: /spec/volumeName
        operator: remove
      annotationsOverrider:
      - operator: remove
        value:
          pv.kubernetes.io/bound-by-controller: "yes"
          pv.kubernetes.io/bind-completed: "yes"
          volume.kubernetes.io/selected-node: ""
          pv.kubernetes.io/provisioned-by: ""
          volume.kubernetes.io/storage-provisioner: ""
          volume.beta.kubernetes.io/storage-provisioner: ""
---
apiVersion: policy.karmada.io/v1alpha1
kind: ClusterPropagationPolicy
metadata:
  name: network
spec:
  resourceSelectors:
    - apiVersion: v1
      kind: Service
    - apiVersion: networking.k8s.io/v1
      kind: Ingress
    - apiVersion: networking.k8s.io/v1
      kind: IngressClass
  propagateDeps: true
  placement:
    clusterAffinity:
      clusterNames:
        - test

相关内容