What You Need to Know About Kubernetes Services
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.
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 theClusterIP
serviceLoadBalancer
is an Extension of theNodePort
service
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