- An application deployed on a Kubernetes Cluster runs as a collection pods.
- The pods are essentially containers that are scheduled across multiple nodes.
- Nodes can be physical servers or VMs offered by your hosting provider. Obviously, you can also Kubernetes on an on-premise server, if you so desire.
- Each Pod has a unique IP address.
- Your application is split into many subcomponents, often referred to as microservices.
- For each microservice of your application, has a corresponding Service in Kubernetes.
- In the context of Kubernetes, a Service exposes a collection of pods to the rest of the cluster as a single abstraction. A single virtual IP.
- This helps one service of your application communicate with another service. It is an abstraction that allows you to address a collection of pods, rather than specifying the IP address of a pod, everytime you want to talk to it.
- A Kubernetes Service also acts as a load balancer for all the pods that it represents. The traffic gets evenly distributed across all the nodes.
So far so good. Each Service can talk to another service. This communication is possible across the entire Kubernetes cluster
“If a tree falls in a forest and no one is around to hear it, does it make a sound?”
On a similar note, if your application doesn’t serve a purpose outside the Kubernetes cluster, does it really matter whether or not your cluster is well built? Probably not.
To give you a concrete example, let’s say we have a classical web app composed of a frontend written in Nodejs and a backend written in Python which uses MySQL database. You deploy two corresponding services on your Kubernetes cluster.
You make a Dockerfile specifying how to package the frontend software into a container, and similarly you package your backend. Next in your Kubernetes cluster, you will deploy two services each running a set of pods behind it. The web service can talk to the database cluster and vice versa.
However, Kubernetes doesn’t expose any of these services (which are essential HTTP endpoint) to the rest of the world. As stated in the official docs:
“Services are assumed to have virtual IPs only routable within the cluster network”
This is perfectly reasonable from a security standpoint, your services can talk to one another, but the cluster won’t allow outside entities to talk to the services directly. For example, only your web frontend can talk to the database service, and no one else can even to send requests to the database service.
The problem arises when we look at the use case of a frontend service. It needs to be exposed to the rest of the Public so end users can use your application. We expose such Services using Kubernetes Ingress.
Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. You can control the routing rules by defining the Kubernetes Ingress resource. But it does a lot more than that. Exposing a single Service can be achieved using various other alternatives like NodePort or Load Balancers but these facilities don’t have features that are sophisticated enough for a modern web app.
Features like, exposing multiple apps on a single IP, defining routes, etc.
So let’s understand these features for the remaining of the article:
Single Service Ingress
This is the simplest version of exposing a single service like a web frontend with an IP (or a domain name) and default HTTP and HTTPS ports (i.e, 80 and 443).
This is an ingress setup that allows you to allow incoming traffic to a single IP and route it to multiple services.
It consists of:
- An ingress resource consists of a host name foo.bar.com
- A list of paths where the traffic is going to be routed like foo.bar.com/admin foo.bar.com/home foo.bar.com/sso
Single fanout is the case where a single IP is used for multiple services. The services can be at different paths in the URI like foo.bar.com/admin can be a service for administrators and foo.bar.com/home can be the service that generates each users home page.
The ingress port will always be 80 or 443, but the port where the services are running (inside the cluster) may differ quite a bit.
This kind of ingress helps us minimize the number of load balancers in the cluster, since it essentially acts like one.
Name Based Virtual Hosting
Public IP addresses are finite. They are also quite expensive. The idea of name based virtual hosting is older than Kubernetes. The gist of it is that, you point the DNS records for different websites like ww1.example.com and ww2.example.com to the same IP address. The server running at that IP address will see the incoming request, and if the host name mentioned in the request is for ww1.example.com then it serves that website for you, and if ww2.example.com is requested, then that is served.
In the context of Kubernetes, we can run two services running at, say, port 80 and expose both of them on a single IP address using an ingress also of port 80. At the ingress point the traffic of ww1.example.com will get separated from the traffic for ww2.example.com. Hence the term name based virtual hosting.
Ingress in Kubernetes is quite sophisticated to be covered in a single post. There are a variety of use cases for it, and a variety of Ingress Controllers that will add the Ingress functionality to your cluster. I would recommend starting with Nginx Ingress Controller.
For further details and specifications you can also follow the official documentation.