Monday 13 May 2024

Kubernetes ClusterIP Service

This article extends my notes from an Udemy course "Kubernetes for the Absolute Beginners - Hands-on". All course content rights belong to course creators. 

The previous article in the series was Kubernetes NodePort Service | My Public Notepad.


A full stack web application typically has different kinds of pods hosting different parts of an application, for example:
  • pods running a frontend web server; their IPs could be e.g. 10.244.0.2, 10.244.0.3, 10.244.0.4 
  • pods running a backend server with IPs 10.244.0.5, 10.244.0.6, 10.244.0.7
  • pods running a key-value store / in-memory DB (e.g. Redis) with IPs e.g. 10.244.0.8, 10.244.0.9, 10.244.0.10
  • pods running a persistent database (e.g. MySQL)
Frontend servers needs to communicate to the backend servers which in turn need to communicate to the database as well as the Redis services etc. How to establish connectivity between these services or tiers of this web application?

The pods all have an IP address assigned to them, but these IPs are not static. These pods can go down any time and new pods are created all the time. We cannot rely on these IP addresses for internal communication between the application tiers.

Also, what if the first front end pod at 10.244.0.2 need to connect to a backend service? Which of the three would it go to and who makes that decision?

Kubernetes service named ClusterIP:
  • group the pods together
  • provide a single interface to access the pods in a group

For example, a service created for the back end pods will help group all the back end pods together and provide a single interface for other parts to access this service. The requests are forwarded to one of the pods under the service randomly. Similarly, create additional services for Redis and allow the back end pods to access the Redis systems through the service. 

This enables us to easily and effectively deploy a microservices based application on Kubernetes cluster. Each layer can now scale or move as required without impacting communication between the various services. Each service gets an IP and name assigned to it inside the cluster, and that is the name that should be used by other paths to access the service.


How to create a ClusterIP service?


We need to provide a definition file:

clusterip-service-definition.yaml:

apiVersion: v1
kind: Service
metadata:
  name: back-end
spec:
  type: ClusterIP
  ports:
    - targetPort: 80
      port: 80
  selector:
    app: myapp
    type: back-end


ClusterIP is the default type for Service kind. Even if we don't specify type, it will be assumed the type to be ClusterIP.

targetPort is the port where the back end is exposed and the port is where the service is exposed and it is the same one as targePort.

To link the service to a set of ports we use selector. We can check the pod definition file and copy the labels from it and move it under selector.


To create the service:

$ kubectl create -f ./minikube/service/clusterip-service-definition.yaml 
service/back-end created

To check its status:

$ kubectl get svc
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
back-end        ClusterIP   10.111.52.100    <none>        80/TCP         12s
kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP        25d
myapp-service   NodePort    10.104.148.160   <none>        80:30008/TCP   37h


The service can be accessed by other parts using the cluster IP or the service name.

If we run the same command before any our custom service is created, we'll see that there is already one service created implicitly:

$ kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.43.0.1    <none>        443/TCP   14m

That is a default service created by Kubernetes at launch.

$ kubectl describe service kubernetes
Name:              kubernetes
Namespace:         default
Labels:            component=apiserver
                   provider=kubernetes
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.43.0.1
IPs:               10.43.0.1
Port:              https  443/TCP
TargetPort:        6443/TCP
Endpoints:         192.40.199.6:6443
Session Affinity:  None
Events:            <none>

This is a ClusterIP service with one endpoint attached (one pod with IP 192.40.199.6). 

In general, if there were multiple pods that this service is directing traffic to, we'd have here multiple IP addresses, for each pod. Endpoints are basically pods that are filtered based on the selector's labels. 
---

No comments: