多集群服务发现

用户能够通过多集群服务API在集群之间导出和导入服务。

注意:使用该特性需要满足成员集群的kubernetes版本在v1.21以上(包含v1.21)。

准备开始

安装Karmada

我们可以通过参考快速开始来安装Karmada,或者直接运行 hack/local-up-karmada.sh 脚本,我们的E2E测试执行正是使用了该脚本。

成员集群网络

确保至少有两个集群被添加到 Karmada,并且成员集群之间的容器网络可相互连接。

  • 如果你使用 hack/local-up-karmada.sh 脚本来部署 Karmada,Karmada 将有三个成员集群,member1member2 的容器网络将被连接。
  • 你可以使用 Submariner 或其他相关的开源项目来连接成员集群之间的网络。

    注意:为了防止路由冲突,集群之间的Pod和Service CIDR需要满足不重叠。

安装 ServiceExport 和 ServiceImport CRD

我们需要在成员集群中安装ServiceExport和ServiceImport。

karmada控制平面上安装完 ServiceExport 和 ServiceImport 之后,我们可以创建 ClusterPropagationPolicy 来分发这两个 CRD 到成员集群。

  1. # propagate ServiceExport CRD
  2. apiVersion: policy.karmada.io/v1alpha1
  3. kind: ClusterPropagationPolicy
  4. metadata:
  5. name: serviceexport-policy
  6. spec:
  7. resourceSelectors:
  8. - apiVersion: apiextensions.k8s.io/v1
  9. kind: CustomResourceDefinition
  10. name: serviceexports.multicluster.x-k8s.io
  11. placement:
  12. clusterAffinity:
  13. clusterNames:
  14. - member1
  15. - member2
  16. ---
  17. # propagate ServiceImport CRD
  18. apiVersion: policy.karmada.io/v1alpha1
  19. kind: ClusterPropagationPolicy
  20. metadata:
  21. name: serviceimport-policy
  22. spec:
  23. resourceSelectors:
  24. - apiVersion: apiextensions.k8s.io/v1
  25. kind: CustomResourceDefinition
  26. name: serviceimports.multicluster.x-k8s.io
  27. placement:
  28. clusterAffinity:
  29. clusterNames:
  30. - member1
  31. - member2

示例

第1步:在member1集群上部署服务

我们需要在 member1 集群上部署服务以便发现。

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: serve
  5. spec:
  6. replicas: 1
  7. selector:
  8. matchLabels:
  9. app: serve
  10. template:
  11. metadata:
  12. labels:
  13. app: serve
  14. spec:
  15. containers:
  16. - name: serve
  17. image: jeremyot/serve:0a40de8
  18. args:
  19. - "--message='hello from cluster member1 (Node: {{env \"NODE_NAME\"}} Pod: {{env \"POD_NAME\"}} Address: {{addr}})'"
  20. env:
  21. - name: NODE_NAME
  22. valueFrom:
  23. fieldRef:
  24. fieldPath: spec.nodeName
  25. - name: POD_NAME
  26. valueFrom:
  27. fieldRef:
  28. fieldPath: metadata.name
  29. ---
  30. apiVersion: v1
  31. kind: Service
  32. metadata:
  33. name: serve
  34. spec:
  35. ports:
  36. - port: 80
  37. targetPort: 8080
  38. selector:
  39. app: serve
  40. ---
  41. apiVersion: policy.karmada.io/v1alpha1
  42. kind: PropagationPolicy
  43. metadata:
  44. name: mcs-workload
  45. spec:
  46. resourceSelectors:
  47. - apiVersion: apps/v1
  48. kind: Deployment
  49. name: serve
  50. - apiVersion: v1
  51. kind: Service
  52. name: serve
  53. placement:
  54. clusterAffinity:
  55. clusterNames:
  56. - member1

第2步:导出服务到 member2 集群

  • karmada控制平面上创建一个 ServiceExport 对象,然后创建一个 PropagationPolicy ,将 ServiceExport 对象分发到 member1 集群。
  1. apiVersion: multicluster.x-k8s.io/v1alpha1
  2. kind: ServiceExport
  3. metadata:
  4. name: serve
  5. ---
  6. apiVersion: policy.karmada.io/v1alpha1
  7. kind: PropagationPolicy
  8. metadata:
  9. name: serve-export-policy
  10. spec:
  11. resourceSelectors:
  12. - apiVersion: multicluster.x-k8s.io/v1alpha1
  13. kind: ServiceExport
  14. name: serve
  15. placement:
  16. clusterAffinity:
  17. clusterNames:
  18. - member1
  • karmada控制平面上创建一个 ServiceImport 对象,然后创建一个 PropagationPlicy 来分发 ServiceImport 对象到 member2 集群。
  1. apiVersion: multicluster.x-k8s.io/v1alpha1
  2. kind: ServiceImport
  3. metadata:
  4. name: serve
  5. spec:
  6. type: ClusterSetIP
  7. ports:
  8. - port: 80
  9. protocol: TCP
  10. ---
  11. apiVersion: policy.karmada.io/v1alpha1
  12. kind: PropagationPolicy
  13. metadata:
  14. name: serve-import-policy
  15. spec:
  16. resourceSelectors:
  17. - apiVersion: multicluster.x-k8s.io/v1alpha1
  18. kind: ServiceImport
  19. name: serve
  20. placement:
  21. clusterAffinity:
  22. clusterNames:
  23. - member2

第3步:从 member2 集群获取服务

经过上述步骤,我们可以在 member2 集群上找到前缀为 derived-派生服务。然后,我们可以访问派生服务来访问member1集群上的服务。

member2 集群上启动一个Pod request来访问派生服务的ClusterIP。

  1. # 我们可以在member2集群中找到对应的派生服务。
  2. $ kubectl --kubeconfig ~/.kube/members.config --context member2 get svc
  3. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  4. derived-serve ClusterIP 10.13.205.2 <none> 80/TCP 81s
  5. kubernetes ClusterIP 10.13.0.1 <none> 443/TCP 15m
  1. $ kubectl --kubeconfig ~/.kube/members.config --context member2 run -i --rm --restart=Never --image=jeremyot/request:0a40de8 request -- --duration={duration-time} --address={ClusterIP of derived service}

例如,如果我们使用ClusterIP地址10.13.205.2持续访问该服务3s,将会得到如下输出:

  1. # 访问派生服务, 这时候member1的工作负载能正常返回一个响应。
  2. $ kubectl --kubeconfig ~/.kube/members.config --context member2 run -i --rm --restart=Never --image=jeremyot/request:0a40de8 request -- --duration=3s --address=10.13.205.2
  3. If you don't see a command prompt, try pressing enter.
  4. 2022/07/24 15:13:08 'hello from cluster member1 (Node: member1-control-plane Pod: serve-9b5b94f65-cp87p Address: 10.10.0.5)'
  5. 2022/07/24 15:13:09 'hello from cluster member1 (Node: member1-control-plane Pod: serve-9b5b94f65-cp87p Address: 10.10.0.5)'
  6. pod "request" deleted