用Stork和Quarkus扩展Kubernetes服务发现

481 阅读2分钟

Ship captain sailing the Kubernetes seas

在传统的单片机架构中,应用程序已经通过静态主机名、IP地址和端口知道后端服务存在的位置。IT运营团队为了服务的可靠性和系统的稳定性,维护着这些静态的配置。自从微服务开始在分布式网络系统中运行以来,这种第2天的操作已经发生了重大变化。发生这种变化是因为微服务需要与多个后端服务进行通信,以提高负载平衡和服务的弹性。

然而,Kubernetes并不支持编程式的服务发现和通过集成应用配置的基于客户端的负载平衡Smallrye Stork是一个解决这个问题的开源项目,提供了以下好处和功能。

  • 增强服务发现能力
  • 支持Consul和Kubernetes
  • 定制客户端负载平衡功能
  • 可管理和可编程的API

尽管如此,Java开发者需要一些时间来适应Stork项目,并将其与现有的Java框架整合。幸运的是,Quarkus使开发者能够将Stork的功能插入到Java应用程序中。本文演示了Quarkus如何让开发者将Stork的功能加入到Java应用程序中。

使用Quarkus CLI创建一个新的Quarkus项目

使用Quarkus命令行工具(CLI),创建一个新的Maven项目。下面的命令将为一个新的反应式RESTful API应用提供支架。

$ quarkus create app quarkus-stork-example -x rest-client-reactive,resteasy-reactive

输出结果应该是这样的。

...
[SUCCESS] ✅  quarkus project has been successfully generated in:
--> /Users/danieloh/Downloads/demo/quarkus-stork-example
...

打开pom.xml 文件,添加以下Stork依赖项:Stork-service-discovery-consulsmallrye-mutiny-vertx-consul-client在这里找到这个例子的解决方案。

<dependency>
  <groupId>io.smallrye.stork</groupId>
  <artifactId>stork-service-discovery-consul</artifactId>
</dependency>
<dependency>
  <groupId>io.smallrye.reactive</groupId>
  <artifactId>smallrye-mutiny-vertx-consul-client</artifactId>
</dependency>

为发现创建新的服务

创建两个服务(herovillain ),Stork 负载平衡器将发现这些服务。在src/main/java/org/acme 中创建一个新的服务目录。然后在src/main/java/org/acme/services 中创建一个新的HeroService.java 文件。

HeroService.java 文件中添加以下代码,该文件基于Vert.x反应式引擎创建一个新的HTTP服务器。

@ApplicationScoped
public class HeroService {
    @ConfigProperty(name = "hero-service-port", defaultValue = "9000") int port;
    public void init(@Observes StartupEvent ev, Vertx vertx) {
        vertx.createHttpServer()
                .requestHandler(req -> req.response().endAndForget("Super Hero!"))
                .listenAndAwait(port);
    }
    
}

接下来,通过创建一个VillainService.java 文件来创建另一个服务。唯一不同的是,你需要在**init()**方法中设置不同的名称、端口和返回信息,如下所示。

@ConfigProperty(name = "villain-service-port", defaultValue = "9001") int port;
public void init(@Observes StartupEvent ev, Vertx vertx) {
        vertx.createHttpServer()
                .requestHandler(req -> req.response().endAndForget("Super Villain!"))
                .listenAndAwait(port);
}

向Consul注册服务

正如我前面提到的,Stork允许你使用基于Vert.x Consul客户端的Consul进行服务注册。创建一个新的ConsulRegistration.java 文件,在src/main/java/org/acme/services 中注册两个同名的服务**(my-rest-service**)。最后,添加以下ConfigProperty和**init()**方法。

@ApplicationScoped
public class ConsulRegistration {
    @ConfigProperty(name = "consul.host") String host;
    @ConfigProperty(name = "consul.port") int port;
    @ConfigProperty(name = "hero-service-port", defaultValue = "9000") int hero;
    @ConfigProperty(name = "villain-service-port", defaultValue = "9001") int villain;
    public void init(@Observes StartupEvent ev, Vertx vertx) {
        ConsulClient client = ConsulClient.create(vertx, new ConsulClientOptions().setHost(host).setPort(port));
        client.registerServiceAndAwait(
                new ServiceOptions().setPort(hero).setAddress("localhost").setName("my-rest-service").setId("hero"));
        client.registerServiceAndAwait(
                new ServiceOptions().setPort(villain).setAddress("localhost").setName("my-rest-service").setId("villain"));
    }
}

将反应式REST客户端委托给Stork

herovillain 服务是正常的反应式RESTful服务,可以通过可公开的API直接访问。你需要将这些服务委托给Stork,以便发现、选择和调用服务。

src/main/java 目录中创建一个新的接口MyRestClient.java 文件。然后添加以下代码。

@RegisterRestClient(baseUri = "stork://my-rest-service")
public interface MyRestClient {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    String get();
}

stork:// 开始的baseUri使Stork能够发现服务,并根据负载平衡类型选择一个。接下来,修改现有的资源文件或创建一个新的资源文件(MyRestClientResource)来注入RestClient (MyRestClient)和端点**(/api**),如下图所示。

@Path("/api")
public class MyRestClientResource {
    
    @RestClient MyRestClient myRestClient;
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String invoke() {
        return myRestClient.get();
    }
}

在你运行应用程序之前,在application.properties中配置Stork以使用Consul服务器,如下图所示。

consul.host=localhost
consul.port=8500
stork.my-rest-service.service-discovery=consul
stork.my-rest-service.service-discovery.consul-host=localhost
stork.my-rest-service.service-discovery.consul-port=8500
stork.my-rest-service.load-balancer=round-robin

测试你的应用程序

你有几种方法来运行本地的Consul服务器。在这个例子中,使用一个容器来运行服务器。这种方法可能比安装或引用一个外部服务器更简单。在这里找到更多信息。

$ docker run --rm --name consul -p 8500:8500 -p 8501:8501 consul:1.7 agent -dev -ui -client=0.0.0.0 -bind=0.0.0.0 --https-port=8501

使用Dev模式运行你的Quarkus应用程序。

$ cd quarkus-stork-example
$ quarkus dev

输出看起来是这样的。

...
INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, jaxrs-client-reactive, rest-client-reactive, resteasy-reactive, smallrye-context-propagation, vertx]
--
Tests paused
Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
Access the RESTful API (/api) to retrieve available services based on the round-robin load balancing mechanism. Execute the following curl command-line in your local terminal:
& while true; do curl localhost:8080/api ; echo ''; sleep 1; done

输出看起来应该是这样的。

Super Villain!
Super Hero!
Super Villain!
Super Hero!
Super Villain!
...

总结

你学到了Quarkus如何让开发者使用Stork和Consul为反应式Java应用程序整合基于客户端的负载均衡编程。开发人员在继续开发Quarkus中的反应式编程的同时,还可以使用实时编码获得更好的开发者体验。关于Quarkus的更多信息,请访问Quarkus指南和实践