Published on

What You Need to Know About Kubernetes Services

Authors

caption

Introduction

A pod is the smallest unit of deployment in Kubernetes and each one gets its IP address when deployed in a Kubernetes cluster. Pods are ephemeral i.e they are destroyed frequently. When the old pod dies and new ones are created in their place, new IP addresses are assigned. Therefore it doesn't make sense to use pod IP addresses to access your application directly as you will have to keep up with the constantly changing IPs when the pods get recreated. This is where Services comes in

A Service is an abstraction that defines a set of Pods and a policy to access them. Services usually have a stable IP address and provide a consistent way of accessing Kubernetes Pods. Services also provide load balancing, loose coupling, and communication within and outside the cluster

In this article, you will learn what a Kubernetes Service is, why they are needed, different types of services, and their use cases

Service Definition

An example of what a service definition looks like.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

The name of the service is my-service as seen above. The selector flag is used to identify the pods to forward the request to. They are usually defined as labels on the Pod. Under the ports section, the port is the service port while the targetPort is used to identify the container port to forward requests to on the Pod.

Service Communication

You might be wondering

  • How does a service know which pod to direct traffic to?

  • How does the service know the port to also forward requests to in the case of a multi-container pod?

Services identify the pod to direct traffic using selectors. The selectors are usually defined as key-value pairs under the spec section of the service definition file(YAML).

There are also instances where you have a multi-container pod with each container listening on a different port. The Service would be able to identify the container to forward the request to with the targetPort attribute

Service Endpoints

When you create a service, Kubernetes creates an Endpoint object that has the same name as the service itself. It is used to keep track of the pods that are endpoints of that service.

Service Endpoints

Headless Service

As seen above, service endpoints keep track of the pods that are endpoints of the service. Services use the endpoint to dynamically forward the request to any of the pods with the right label. But sometimes, you want to communicate directly with a Pod especially when working with stateful applications like a database. Kubernetes allows you to define a headless. When you create a Headless service, there is no load balancing or proxying done by the platform for them, this way you can make a request to a specific pod as opposed to randomly forwarding requests to Pods

To define a Headless Service, set the clusterIP under the spec section to None.

apiVersion: v1
kind: Service
metadata:
  name: headless-svc
spec:
  clusterIP: None
  selector:
    app: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Multi-Port Services

There are scenarios where you need to expose more than one port in your service. i.e You can expose one port to handle client requests and the other port to perform another operation like logging or monitoring. Services allow you to do that by defining the ports as a list. When defining multi-port services, it's advisable to give it a name to differentiate each port

apiVersion: v1
kind: Service
metadata:
  name: multi-port-svc
spec:
  selector:
    app: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
    - name: https
      protocol: TCP
      port: 443
      targetPort: 9377

Types of Services

  • ClusterIP: This is the default service type in Kubernetes. When you create a service without specifying the type, it automatically becomes a Cluster IP. Cluster IP exposes the service on an internal IP in the cluster. Services of type ClusterIP are only reachable from within the cluster. An example of a service with the type ClusterIP is given below
apiVersion: v1
kind: Service
metadata:
  name: cluster-ip-svc
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  • NodePort: This is a type of service that is accessible on a static port on each worker node in a Kubernetes cluster. While a clusterIP only allows traffic from within the cluster, NodePort on the other hand allows External Traffic through the fixed port on the worker nodes. So instead of using Ingress, the client can hit the cluster directly via the static port. When you create a Service of type NodePort, a ClusterIP service is automatically created. The NodePort uses the ClusterIP to route the request through the cluster internally. This type of Service definition is not secure, as you are opening the port to directly talk to the services on the worker nodes. The NodePort type is mainly used for testing purposes and not used in a production environment. The NodePort is an extension of the ClusterIP service
apiVersion: v1
kind: Service
metadata:
  name: node-port-svc
spec:
  type: NodePort
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
      nodePort: 30021

It is important to note that, the nodePort attribute under the service definition can only have a value within the range of 30000 - 32767

  • Load Balancer: This type of Service definition allows the service to become accessible externally through cloud provider's load balancer functionality. Cloud providers have their native implementation of a load balancer which is used whenever you create a service type of Load balancer. When you create a Load balancer service, NodePort and ClusterIP Services are created automatically by Kubernetes to which the external load balancer of the cloud platform will route traffic. LoadBalancer Service is an extension of the NodePort Service
apiVersion: v1
kind: Service
metadata:
  name: load-balancer-svc
spec:
  type: LoadBalancer
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
      nodePort: 30021

ClusterIP, NodePort and LoadBalancers

It is important to note that

  • The ClusterIP Service is only reachable from within the cluster

  • NodePort is an Extension of the ClusterIP service

  • LoadBalancer is an Extension of the NodePort service

    Relationship

Conclusion

In a real Kubernetes setup in production, you will not use the NodePort Service for external connection. You can use it to test your application but not for a production use case. If you have an application you want to expose to the client from the Kubernetes cluster, you can consider using an Ingress or use a Service type of LoadBalancer that uses the cloud provider's load balancer implementation. You can read more about Kubernetes Services here