Let’s implement the microservice and then test it on the development machine.
The frontend service is encapsulated in a MicroServiceVerticle
class.
The service will request another pod of the Kubernetes cluster with a service address.
The microservice Verticle creates an HttpClient
configured with a load-balancer and a resolver.
Java src/main/java/io/vertx/howtos/clientsidelb/MicroServiceVerticle.java
client = vertx
.httpClientBuilder()
.withLoadBalancer(loadBalancer)
.withAddressResolver(resolver)
.build();
For this matter we create an address resolver that takes logical ServiceAddress
as input and returns a list of addresses the HTTP client can use in practice.
The KubeResolver
is the resolver to go when deploying in Kubernetes.
Notice that the resolver is created with new KubeResolverOptions()
, configured from the pod env variables set by the Kubernetes.
Java src/main/java/io/vertx/howtos/clientsidelb/MicroServiceVerticle.java
AddressResolver resolver = KubeResolver.create(new KubeResolverOptions());
The load-balancer part is very straightforward with a round-robin strategy.
Java src/main/java/io/vertx/howtos/clientsidelb/MicroServiceVerticle.java
LoadBalancer loadBalancer = LoadBalancer.ROUND_ROBIN;
There are other available strategies.
We also need to create and bind a web server for our service, this is very much straightforward:
Java src/main/java/io/vertx/howtos/clientsidelb/MicroServiceVerticle.java
return vertx.createHttpServer()
.requestHandler(request -> handleRequest(request))
.listen(8080);
Finally let’s have a look at service request handling.
First we create an HTTP server request to the back-end server.
Instead of passing the back-end server socket address, we use instead the logical service address, which is the name of the service in Kubernetes (hello-node
).
Java src/main/java/io/vertx/howtos/clientsidelb/MicroServiceVerticle.java
ServiceAddress serviceAddress = ServiceAddress.of("hello-node");
Future<HttpClientRequest> fut = client.request(new RequestOptions()
.setMethod(HttpMethod.GET)
.setServer(serviceAddress)
.setURI("/"));
Then we implement the back-end server response handling.
We send back the original response as part of our response, decorated with the response socket address so we can determine which server the service interacted with.
Java src/main/java/io/vertx/howtos/clientsidelb/MicroServiceVerticle.java
fut.compose(r -> r.send()
.expecting(HttpResponseExpectation.SC_OK)
.compose(resp -> resp.body())
.map(body -> "Response of pod " + r.connection().remoteAddress() + ": " + body + "\n"))
.onSuccess(res -> {
request.response()
.putHeader("content-type", "text/plain")
.end(res);
})
.onFailure(cause -> {
request.response()
.setStatusCode(500)
.putHeader("content-type", "text/plain")
.end("Error: " + cause.getMessage());
});