Integrating Lagom Service Discovery with Kubernetes

Table of contents
Reading Time: 3 minutes

Consider a situation where a microservice is deployed on multiple pods and on condition one pod got restarted with any of the failure reason makes unreachable and at the same time interdependent services are registers its IP for communication. Now, since other pods of the service are alive but not able to communicate makes the communication failure as well as making the failure of every call to service which is dependent makes a disconnected network i.e dependent service is trying to talk a machine/pod which is no more. So, this problem simply solved by service discovery. Usually, in containerized environment service internal IP address changes frequently. The above scenario also happens in case of scale up and scale down of service.

In this post, we will learn what service discovery is, how Lagom locate a service and most important how to delegate Lagom service locator to Kubernetes to locate service running over the pod.

What is Service discovery?

Service discovery defines how services locate each other. The concept is broader in case of cluster nodes are dynamic, service discovery tool provides an address of a live node at a given time. This is very much similar to the service registry in Service Oriented Architecture. In a monolithic application, service invokes one another through simple procedural calls but in distributed environment service run to a well-known location so, call each other either using rest call or some RPC method calls. Typically service discovery is of two types:

    • Client Side Discovery
    • Server Side Discovery

The only difference in client and server-side discovery is that server-side service discovery relies on router or load balancer to get location instead of in client-side discovery client directly call for service registry.

Service Discovery in Lagom

Lagom has the implementation of Service Locator named as Lagom Service Locator which inherits from CircuitBreakingServiceLocator having implementation for handling circuit breaker. In Lagom service locator there is an overridden method locate which takes the name of the service as parameters and the return type is resolved URI. This resolved URI contains the IP address of a machine in which service is running and in case of Kubernetes, this should be the IP address of anyone such pod on which service is running. Let’s have a look over the method locate by Lagom as well as name register by dependent service to locate itself.

Registering a service

public interface HelloService extends Service {
    ServiceCall<NotUsed, String> hello(String id);
    @Override
    default Descriptor descriptor() {
        return named("helloservice").withCalls(
                restCall(Method.GET, "/api/hello/:id", this::hello)
        ).withAutoAcl(true);
    }
}

Locating a service

@Override
public CompletionStage locate(String name, Descriptor.Call serviceCall) {
    return com.lightbend.rp.servicediscovery.javadsl.ServiceLocator
            .lookupOne(name, "http", actorSystem)
            .thenCompose(service -> service.isPresent() ? CompletableFuture.completedFuture(service) : com.lightbend.rp.servicediscovery.javadsl.ServiceLocator.lookupOne(name, actorSystem))
            .thenApply(service -> service.map(Service::uri));
}

Now, notice one thing the name in the locate method is the name of dependent service as defined in the descriptor. That was all about Lagom’s service discovery. Let’s move on to Kubernetes service discover and see what Kubernetes does for discovering a service and trying to delegate service discovery to Kubernetes service discovery. The main reason for delegation is that calling an Akka cluster based microservice on Lagom will not be able to recognized by Lagom service locator.

Service Discovery in Kubernetes

Kubernetes allows discovering with service name running in the same namespace. For example, there is greeting service which calling hello service to welcome and both greeting and hello service running on multiple pods say it 3. It automatically resolves anyone live pod IP by calling the service by name i.e. hello.cluster.local or in case of service running on another namespace then service locator is <namespace>.hello.

Delegate Lagom Discovery To Kubernetes

For custom service discovery in Lagom just extend CircuitBreakingServiceLocator which overrides locate method in which we are writing the code for delegation, only trick here is to provide the Kubernetes service name same as in Lagom service descriptor, with this Kubernetes and Lagom both register the service name with identical name and now see the delegation code below.

public class GreetingCustomServiceLocator extends CircuitBreakingServiceLocator {

    private final ActorSystem actorSystem;

    @Inject
    public GreetingCustomServiceLocator(final ActorSystem actorSystem, final CircuitBreakersPanel circuitBreakersPanel) {
        super(circuitBreakersPanel);
        this.actorSystem = actorSystem;
    }

    @Override
    public CompletionStage<Optional<URI>> locate(final String name, final Descriptor.Call<?, ?> serviceCall) {
        try {
            String serviceLocatorUri = ServiceConstants.HTTP_PROTOCOL_KEY + name + ServiceConstant.KUBERNETES_SERVICE_INTERNAL_PORT;
            return CompletableFuture.completedFuture(Optional.of(new URI(serviceLocatorUri)));
        } catch (URISyntaxException e) {
            LOGGER.error("Error while parsing URI : " + serviceLocatorUri);
            throw new RuntimeException();
        }
    }
}

Here the GreetingCustomServiceLocator return an object of URI with dependent service name which internally resolved by Kubernetes.

Hope you find the blog helpful.

Reference

  1. Lagom Service Locator.
  2. Akka Kubernetes API.
  3. Kubernetes Services.
Knoldus Blog Footer