What is Service in Kubernetes
In Kubernetes, managing how parts of your application communicate with each other or with external services is crucial. That's where the concept of "Services" comes into play. A Service in Kubernetes is a resource that you use to expose an application running in a set of Pods as a network service.
Services track the IP addresses of the pods using label selectors. Since pods are ephemeral, the set of pods that a service sends traffic to can change dynamically as pods are created and destroyed. A service’s IP address remains the same over time, and other applications can rely on this consistent address despite the turnover of the underlying pods.
A Kubernetes Service acts as an L4 (Layer 4) load balancer. It ensures that traffic is distributed among the available pods.
The following diagram illustrates how Services operate:
+--------------+ +------------+ +------------+
| | | | | |
| Client +-----> Service +-----> Pod |
| | | | | |
+--------------+ +------------+ +------------+
/\ |
/ \
selector / \ label
/ \
+------------+ +------------+
| | | |
| Pod | | Pod |
| | | |
+------------+ +------------+
- Client: Initiates requests.
- Service: Distributes network traffic.
- Pods: Processes requests.
Types of Services in Kubernetes
There are three types of Services in Kubernetes:
- ClusterIP
- NodePort
- LoadBalancer
ClusterIP Service
Pods are ephemeral in nature, and it's not feasible to know on which node a Pod is deployed. Even if you were aware, Pods can be frequently restarted, so there's no guarantee of accessing the same Pod consistently.
Using a ClusterIP Service is beneficial as it abstracts the impermanent Pod IPs and places a proxy with a static IP in front of them. This eliminates the need to know the Pod IP and enables load balancing for access to the Pods.
Example: Expose and Load Balance Pod within the Cluster using ClusterIP
Start Minikube:
$ minikube start
Create a helloworld
Pod:
$ kubectl run --port 8080 --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
pod/helloworld created
Expose the helloworld
Pod as a ClusterIP Service helloworld-clusterip
:
$ kubectl expose pod helloworld --type ClusterIP --port 8080 --name helloworld-clusterip
Now, test access to the helloworld
ClusterIP Service from another Pod within the cluster:
$ kubectl run --restart Never --image curlimages/curl:7.68.0 -it --rm curl sh
/ $ curl helloworld-clusterip:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $ exit
However, the host OS cannot access the pod.
$ kubectl get pod,svc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/helloworld 1/1 Running 0 3m57s 10.244.0.3 minikube <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/helloworld-clusterip ClusterIP 10.99.232.132 <none> 8080/TCP 2m37s run=helloworld
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5m4s <none>
$ curl 10.99.232.132:8080
curl: (28) Failed to connect to 10.99.232.132 port 8080 after 75007 ms: Operation timed out
NodePort Service
NodePort Services allow exposing Pods to external networks, which is not possible with ClusterIP. It achieves this by making the Pod accessible through the Node IP and a designated port.
Example: Expose Pod Externally using NodePort
Expose the Pod as a NodePort Service:
$ kubectl expose pod helloworld --type NodePort --port 8080 --name helloworld-nodeport
Now, test access to the helloworld NodePort Service from within the cluster:
$ kubectl run --restart Never --image curlimages/curl:7.68.0 -it --rm curl sh
/ $ curl helloworld-nodeport:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $ exit
You can also access it externally using the Node IP and NodePort:
$ minikube service helloworld-nodeport --url
$ curl $(minikube service helloworld-nodeport --url)
Hello, world!
Version: 1.0.0
Hostname: helloworld
However, the downside of using NodePort is that you need to know both the Node IP and the NodePort, which is typically a high port number above 30000. Additionally, in a multi-host cluster, node IPs may change, making this method of access less stable.
To address these issues, you can use a LoadBalancer
service type, which puts a load balancer in front of the nodes and provides it with a static IP and DNS, removing the need to know the node IPs.
LoadBalancer Service
LoadBalancer services are an extension of NodePort services and are primarily used in cloud environments. They facilitate access to the Pods by routing external traffic from the cloud provider's Load Balancer to the nodes on specific ports, and eventually to the Pods.
Example: Expose Pod Externally using LoadBalancer
Expose the Pod as a LoadBalancer Service:
$ kubectl expose pod helloworld --type LoadBalancer --port 8080 --name helloworld-lb
Now, test access to the helloworld LoadBalancer Service from within the cluster:
$ kubectl run --restart Never --image curlimages/curl:7.68.0 -it --rm curl sh
/ $ curl helloworld-lb:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $ exit
You can also access it externally by fetching the LoadBalancer's URL and using curl:
$ minikube service helloworld-lb --url
$ curl $(minikube service helloworld-lb --url)
Hello, world!
Version: 1.0.0
Hostname: helloworld
When operating a Kubernetes cluster in the cloud, the LoadBalancer service will be assigned a public IP and DNS through which you can access the service.
Issues with LoadBalancer
While the LoadBalancer service provides an excellent way to expose Pods externally and abstract the Node IPs, there are some drawbacks:
- Each service requires its own LoadBalancer, which can be costly.
- It operates at L4, meaning it's not aware beyond the TCP/IP stack and cannot handle HTTP host/path-based routing.
For more sophisticated L7 (application layer) load balancing, which enables HTTP host and path-based routing, Kubernetes provides another resource called Ingress
.