服务发现接口
接口定义
Pilot提供 ServiceDiscovery 服务用于获取Istio服务实例,源代码在 istio/pilot/pkg/model/service.go
下:
type ServiceDiscovery interface {
// 列举出当前系统中所有的服务
Services() ([]*Service, error)
// 通过hostname 获取服务,注意这个方法已经被废弃
GetService(hostname Hostname) (*Service, error)
// 通过给定的 hostname,service port 获取服务实例,并匹配任意给定的label。如果label为空则匹配所有实例。
InstancesByPort(hostname Hostname, servicePort int, labels LabelsCollection) ([]*ServiceInstance, error)
// 获取代理的服务实例
GetProxyServiceInstances(*Proxy) ([]*ServiceInstance, error)
// 获取代理位置
GetProxyLocality(*Proxy) string
// 获取管理端口
ManagementPorts(addr string) PortList
// 获取工作负载的健康检查信息
WorkloadHealthCheckInfo(addr string) ProbeList
}
方法详解
Services()
Services()方法列出系统中所有服务的声明。
Services() ([]*Service, error)
只有服务定义,没有服务实例的数据。
GetService()
GetService()方法通过 hostname 获取服务,注意这个方法已经被废弃:
GetService(hostname Hostname) (*Service, error)
但是,请注意,在这个方法被废弃之后, ServiceDiscovery 接口并没有提供替代品,导致现在 ServiceDiscovery 接口中就没有方法可以查询 Service,只能通过 Services() 方法列出所有服务。
备注:不确认这个设计的由来,如果系统中服务数量不是太多的话,通过 Services() 方法取全量数据,然后自行获取单个服务也是很容易实现的。
InstancesByPort()
InstancesByPort()方法用于获取服务实例列表,需要匹配 hostname,service port 和 标签列表。Label列表为空则表示匹配所有实例。
InstancesByPort(hostname Hostname, servicePort int, labels LabelsCollection) ([]*ServiceInstance, error)
举例,假设要查询 catalog.mystore.com 的服务实例, InstancesByPort(catalog.myservice.com, 80) 会有如下 NetworkEndpoints 结果:
- NetworkEndpoint(172.16.0.1:8888), Service(catalog.myservice.com), Labels(foo=bar)
- NetworkEndpoint(172.16.0.2:8888), Service(catalog.myservice.com), Labels(foo=bar)
- NetworkEndpoint(172.16.0.3:8888), Service(catalog.myservice.com), Labels(kitty=cat)
- NetworkEndpoint(172.16.0.4:8888), Service(catalog.myservice.com), Labels(kitty=cat)
使用特定Label调用InstancesByPort()方法会返回剪切后的子集, 如 InstancesByPort(catalog.myservice.com, 80, foo=bar) 会返回:
- NetworkEndpoint(172.16.0.1:8888), Service(catalog.myservice.com), Labels(foo=bar)
- NetworkEndpoint(172.16.0.2:8888), Service(catalog.myservice.com), Labels(foo=bar)
类似的概念适用于使用特定的端口,主机名和标签来调用此函数。
这个方法在 Istio 0.8 版本中引入,每次只能使用一个端口来调用。
特别说明:
- CDS (clusters.go) 调用这个方法来构建 ‘dnslb’ 类型的集群
- EDS 调用这个方法来构建端点结果
- 在使用这个方法做其他任何事情 (除了调试和工具外)之前请参阅 istio-dev
GetProxyServiceInstances()
GetProxyServiceInstances()方法返回与给定代理共处一地的服务实例。
GetProxyServiceInstances(*Proxy) ([]*ServiceInstance, error)
共址通常意味着在相同的网络命名空间和安全上下文中运行。
作为Sidecar运行的代理将返回非空片。 独立代理将返回空切片。
这有两个原因导致它返回多个ServiceInstances而不是一个:
- ServiceInstance有一个NetworkEndpoint,它有一个端口。 但是服务可能有很多端口。 因此,实现此类服务的工作负载需要多个ServiceInstances,每个端口一个。(备注:这是上一节总结中提到的 ServiceInstance 模型和 ServicePort 一对一绑定)
- 单个工作负载可以实现多个逻辑服务。(备注:这有悖于微服务的理念,不过理论上也还是可能存在的,但是Istio真的支持多个逻辑服务存在于一个服务实例中吗?)
在第二种情况下,可以通过相同的物理端口号实现多个服务,尽管每个服务具有不同的 ServicePort 和 NetworkEndpoint。 如果这些重叠服务中的任何一个不是基于HTTP或HTTP/2的,则行为是未定义的,因为如果请求没有 Host header,则监听器可能无法确定连接的预期目标。
GetProxyLocality()
GetProxyLocality()方法返回代理运行的位置。
GetProxyLocality(*Proxy) string
ManagementPorts()
ManagementPorts() 方法列出与IPv4地址关联的一组管理端口。
ManagementPorts(addr string) PortList
这些管理端口通常由平台用于带外(out of band)管理任务,例如健康检查等。在代理以透明模式运行的情况下(捕获与服务实例IP地址之间的所有流量),为代理生成的配置不会操纵发往管理端口的流量。
WorkloadHealthCheckInfo()
WorkloadHealthCheckInfo()方法列出与IPv4地址关联的探针列表。平台使用这些探针来识别执行运行状况检查的请求。
WorkloadHealthCheckInfo(addr string) ProbeList
总结
ServiceDiscovery 接口的设计和通常的服务发现接口设计风格迥异,从使用者的角度看,基本只有两个主要方法可用:
- Services()方法列出系统中所有服务
- InstancesByPort()方法用于获取服务实例列表,需要给出 hostname,service port 和 Label列表
明显是一个高度订制的服务发现接口,而不是通用接口。