01Istio与外部注册中心
Istio为何需要对接外部注册中心
Istio 对 Kubernetes 具有较强的依赖性:
1.服务发现就是基于 Kubernetes 实现的,如果要使用 Istio,首先需要迁移到 Kubernetes 上,并使用 Kubernetes 的服务注册发现机制。
2.对于大量现存的微服务项目来说,这个前提条件并不成立。对于存量的微服务存在一下几种情况:
第一种情况:微服务项目暂时迁移到 Kubernetes 上;
第二种情况:虽然采用了 Kubernetes 来进行部署和管理,但还是使用了 Consul,Eureka 等其他服务注册解决方案或者自建的服务注册中心。
02Istio服务模型
Pilot
管理服务网格内部的服务和流量策略:
Pilot 将服务信息和路由策略转换为 xDS 接口的标准数据结构,下发到数据面的 Envoy。但 Pilot 自身并不负责网格中的服务注册。
Pilot 中管理的服务数据有两处数据来源:
Service Registry:来源于各个服务注册表,例如 Kubernetes 中的 Service 和 Consul Catalog 中注册的服务。Istio 通过特定的适配器连接这些服务注册表,由适配器将服务注册表中的私有服务模型转换为 Istio 内部支持的标准服务模型。
Config Storage:来源于各种配置数据源中的独立服务,通过 Istio 定义的 ServiceEntry2 和WorkloadEntry资源类型加入到 Pilot 的内部服务模型中。
03 Istio 对接外部注册中心
自定义 Service Registry 适配器
这种集成方式的业务流程参见图中的蓝色箭头。该方案需要编写自定义的 MCP Server 从第三方注册表中获取服务和服务实例,然后转换为 ServiceEntry 和 WorkloadEntry 资源,通过 MCP 协议提供给 Pilot 中的 MCP config Controller。
采用这种方式,需要在 istio configmap 中通过 configSources 参数设置自定义 MCP Server 的地址。
修改完成后需重启istiod.
自定义 MCP Server
如图中红色箭头所示,我们可以编写一个自定义的适配器来集成第三方服务注册表。该自定义适配器从第三方服务注册表中获取服务和服务实例,转换为 Pilot 内部的标准模型,集成到 Service Controller 中。自定义适配器需要实现 serviceregistry.Instance 接口。该方式的原理和 Consul Service Registry 的适配是类似的,可以参照 Consul Service Registry 的适配代码进行编写。
实施该方案需要熟悉 Pilot 内部服务模型和 Service Registry 适配相关 Istio 源码,并且需要将自定义适配器代码和 Pilot 代码一起编译生成定制的 Pilotd 二进制执行文件。该方案的问题是和 Istio 代码耦合较强,后续 Istio 版本升级时可能需要修改适配器代码并重新编译。
向 API Server 写入
该集成方式的业务流程如图中绿色箭头所示。我们只需要编写一个独立的服务,该服务从第三方法服务注册表中获取服务和服务实例数据,然后转换为 Istio 的 ServiceEntry 和 WorkloadEntry 资源,通过 Kubernetes API Server 的接口写入到 API Server 中。Pilot 中自带的 Kube Config Controller 会监听 Kubernetes API Server 中和 Istio 相关的资源对象的变化,并将 ServiceEntry 和 WorkloadEntry 转换为 Pilot 的内部服务模型。
04 MCP
MCP是基于订阅的配置分发API。配置消费者(即sink)请求更新来自配置生产者(即source)的资源集合。添加,更新或删除资源时,source会将资源更新推送到sink。如果sink接受,则回复ACK,如果被拒绝则是NACK,例如因为资源无效。一旦对先前的更新进行了ACK/NACK,则source可以推送其他更新。该source一次只能运行一次未完成的更新(每个集合)。
就消息交换而言,ResourceSource和ResourceSink在语义上是等效的。唯一有意义的区别是谁启动连接并打开grpc流。
istio 1.9 变化
注意:istio 1.9 之后移除了mcp 使用mcp over xds,具体参考设计文档
Istio 1.9 在对接第三方注册中心方面,有两个需要注意的地方:
istio 1.8 不再 in-tree 支持 consul 作为外部注册中心 :加上之前版本移除了对于euraka的支持。截止1.8,所有通过 in-tree 方式支持外部注册中心的代码彻底被移除。
istio1.9 不再支持MCP的方式对接外部注册中心,改为 MCP-over-XDS的方式:新的方式虽然叫mcp over xds,但本质上没有使用之前的mcp协议。这意味着istio 1.9 中不能使用之前社区开源的一些 mcp 实现。
05 MCP-over-XDS 对接第三方注册中心
编写 MCP-over-XDS server。然后将该server的地址配置到pilot 的configSource 参数中。pilot 启动的时候,就会向目的 MCP-over-XDS server 发起订阅请求,并建立 grpc 链接。MCP-over-XDS server 读取 注册中心的数据,并转换为ServiceEntry,然后 push 给 pilot。pilot接受到数据后,会对比内存中的数据,保证数据一致。
其中 MCP-over-XDS server 主要包含两部分:
一部分是Service watcher,用于监听服务注册中心,一旦有服务变更,就需要触发一次MCP推送,将最新的服务信息同步给istio。
另一部分是XDS grpc server,用于向istiod推送MCP协议的数据
要对接一个服务注册中心,只需实现Registry接口即可
接口包含3个方法:
-
AppendServiceChangeHandler:添加“服务更新时需要触发的回调函数”,也就是说,在发现该注册中心的服务变更时,需要触发serviceChanged回调函数
-
Run:运行service watcher,开始监听注册中心
-
ServiceEntries:返回目前注册中心中的所有服务,以istio ServiceEntry的形式输出
触发XDS grpc server推送MCP的时机有2类:
-
istiod启动时,会向mcp server发送一个初始(initial)请求,获取当前注册中心的所有服务服务信息
-
注册中心的服务变更时
在发生上述事件后,grpc server会调用Service watcher的ServiceEntries方法,获取到最新的服务信息,并用MCP协议包装,最终作为XDS协议的payload发送给istiod。
推送的过程存在一个防抖机制(参考istio推送XDS的过程),目的是为了避免频繁的服务更新导致多次MCP推送。防抖会将短时间内的多次更新事件合并为一次,减轻推送压力