Kubernetes服务发现模型
为了明确 K8s 在服务接入管理提供的解决方案,我们以 kube-apiserver 提供的 API(HTTPS) 服务为例。K8s 集群为该服务分配了一个集群内有效的 ClusterIP ,并通过 CoreDNS 为其分配了唯一的域名 kubernetes 。如果集群内的 Pod 需要访问该服务时直接通过 https://kubernetes:443 即可完成。
具体流程如上图所示 ( 红⾊为客户端,绿⾊为 kube-apiserver ):
- ⾸先客户端通过 CoreDNS 解析域名为 kubernetes 的服务获得对应的 Cluster IP 为 10.96.0.1。
- 客户端向 10.96.0.1 发起 HTTP 请求。
- HTTP 请求 kube-proxy 所创建的 IP tables 拦截随机 DNAT 为 10.0.2.16 或者 10.0.2.15 。
- Client 与最终提供服务的 Pod 建⽴连接并交互。
由此可⻅,Kubernetes 提供的服务发现为域名解析级别。
Dubbo-go所采用的注册/发现方案
服务注册
Kubernetes 基于 Service 对象实现服务注册/发现。可是 dubbo 现有⽅案为每个 dubbo-go 进程独⽴注册,因此 dubbo-go选择将该进程具有的独有的元数据写⼊运⾏该 dubbo-go 进程的 Pod 在 Kubernetes中的 Pod 资源对象的描述信息中。每个运⾏ dubbo 进程的 Pod 将本进程的元数据写⼊ Kubernetes-Pod Annotations 字段。为了避免与其他使⽤Annotations 字段的 Operator 或者其他类型的控制器( Istio ) 的字段冲突。dubbo-go 使⽤ Key 为 dubbo.io/annotation value 为具体存储的 K/V 对的数组的 json 编码后的 base64 编码。
样例为:
apiVersion: v1
kind: Pod
metadata:
annotations:
dubbo.io/annotation:
W3siayI6Ii9kdWJibyIsInYiOiIifSx7ImsiOiIvZHViYm8vY29tLmlrdXJlbnRvLnVzZXIuVXNlcl
Byb3ZpZGVyIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlk
ZXIvY29uc3VtZXJzIiwidiI6IiJ9LHsiayI6Ii9kdWJibyIsInYiOiIifSx7ImsiOiIvZHViYm8vY2
9tLmlrdXJlbnRvLnVzZXIuVXNlclByb3ZpZGVyIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1
cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvcHJvdmlkZXJzIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb2
0uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvY29uc3VtZXJzL2NvbnN1bWVyJTNBJTJGJTJGMTcy
LjE3LjAuOCUyRlVzZXJQcm92aWRlciUzRmNhdGVnb3J5JTNEY29uc3VtZXJzJTI2ZHViYm8lM0RkdW
Jib2dvLWNvbnN1bWVyLTIuNi4wJTI2cHJvdG9jb2wlM0RkdWJibyIsInYiOiIifV0=
由于每个 dubbo-go 的 Pod 均只负责注册本进程的元数据,因此 Annotations 字段⻓度也不会因为运⾏ dubbo-go 进程的 Pod 数量增加⽽增加。
服务发现
依赖kubernetes Api-Server 提供了Watch的功能。可以观察特定namespace内各Pod对象的变化。 dubbo-go为了避免dubbo-go进程watch到与dubbo-go进程⽆关的Pod的变化,dubbo-go将watch的条件限制在当前Pod所在的namespace,以及 watch 具有 Key为dubbo.io/label Value为 dubbo.io-value 的Pod。在Watch到对应Pod的变化后实时更新本地Cache,并通过Registry提供的Subscribe通知建⽴在注册中⼼之上的服务集群管理,或者其他功能。
总体设计图
具体流程如上图所示:
- 启动dubbo-go的Deployment或其他类型控制器使用kubernetes Downward-Api将本Pod所在namespace通过环境变量的形式注入dubbo-go进程。
- dubbo-go 进程的 Pod 启动后通过环境变量获得当前的 namespace 以及该 Pod 名称,调⽤ Kubernetes-Apiserver PATCH 功能为本 Pod 添加 Key 为 dubbo.io/label Value为 dubbo.io-value的label。
- dubbo-go 进程调⽤ Kubernetes-Apiserver 将本进程的元数据通过 PATCH 接⼝写⼊当前 Pod 的 Annotations 字段。
- dubbo-go 进程 LIST 当前 namespace 下其他具有同样标签的 Pod,并解码对应的 Annotations 字段 获取其他 Pod 的信息。
- dubbo-go 进程 WATCH 当前 namespace 下其他具有同样标签的 Pod 的 Annotations 的字段变化。