使用 Stork 在 Kubernetes 中进行服务发现和选择

正如我们在上一篇文章中所述,SmallRye Stork 是一个服务发现和客户端负载均衡框架,它提供了开箱即用的 Kubernetes 集成。本文将解释此集成,如何在客户端微服务中配置 Stork,以及它与传统的 Kubernetes 服务发现和负载均衡有何不同。

本文已更新,在配置 stork 属性时使用 quarkus. 前缀。自 Quarkus 2.8 起,此前缀是必需的。

Kubernetes 服务发现和负载均衡

Kubernetes 内置了服务发现和负载均衡功能。

假设您有一个部署在 Kubernetes 中的应用程序,并且公开了一个 HTTP API。您可以声明一个 Kubernetes 服务,该服务将调用委托给您的应用程序。此服务充当一组 Pod(通常是应用程序副本)前面的代理。当另一个应用程序调用我们的 HTTP API 时,它使用 DNS 来定位 Kubernetes 服务并使用解析后的地址。重要的是要理解,它定位和调用的不是应用程序实例,而是 Kubernetes 服务。然后,此服务将调用委托给实际应用程序,并在存在多个副本时实现轮循。

Kubernetes service discovery

Stork 为 Kubernetes 带来了什么?

尽管 Kubernetes 内置了服务发现支持,但有时我们需要在服务实例选择方面拥有更大的灵活性。如我们所见,Kubernetes 服务实现的是轮循。使用 Stork,您可以自定义选择。

与前面的示例不同,Stork 不使用 DNS 来定位 Kubernetes 服务。它使用 Kubernetes API 来检索 Kubernetes 服务后面的 Pod 集合。然后,您可以应用任何 Stork 服务选择,甚至实现自己的选择。

下图描绘了架构以及 Stork 如何定位和选择服务实例。

Service instances location

如上图所示,Kubernetes rest-service 由两个 Pod 支持。虽然传统的 Kubernetes 服务发现会确保对 rest-service 的请求在这些 Pod 之间进行负载均衡,但 Stork 直接检索 Pod 的地址。因此,它可以处理服务选择(目前使用轮循)。

请注意,虽然使用 Stork 的应用程序不使用 Kubernetes 服务委托,但它们仍然需要 Kubernetes 服务来发现支持的 Pod。因此,这不会改变您的 Kubernetes 部署。

配置和使用 Stork Kubernetes 服务发现

在客户端,我们的 Quarkus 应用程序使用 REST Client Reactive 与 rest-service 公开的 REST API 进行交互。客户端应用程序使用 Stork 来发现 rest-service 实例。启用 Stork 的最简单方法是将相应的 Jar 添加到您项目的类路径中

pom.xml
    <dependency>
        <groupId>io.smallrye.stork</groupId>
        <artifactId>stork-service-discovery-kubernetes</artifactId>
    </dependency>

有了 Stork 和 Stork Kubernetes Service Discovery 在类路径中,我们需要告诉 Stork 如何定位和选择服务。为此,我们只需在 Quarkus 应用程序配置中添加 stork.[service-name].[kebab-cased-property-name]。在我们的例子中,要配置 rest-service 并指示 Stork 使用 Kubernetes,我们添加

application.properties
quarkus.stork.rest-service.service-discovery.type=kubernetes
quarkus.stork.rest-service.service-discovery.k8s-namespace=my-namespace

请注意,您也可以通过注解配置它们,请查看 @ServiceDiscoveryType@ServiceDiscoveryAttribute 注解。

我们还可以将服务查找限制在我们的命名空间内。我们也可以使用 all 值来查找所有命名空间中的服务。

我们还可以配置更多属性来调整服务发现

属性 描述

quarkus.stork.service-name.service-discovery.k8s-host

Kubernetes API URL

quarkus.stork.service-name.service-discovery.application

目标应用程序的名称

quarkus.stork.service-name.service-discovery.refresh-period

服务发现缓存刷新周期

quarkus.stork.service-name.service-discovery.secure

使用安全连接(例如 HTTPS)

这就是 Stork Kubernetes 服务发现的简单之处。

配置好 Stork 后,我们需要配置 REST Client 来使用它。这可以在 @RegisterRestClient 注解的接口中通过添加带有 stork:// 方案的 baseUri 属性来完成

@Path("/test")
@RegisterRestClient(baseUri = "stork://rest-service")
public interface Client {
@GET
@Path("/")
Uni<String> get();
}

自定义服务选择

现在服务已定位,我们需要选择最佳实例。例如,您可以使用最少响应时间负载均衡器实现。此选择策略会监视交互并选择最快的实例以改善响应时间。

为此,您需要将负载均衡器实现添加到类路径中

pom.xml
<dependency>
    <groupId>io.smallrye.stork</groupId>
    <artifactId>smallrye-stork-load-balancer-response-time</artifactId>
</dependency>

然后在应用程序配置中添加

application.properties
quarkus.stork.my-service.load-balancer.type=least-response-time

显然,您可以选择任何负载均衡策略,甚至实现自己的策略!

总结

本文展示了如何在 Kubernetes 环境中使用 Stork 来自定义服务选择。虽然 Kubernetes 提供了内置的服务发现和负载均衡,但 Stork 增加了另一个层面的灵活性。

您可以在此仓库中查看客户端示例代码,在此仓库中查看 HTTP 服务代码。