Fouad
Fouad

Reputation: 855

Service discovery with microservices in kubernetes

I've been reading a lot about microservices and kubernetes a lot lately, and also experimenting with the two technologies. I am aware of the different pieces available in k8s such as pods, services, deployments... I am also aware that services can be of type ClusterIP to restrict connectivity to within the cluster.

Let's say we have 10 microservices that each expose its functionality using some kind of http server. Basically each microservice is a REST API. In kubernetes terms, this would be a container managed by a Pod and there would be a Service managing this Pod's connectivity.

My question is the following: If you are not using a framework such as Spring that utilizes Eureka, for example bare bone golang http server in each microservice. How does each service find the other service without passing the service name and port number to each microservice.

For example: Let's say Service A is exposed on port 8080 which needs to call Service B which is exposed on port 8081 and another service which is running on port 8082; this means that we need to pass the ports as environment variables to Service A...You can clearly see that when the number of services increases, it will be hard maintaining all of these environment variables.

How do people solve such a problem? do they use some kind of centralized service registry? if yes then how would that service registry integrate with the kubernetes Service?

Thanks in advance

UPDATE

The provided accepted answer is spot on with the explanation, the thing that I was failing to see is that for example in kubernetes, typically each deployment object has its own IP address so it's okay to use the same port number for each microservice.

In case anyone is interested with a simple/dummy microservice example, I put together a small project that can be run on a local kubernetes cluster with minikube.

https://github.com/fouadkada/simple_microservice_example

Upvotes: 1

Views: 2031

Answers (2)

Matt
Matt

Reputation: 8152

I understand that by saying service you mean microservice, but to avoid ambiguity, first I would like to define some things. When I say service I am refering to k8s service. When I say application I am refering to application running in pod.

Now your questions:

How does each service find the other service without passing the service name and port number to each microservice

In kubernetes there is a concept of services (link to docs). Each service is registered in k8s dns server (typically CoreDNS). You can use names of these services as regular FQDN.


Let's say Service A is exposed on port 8080 which needs to call Service B which is exposed on port 8081 and another service which is running on port 8082; this means that we need to pass the ports as environment variables to Service A.

As @sachin already mentioned correctly, you don't typically use different ports for every application just beacuse you can. Porst are good to use to know what type of application you can expect on specific port. e.g. when you see port 80 it is almost certain it's HTTP server. When you see 6379 you can be pretty sure its redis etc.

In k8s documentation on Kubernetes networking model you can find:

Every Pod gets its own IP address. This means you do not need to explicitly create links between Pods and you almost never need to deal with mapping container ports to host ports. This creates a clean, backwards-compatible model where Pods can be treated much like VMs or physical hosts from the perspectives of port allocation, naming, service discovery, load balancing, application configuration, and migration.


One last thing you may have not known about is that when k8s starts a pod some information about already existing services is passed through environment variables. You can check it yourself; just exec to any pod an run set to see all environment variables.

Here is example output (I removed unimportant part):

KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443

But please notice that these environment variables are services listed only within the same namespace as your application and only those that existed then creating the pod. Anything created after container started will not be reflected in envs.


To summarize and answer your question:

How do people solve such a problem?

People use DNS (existing on every k8s cluster) and static ports (ports that don't change randomly).

Of course there are solutions like Consul, but out of the box functionality of k8s is sufficient for 90%+ usecases.

Upvotes: 5

sachin
sachin

Reputation: 1350

I assume the application has some client library to communicate with kubernetes which has service discovery capability.Each application is exposed to other applications in kuberenetes by Kubernetes services.

Instead of giving each microservices a seperate port , give same port for each application eg:8080. Then correctly map your application to the Kubernetes service object.After that, you can easily call other microservices with http://your-kubernetes-service-name:8080 to communicate.

Basically if your pod contains only one container per pod, you need not pass different port numbers for different services. Its recommended to run one container per pod as a best practice.

Upvotes: 1

Related Questions