Kubernetes - Communication Between Services

Prerequisites

  • Docker
  • Minikube

Description

In this post I show a simple example of how services communicate with each other inside the kubernetes cluster. First I’ll explain the scenario, then build the application.

Scenario

In the previous post Kubernetes - Exposing Two Services Using Ingress we had two services and exposed them outside the cluster using the ingress controller. The user could send a request to the service of choice depending on their workflow. However say they only have one workflow - they want to find the named entities from images of text. Using the previous architecture, they would have to make two requests.

First they would have to send the image to the ocr-service and get the text, then they would have to send that text to the ner-service to extract the named entities. To make the process more efficient for the use case, we will introduce a third service following the orchestrator design pattern. The user will get the named entities that are present in the text of the image in only one request.

The orchestrator-service will be responsible for accepting the image, sending it to the ocr-service, receiving the extracted text, then sending that text to the ner-service. Finally it will respond with the named entities to the original request.

Communication between services

This scenario requires the orchestrator-service to communicate with the ner-service and ocr-service inside the cluster. If you run these three services on a local machine you would point the orchestrator to some URL like http://localhost:80/api/endpoint. However, inside the cluster there is no common IP that all pods share such as ‘localhost’

Each pod that is created is assigned its own unique IP. If you delete a pod and Kubernetes recreates it, the pod that takes its place will have a new IP. Therefore there is no single IP we can use to comunicate with.

DNS

Domain Name System (DNS) is a system for associating IP addresses with easy to remember names. Kubernetes automatically configures an internal DNS service that provides a method for service discovery. This service is called CoreDNS. It listens for service and endpoint events which are triggered when you create, update or delete Kubernetes services and their associated pods. When those events occur CoreDNS updates its DNS records.

Every service defined in the cluster (including the DNS server itself) is assigned a DNS name. You use these names to target services from within the cluster instead of using IP address. The names are of the form

servicename.namespace.svc.cluster.local

Services can be resolved by the service name alone from within the same namespace. Pods can access services in other namespaces by specifying the namespace.

In this example we will deploy everything within the same (default) namespace, so we will target a URL that looks like

http://servicename:80

As long as you keep the service names consistent between deployments, your services will always be able to locate each other even if the underlying pod IP addresses are constantly changing.

In this example, the orchestrator microservice will need to communicate with other services inside the cluster. It does so by targeting the service names as defined in their kubernetes specification files. Note how each address has been set to the name of the service.

Build Docker Images

First make sure to point your shell to the minikube docker daemon. To get the command for your shell run minikube docker-env.

For example on Windows we use the following command

For more information please refer to the section Use local images by re-using the Docker daemon

Finally, make note of the minikube IP address by running this command.

minikube ip

ner-service

From the ner-service folder run docker build . -t ner

ocr-service

From the ocr-service folder run docker build . -t ocr

orchestrator-service

From the orchestrator-service folder run docker build . -t orchestrator

Create Kubernetes Deployments

In the root of the folder for the sample code (where all the yaml files are located) apply all three yaml deployments for the three services.

kubectl apply -f ner-deployment.yaml
kubectl apply -f ocr-deployment.yaml
kubectl apply -f orchestrator-deplyment.yaml

Create NodePort Service

In this example I apply the nodeport-service to expose the orchestrator outside the cluster. Note this is just for testing that the orchestrator is able to communicate with the two services and returns the expected result.

kubectl apply -f nodeport-service.yaml

Test

Run kubegtl get services, you should see three services of type CLusterIP and one NodePort service.

Then using the following command create a POST request with the body containing the test image to the endpoint api/NER on the minikube IP, port 30001 as follows

curl --verbose --request POST --header "Content-Type:multipart/form-data" --form "file=@test-image.jpg"  192.168.64.4:30001/api/NER`

You should see the following output

When finished remove the nodeport service by running

kubectl delete -f nodeport-service.yaml

Sample Code

References