适用于 Kubernetes 的 DiscoveryClient
该项目提供了 Discovery Client for Kubernetes 的实现。
此客户端允许您按名称查询 Kubernetes 端点(请参阅服务)。
服务通常由 Kubernetes API 服务器公开为表示http和https地址,客户端可以
从作为 Pod 运行的 Spring Boot 应用程序访问。
DiscoveryClient 还可以查找ExternalName(请参阅 ExternalName 服务)。目前,外部名称支持服务类型仅在以下属性时可用spring.cloud.kubernetes.discovery.include-external-name-services设置为true(这是false默认情况下)。
我们支持 3 种类型的发现客户端:
1.
Fabric8 Kubernetes 客户端
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
</dependency>2.
Kubernetes Java 客户端
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-client</artifactId>
</dependency>3.
基于 HTTPDiscoveryClient
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-discoveryclient</artifactId>
</dependency>| spring-cloud-starter-kubernetes-discoveryclient旨在与 Spring Cloud Kubernetes DiscoveryServer 一起使用。 | 
要启用加载DiscoveryClient加@EnableDiscoveryClient到相应的配置或应用程序类,如以下示例所示:
@SpringBootApplication
@EnableDiscoveryClient
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}然后,只需对客户端进行自动连接,即可将客户端注入到代码中,如以下示例所示:
@Autowired
private DiscoveryClient discoveryClient;您应该问自己的第一个问题是,在哪里DiscoveryClient应该发现服务。在 kubernetes 世界中,这意味着命名空间。这里有 3 个选项:
- 
selective namespaces.例如:
spring.cloud.kubernetes.discovery.namespaces[0]=ns1
spring.cloud.kubernetes.discovery.namespaces[1]=ns2这样的配置使发现客户端仅搜索两个命名空间中的服务ns1和ns2.
- 
all-namespaces.
spring.cloud.kubernetes.discovery.all-namespaces=true虽然存在这样的选项,但这可能会给 kube-api 和你的应用程序带来负担。很少需要这样的设置。
- 
one namespace.如果您未指定上述任何一项,则这是默认设置。它适用于命名空间解析中概述的规则。
| 上述选项的工作方式与为 fabric8 和 k8s 客户端编写的完全相同。对于基于 HTTP 的客户端,您需要在服务器上启用这些选项。这可以通过将它们设置为 deployment.yaml用于使用 env 变量在集群中部署映像。 | 
例如:
      containers:
        - name: discovery-server
          image: springcloud/spring-cloud-kubernetes-discoveryserver:3.0.5-SNAPSHOT
          env:
            - name: SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0
              value: "namespace-a"配置命名空间后,下一个要回答的问题是要发现哪些服务。将其视为要应用的过滤器。默认情况下,根本不应用任何筛选,并且会发现所有服务。如果需要缩小发现客户端可以查找的内容,则有两个选项:
- 
仅采用与特定服务标签匹配的服务。此属性指定为: spring.cloud.kubernetes.discovery.service-labels.它接受一个Map并且仅具有此类标签的服务(如metadata.labels在服务定义中)将被考虑在内。
- 
另一种选择是使用 SpEL 表达式。这由 spring.cloud.kubernetes.discovery.filter属性,其值取决于您选择的客户端。如果使用 fabric8 客户端,则必须针对io.fabric8.kubernetes.api.model.Service类。一个这样的例子可能是:
spring.cloud.kubernetes.discovery.filter='#root.metadata.namespace matches "^.+A$"'它告诉发现客户端仅获取具有metadata.namespace以大写结尾A.
如果您的发现客户端基于 k8s 原生客户端,则 SpEL 表达式必须基于io.kubernetes.client.openapi.models.V1Service类。上面显示的相同过滤器在这里也起作用。
如果您的发现客户端是基于 http 的客户端,则 SeEL 表达式必须基于相同的io.kubernetes.client.openapi.models.V1Service类,唯一的区别是需要在部署 YAML 中将其设置为 env 变量:
      containers:
        - name: discovery-server
          image: springcloud/spring-cloud-kubernetes-discoveryserver:3.0.5-SNAPSHOT
          env:
            - name: SPRING_CLOUD_KUBERNETES_DISCOVERY_FILTER
              value: '#root.metadata.namespace matches "^.+A$"'
现在是时候考虑什么发现客户应该返回了。一般来说,有两种方法DiscoveryClient有:getServices和getInstances.
getServices将返回服务名称,如metadata.name.
| 此方法将返回唯一的服务名称,即使不同命名空间(您为搜索选择)之间存在重复项。 | 
getInstances返回一个List<ServiceInstance>.除了通常的字段之外,一个ServiceInstance有,我们还添加了一些数据,例如命名空间或 Pod 元数据(有关这些的更多解释将在文档中进行)。以下是我们目前返回的数据:
- 
instanceId- 服务实例的唯一 ID
- 
serviceId- 服务名称(与调用getServices)
- 
host- 实例的 IP(或名称,如果是ExternalName服务类型)
- 
port- 实例的端口号。这需要更多解释,因为选择端口号有其规则:- 
服务未定义端口,则返回 0(零)。 
- 
service 定义了一个端口,则该端口将返回。 
- 
如果服务有标签 primary-port-name,我们将使用具有标签值中指定名称的端口号。
- 
如果上面的标签不存在,那么我们将使用 spring.cloud.kubernetes.discovery.primary-port-name以查找端口号。
- 
如果以上都未指定,我们将使用名为 https或http以计算端口号。
- 
作为最后的手段,我们将选择端口列表中的第一个端口。最后一种选择可能会导致非确定性行为。 
 
- 
- 
uri服务实例的
- 
scheme也http或https(取决于secure结果)
- 
metadata服务:- 
labels(如果通过spring.cloud.kubernetes.discovery.metadata.add-labels=true).标签键可以“前缀”值为spring.cloud.kubernetes.discovery.metadata.labels-prefix如果已设置。
- 
annotations(如果通过spring.cloud.kubernetes.discovery.metadata.add-annotations=true).注释键可以“前缀”值为spring.cloud.kubernetes.discovery.metadata.annotations-prefix如果已设置。
- 
ports(如果通过spring.cloud.kubernetes.discovery.metadata.add-ports=true).端口键可以“前缀”值spring.cloud.kubernetes.discovery.metadata.ports-prefix如果已设置。
- 
k8s_namespace替换为 instance 所在的命名空间的值。
- 
type,例如,保存服务类型ClusterIP或ExternalName
 
- 
- 
secure如果发现的端口应被视为安全端口。我们将使用上述相同的规则来查找端口名称和端口号,然后:- 
如果此服务具有名为 secured使用任何值:["true", "on", "yes", "1"],然后将发现的端口视为安全端口。
- 
如果找不到这样的标签,请搜索名为 secured并应用上述相同的规则。
- 
如果此端口号是 spring.cloud.kubernetes.discovery.known-secure-ports(默认情况下,此值成立[443, 8443]),将端口号视为安全。
- 
最后的手段是查看端口名称是否匹配 https;如果它确实将此端口视为安全端口。
 
- 
- 
namespace- 找到的实例的命名空间。
- 
pod-metadata服务实例(Pod)的标签和注释,以Map<String, Map<String, String>>.需要通过以下方式启用此支持spring.cloud.kubernetes.discovery.metadata.add-pod-labels=true和/或spring.cloud.kubernetes.discovery.metadata.add-pod-annotaations=true
要发现未被 kubernetes api 服务器标记为“就绪”的服务端点地址,您可以在application.properties(默认值:false):
spring.cloud.kubernetes.discovery.include-not-ready-addresses=true| 这在发现服务以进行监控时可能很有用,并且可以检查 /health未就绪服务实例的终结点。
如果您想获取列表ServiceInstance还包括ExternalName类型服务,您需要通过以下方式启用该支持:spring.cloud.kubernetes.discovery.include-external-name-services=true.因此,当调用DiscoveryClient::getInstances这些也将被退回。您可以区分ExternalName以及任何其他类型通过检查ServiceInstance::getMetadata并查找名为type.这将是返回的服务类型:ExternalName/ClusterIP等。
如果出于任何原因需要禁用DiscoveryClient,您可以在application.properties: | 
spring.main.cloud-platform=NONE请注意,发现客户端的支持是自动的,具体取决于您运行应用程序的位置。因此,可能不需要上述设置。
一些 Spring Cloud 组件使用DiscoveryClient以获取有关本地服务实例的信息。为
要使其正常工作,您需要将 Kubernetes 服务名称与spring.application.name财产。
| spring.application.name对于在 Kubernetes 中为应用程序注册的名称没有影响 | 
Spring Cloud Kubernetes 还可以监视 Kubernetes 服务目录的更改,并更新DiscoveryClient相应地实施。为了启用此功能,您需要添加@EnableScheduling在应用程序中的配置类上。“watch”是指我们将在每spring.cloud.kubernetes.discovery.catalog-services-watch-delay毫秒(默认为30000).对于 http 发现服务器,这必须是在部署 yaml 中设置的环境变量:
      containers:
        - name: discovery-server
          image: springcloud/spring-cloud-kubernetes-discoveryserver:3.0.5-SNAPSHOT
          env:
            - name: SPRING_CLOUD_KUBERNETES_DISCOVERY_CATALOGSERVICESWATCHDELAY
              value: 3000
心跳事件将包含目标引用(及其所有端点地址的命名空间(有关将返回的内容的确切详细信息,您可以查看内部KubernetesCatalogWatch). 这是一个实现细节,检测信号事件的侦听器不应依赖于详细信息。相反,他们应该通过以下方式查看两个后续检测信号之间是否存在差异equals方法。我们将注意返回符合等价契约的正确实现。
将在以下任一位置查询端点:
-all-namespaces(通过spring.cloud.kubernetes.discovery.all-namespaces=true)
- 
selective namespaces(通过spring.cloud.kubernetes.discovery.namespaces),例如:
- 
one namespace通过命名空间解析,如果未采用上述两条路径。
| 如果出于任何原因想要禁用目录观察程序,则需要将 spring.cloud.kubernetes.discovery.catalog-services-watch.enabled=false.对于 http 发现服务器,这需要是在部署中设置的环境变量,例如: | 
SPRING_CLOUD_KUBERNETES_DISCOVERY_CATALOGSERVICESWATCH_ENABLED=FALSE目录监视的功能适用于我们支持的所有 3 个发现客户端,但在 http 客户端的情况下,您需要注意一些注意事项。
- 
首先是该功能默认禁用,需要在两个地方启用: - 
在 Discovery Server 中通过部署清单中的环境变量,例如: containers: - name: discovery-server image: springcloud/spring-cloud-kubernetes-discoveryserver:3.0.5-SNAPSHOT env: - name: SPRING_CLOUD_KUBERNETES_HTTP_DISCOVERY_CATALOG_WATCHER_ENABLED value: "TRUE"
- 
在发现客户端中,通过 application.properties例如:spring.cloud.kubernetes.http.discovery.catalog.watcher.enabled=true 
 
- 
- 
第二点是这仅自版本以来受支持 3.0.6并向上。
- 
由于 http 发现有两个组件:服务器和客户端,我们强烈建议在它们之间对齐版本,否则可能无法正常工作。 
- 
如果您决定禁用目录观察程序,则需要在服务器和客户端中禁用它。 
默认情况下,我们使用Endpoints(见 kubernetes.io/docs/concepts/services-networking/service/#endpoints)API 来了解服务的当前状态。不过还有另一种方法,通过EndpointSlices (kubernetes.io/docs/concepts/services-networking/endpoint-slices/)。可以通过以下属性启用此类支持:spring.cloud.kubernetes.discovery.use-endpoint-slices=true(默认情况下,它是false).当然,您的集群也必须支持它。事实上,如果您启用了此属性,但您的集群不支持它,我们将无法启动应用程序。如果您决定启用此类支持,则还需要设置正确的角色/集群角色。例如:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: namespace-reader
rules:
  - apiGroups: ["discovery.k8s.io"]
    resources: ["endpointslices"]
    verbs: ["get", "list", "watch"]