Dawn's Blogs

分享技术 记录成长

0%

Triple协议 (8) Kubernetes作为注册中心

Kubernetes 服务发现

Kubernetes Service 服务发现模型

在 Kubernetes 中,服务发现通过 Service 实现。每一个 Service 对象都被分配了一个唯一的 VIP,访问 Service.name 通过 CoreDNS 既可以访问到 VIP,kube-proxy 通过 iptables 将 VIP 映射为具体的某个 Pod IP 地址。流程为:

  1. 客户端通过 CoreDNS 解析 Kubernetes-Service 对应的 VIP。
  2. 客户端向 VIP 发起 HTTP 请求。
  3. HTTP 请求被 kube-proxy 拦截,通过 kube-proxy 创建的 iptables 将请求的目标地址映射到 Pod 的 IP 地址。

img

为什么无法使用 Kubernetes Service 作为 Dubbo 接口级服务发现

在 Dubbo 中接口级服务发现,无法直接使用 Kubernetes 作为注册中心主要有以下几点原因:

  1. 在 Dubbo 调用时,需要元数据信息。但是 Kubernetes-Service 的服务描述字段中并不包含 Dubbo 元数据信息。
  2. Dubbo 的服务注册是基于每一个进程的,每一个 Dubbo 进程均需要独立的注册
  3. Kubernetes-Service 默认为服务创建 VIP,提供 round-robin 的负载策略也与 dubbo-go自有的负载策略形成了冲突

Dubbo 应用级服务发现

在应用级服务发现中,是能够与 Kubernetes-Service 兼容的,因为本质上来说 Kubernetes-Service 也是一种应用级服务发现。

因为有应用级别的元数据,如何在 Service 中携带应用级元数据?以下是本人猜想:通过在 Service 中加入注解实现,value 为应用级元数据的 base64 编码。

Dubbo 方案

接口级服务发现

因为 Kubernetes 原生的服务注册发现与 Dubbo 接口级服务发现产生了冲突,所以 Dubbo 放弃了 Kubernetes-Service 机制,转而另设计了一套 Dubbo 在 Kubernetes 体系下的服务注册和发现机制。

服务注册

Dubbo-go 选择将元数据写入所在写入 Kubernetes-Pod Annotations 字段。为了避免与其他使用 Annotations 字段的 Operator 或者其他类型的控制器( Istio )的字段冲突。Dubbo-go 使用 Key 为 dubbo.io/annotation,value 为元数据的 base64 编码。

服务发现

Dubbo 通过 Kubernetes-Apiserver 的 Watch 功能实现服务发现。Dubbo-go为了避免 Watch 到非 Dubbo 进程的 Pod 变化,将 Watch 的条件限制在当前 Pod 所在的 namespace,并且 Watch 标签具有 Key 为 dubbo.io/label,Value为 dubbo.io-value 的 Pod。在 Watch 到对应Pod的变化后实时更新本地 Cache,此过程为 Informer 机制

总体设计

具体流程如下图所示:

  1. Provider 启动时,向 Dubbo-go Provider 应用所在的 Pod,以环境变量的方式注入 namespace 信息
  2. Dubbo-go Provider 进程的 Pod 启动后通过环境变量获得当前的 namespace 以及该 Pod 名称,调用 Kubernetes-Apiserver PATCH 功能为本 Pod 添加 Key 为 dubbo.io/label,Value为 dubbo.io-value的 label。
  3. Dubbo-go Provider 进程调用 Kubernetes-Apiserver,将本进程的元数据通过 PATCH 接口写入当前 Pod 的 Annotations 字段(key 为 dubbo.io/annotation)。
  4. (Informer 机制)Dubbo-go Consumer 进程 LIST 当前 namespace 下其他具有同样标签的 Pod,并解码对应的 Annotations 字段,获取其他 Pod 的元数据信息,后续可以根据元数据信息进行调用。
  5. (Informer 机制)Dubbo-go Consumer 进程 WATCH 当前 namespace 下其他具有同样标签的 Pod 的 Annotations 的字段变化。

img

应用级服务发现

对于应用级服务发现,官方文档并没有说明。以下是本人猜想:

  1. 创建 Service,填写向其中填写应用级元数据。
  2. Provider 将本进程的元数据通过 PATCH 接口写入当前 Pod 的 Annotations 字段(key 为 dubbo.io/annotation),实现元数据的注册。
  3. Consumer 通过应用名,获取 Kubernetes-Service,进而获取到应用级别的元数据,同时也获取到了 Pod 地址。
  4. Consumer 通过 Informer 机制,监听 Pod 变化,实现元数据变化的监听。