Part 7- Services in Kubernetes

Erhan Cetin
8 min readNov 20, 2020

Smooth Transition to Kubernetes

Before reading this post, please visit the sample project which is used in this post, plus, highly recommend you to have a look at the Ephemeral Pods in Kubernetes. That'll give you an insight. In this post, we’re going to walk through with a Service Resource in Kubernetes. Let’s get it started.

What is a Service in Kubernetes?

After creating pods, the next questions ending up, “How can app access another app running in the cluster, or can customer access to our apps? “

For now, I’m going to focus just on inter-app communication, not the customer perspective. So, let’s redefine our question, how does a pod know another pod IP each time when redeploying happened? It is critical. Because in every new deployment, the kubelet assigns automatically a new IP to the pod, which is ephemeral, and also can place them on different nodes. Also, don’t forget the scaling up and down feature of Kubernetes. How do you get new IPs to use in your other pod every time? I think the requirements here are pretty clear. We need to make a single, constant point of entry to a group of pods. Kubernetes introduce a Service resource to handle that.

A Service resource in Kubernetes is just an abstract layer that provides a network connection to one or more Pods. Each service is given its own IP address and port, which remains constant for the lifetime of the service. The service IP itself doesn’t represent anything. IP address and port are given are virtual and you cannot ping.

To show relation pods and services, I’m going to deploy the activemq app. What we need here is just apply service and deployment :

Prepare the activemq app for the newsproducer app :

Create a service for activemq:

$ kubectl apply -f  https://raw.githubusercontent.com/ErhanCetin/k8s-smooth-transition/develop/k8s/medium-post/services/activemq-service.yaml$ kubectl get svc

Create a deployment for the activemq app :

$ kubectl apply -f  https://raw.githubusercontent.com/ErhanCetin/k8s-smooth-transition/develop/k8s/medium-post/deployment/activemq-deployment.yaml$ kubectl get pods

Here, you can get the IP of the activemq pod and put newsproducer app. But as I said, this is dynamic and will be changed after each new deployment. Also, this is not ideal for product env. We need a constant entry point for the activemq app. Let’s continue.

It is time to deploy a newsproducer app using the activemq-service:

In this YAML above, the newsproducer app connects to the activemq app via “activemq-service”, not IP.

Deploy a newsproducer app :

$ kubectl apply -f  https://raw.githubusercontent.com/ErhanCetin/k8s-smooth-transition/develop/k8s/medium-post/deployment/newsproducer-deployment.yaml

Now, the newsproducer app is ready to fetch news and put it into the activemq queue. Let’s check if it is working or not. For that, we need to access activemq-service in minikube cluster from local :

$ minikube service activemq-service # Don't close the terminal, details : https://minikube.sigs.k8s.io/docs/commands/service/

Open a browser and hit http://127.0.0.1:57462/ ( user : admin / pass: admin). You should see the news written by the newsproducer app :

What we’ve done so far :

  • Created a service for an activemq app (activemq-service )
  • Created a deployment for an activemq app (activemq-deployment)
  • Created a deployment for a newsproducer app ( newsproducer-deployment)
  • The newsproducer app’s accessed to the activemq app over the activemq-service to write the data into it. To make the scenario simple, see diagram :

We see that how can access a pod over the service. But how?

As you see in the figure above, the activemq-service is used by the newsproducer app to access the activemq app. But, how does the newsproducer know the “activemq-service”, which is called service discovery? In Kubernetes there is two way for service discovery :

  1. Environment Variable: It is being used so far in my post. When a pod is created, all services created before the pod is being injected into the container environment. In this method, you have to create a service first. Let’s check the newsproducer container env. You should see the activemq service in env variables.
# execute env in shell
$ kubectl exec -it <your newsproducer pod name > /bin/bash
$ root@newsproducer-deployment-5b8ff65958-mtbhg:/opt/newsproducer# env

Via this env injection, the newsproducer app is able to access the “activemq” app even if the activemq app is deployed again and again.

2. DNS: This is not our scope and hasn’t installed to the minikube for this post. If you want to check it: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/

After service discovery stuff, I’m going to dive a bit more into k8s internal and finish inter-app communication. So, we need to know some new players to understand the behind pod and service communication, which are kube-proxy, kubelet, and endpoint resources.

What happens when you create a service and, afterward, a pod which is backed a service (please check the Kubernetes Architecture first) :

  • When you create a service, the API server assigns immediately a virtual IP with a port you define in the service YAML file to it.
  • The API server notifies all kube-proxy agents running on the worker nodes for a service newly created.
  • A kube-proxy makes that service addressable on a node by setting a few IP table rules, which makes sure each packet destined for the service IP/port pair is intercepted, so the package is redirected to one of the pods backing the service.
  • When a pod backed service is created, the kubelet assigns an IP to it automatically. Also, an endpoint object is created to hold the related pod’s IP/port pair. Besides watching the API server for changes to Services, a kube-proxy also watches for changes to Endpoints objects. After all, an Endpoints object changes every time a new backing pod is created or deleted, and when the pod’s readiness status changes or the pod’s labels change and it falls in or out of the scope of the service.
  • As always, to make the story simple, see the figure :

So far, I’ve just covered inter-pod communication. Now, we can hang out from the customer's perspective. I’m aware that the post itself is getting boring. Sorry about that. The show must go on :)))

How can customers access our apps?

It is needed to write something a bit details about the service YAML in here, remember activemq-service YAML file :

#1: Service name: It is used to access a pod beyond the service, which you want to access the activemq app from another pod by using “activemq-service:6163”.

#2: Services come in four different types:

  • ClusterIP: The default service type, a ClusterIP service makes the service reachable from within the cluster via a cluster-internal IP, like for a database service. You can’t make requests to your Pods from outside the cluster. Note: I should have used this service type for activemq, but, ignore me for now.
  • NodePort: This makes the services accessible on a static port on each Node in the cluster. It is one of the ways to expose service outside the cluster. The Kubernetes master will allocate a port from a flag-configured range (default: 30000–32767), and each node of the cluster will proxy that port (the same port number on every Node) into your service. See figure below: how to access our FE app over the NodePort.The clients need to know the Node IPs and you may need to configure the necessary network and firewall rules to allow external traffic.
  • LoadBalancer: It is an extension of the NodePort type, which makes a service is accessible through a cloud provider’s load balancer like Azure, GCP, and AWS. The cloud provider will create a load balancer routing automatically requests to your services. This feature is not available when using Minikube. See figure below: how to access our FE app over the LoadBalancerPort.
  • External Name: Services of type ExternalName map a Service to a DNS name, not to a typical selector such as my-service.Please check for details.

#3 , #4 : service port’s list. Multiple ports can be assigned to a service.

#5: Services are assigned an IP/port pair that, when accessed, proxy to an appropriate backing pod. A service uses a label selector to find all pods. In our case, If you check https://raw.githubusercontent.com/ErhanCetin/k8s-smooth-transition/develop/k8s/medium-post/services/activemq-service.yaml, you will see the be-activemq label on it. So, when you want to access the activemq app from any other pod, you can use activemq-service:8161 or activemq-service:61613 , not with the actual IP.

As I said, I don’t really want to cover all details of a service, which means service discovery, here. Just keep in mind, also, there are Headless Service and Ingress Controller in Kubernetes’ point of service discovery perspective. If you are impatient, visit Ingress page.

Some useful commands :

$ kubectl get svc # get service list $ kubectl get deployment # get deployment list$ kubectl get pods # get pods list$ minikube service activemq-service # make service accessible from local$ kubectl get service activemq-service  --output='jsonpath="{.spec.ports[0].nodePort}"' # get nodePort of service$ kubectl get endpoints # get endpoint list# Details https://minikube.sigs.k8s.io/docs/commands/service/

--

--