In this tutorial post, we will see why we need service and then see what is a service and the types of services in Kubernetes.
Now, if we want to establish connectivity from a Wordpress pod to another MySQL pod, the MySQL pod does not know which pod to connect to. As a hypothetical scenario, we have to establish a connection via IPs and when we establish a connection by hardcoding IPs, we keep giving work to the same MySQL pod and the other pods are not utilized.
Now that takes away the very benefit that deployments give and the pods become mortal again. Let's say a pod with x IP is deleted, the deployment controller will create another pod with y IP. Now, WordPress pod doesn't know which MySQL pod it should connect to as it only knew pod with x IP.
Its a pandemonium. Now the MySQL pods decide that they will get themselves a manager which will be discovered easily by the WordPress Pod and to others if needed by a single static name and load balance the work among them.
Thus services are born. A Kubernetes Service is an abstract way to expose an application running on a set of Pods as a network service. With Kubernetes, you don't need to modify your application to use an unfamiliar service discovery mechanism.
Kubernetes gives Pods their own IP addresses and a single DNS name for a set of Pods and can load-balance across them.
Now the WordPress pod doesn't need to know about MySQL pod or its IPs. It only needs to know about the name of the service that front-ends the MySQL pods.
You can have many services within the cluster. Kubernetes services can efficiently power a microservice architecture.
Services provide features that are standardized across the cluster(irrespective of the nodes on which the service and pods are running on):
- Load balancing
- Service discovery between applications (DNS,port-mapping).
- Features to support zero-downtime application deployments (on combination with rollingUpdates of deployments).
There are 3 different types of services.
This is the default Service type. It exposes the service on a cluster internal IP. Choosing this type makes the service reachable only from within the cluster.
So except the web or app service, all other services which should not be accessed from the outside like DB use ClusterIP service.
A NodePort is a very basic way to get external traffic directly to your service.
NodePort opens a specific port on your node/VM and when that port gets traffic, that traffic is forwarded directly to the service. The service is applied to all nodes in the cluster(master and workers) and hence can be accessed by http://anyNodeName:port.
For a NodePort service, Kubernetes allocates a port from a configured range ( default is 30000 - 32767). We cannot use standard ports like port 80 or 8080. It is possible to define a specific port number(in the range), but you should take care to avoid potential port conflicts.
There are a few limitations like
- Only one service per port
- You can only use ports 30000-32767.
- Dealing with dynamic or changing node/VM IP is difficult.
A LoadBalancer is the standard way to expose a service to the internet.
Only in case of public cloud providers like Azure, GCP, AWS, etc, on creating a service of type LoadBalancer, an external LoadBalancer in that public cloud would be created.
In the case of a private cloud, by default, a service of type LoadBalancer would behave like a service of type NodePort. A custom load balancer like NGINX or load balancers applications like DevCental F5 will use the IP and port of the nodes on which the service is running to load balance it.
A service manifest like other kubernetes object manifests have
- spec - selector and ports
.spec.type specifies the type of service we need to create.
Default is ClusterIP and other acceptable values are NodePort and LoadBalancer.
Like we have seen in a deployment manifest,
.spec.selector must match the
.metadata.labels of the pods which have to be load-balanced and catered by this service. This is the link between the service and the pods in the deployment.
The difference between deployment manifest and service manifest selectors is that deployment manifest selector will have
.spec.selector.matchLabels and service manifest will have
Below, ports[i..n] represents the index of the port object
- .spec.ports[i..n].port represents the port on which the service is listening to.
- .spec.ports[i..n].targetPort represents the port of the pods to connect to.
- .spec.ports[i..n].protocol is the protocol to use - default is tcp
- .spec.ports[i..n].name is the name of the virtual server (each port)
.spec.ports is an array and we can define multiple ports here.
--- apiVersion: v1 kind: Service metadata: name: app-service labels: app: wordpress type: app-service spec: selector: app: wordpress type: app type: LoadBalancer ports: - protocol: TCP port: 80 targetPort: 80 name: wordpress
In the above example, we created a service of type LoadBalncer and the values in .spec.selector should match with the label of the pod to connect to and port 80 represents that the service is listening to requests on port 80 and targetPort 80 represents that the service is sending traffic to the nodes on port 80.