In the Services topic, we have seen how to expose our application, deployed in a Kubernetes cluster, to the outside world using the service of type LoadBalancer. But what if we have to expose another application and access it from another URL? In this case, we would need to create another service of type LoadBalancer in our cluster. Each time a LoadBalancer type Service is created in a cloud environment, Kubernetes makes a request to the cloud provider's API to create a new load balancer. This can add cost for each load balancer, which would not be cost-effective.
In this topic, we will explore the concept of Ingress and understand its role in managing external access for multiple applications through a single entry point — a single IP address.
Ingress
In Kubernetes, an Ingress is an API object that provides HTTP and HTTPS routing to Kubernetes services based on defined rules. It provides a mechanism to expose multiple services to the external world. An Ingress is not a Kubernetes service; rather, it is an entry point that sits in front of the Kubernetes services you wish to expose to the internet. Ingress allows you to define rules for routing external HTTP(S) traffic to different Kubernetes services.
One way of exposing our production application to the internet is by creating a Kubernetes Service of type LoadBalancer. Typically, we have multiple applications that we would like to expose, for example, a frontend application and a REST API, so that external developers could build applications on top of ours. Each time a LoadBalancer Service is created in a cloud environment, Kubernetes sends a request to the cloud provider's API to create a new load balancer. This can add a cost for each load balancer, which would not be cost-effective. Using Ingress, we can expose multiple services with a single IP address, specifically, the IP address of the load balancer. With Ingress, you can define rules to determine how incoming requests should be routed to different services based on criteria such as the host, path, or other HTTP headers.
Ingress consists of two components: Ingress Controller and Ingress Resource. An Ingress Controller is responsible for implementing the rules defined in the Ingress resource. It listens for incoming requests and routes them to the appropriate service based on the URL or other information. Examples of Ingress Controllers include Nginx, Traefik, and HAProxy. An Ingress controller is not a part of Kubernetes by default. Different implementations of Kubernetes use different implementations of Ingress Controller. For example, the default Ingress controller varies depending on the Kubernetes distribution: for K3s, it is Traefik, and for Minikube, it is Nginx. An Ingress Resource is a Kubernetes API object that defines how external HTTP/HTTPS traffic should be routed to different Kubernetes Services within the cluster. We primarily interact with the Ingress Resource to define routing policies, while the actual implementation of the rules is executed behind the scene by the Ingress Controller.
Ingress resource
Ingresses in Kubernetes are used in conjunction with Services. The Ingress resource defines rules for the direction of external traffic, but it doesn't route traffic directly to Pods. Instead, it routes traffic to Services, which then forward the traffic to the appropriate Pods based on their labels.
In Kubernetes, Ingress operates at the application level (Layer 7) of the OSI model, managing HTTP and HTTPS routing based on hostnames, paths, etc. On the other hand, Kubernetes Services function at the network level (Layer 4), dealing with IP addresses and ports for internal traffic management within the cluster. Imagine you have an application deployed in a Kubernetes cluster, and you need to route HTTP requests like http://example.com/services/service1 to one Service and http://example.com/services/service2 to another Service. Achieving this with a regular Kubernetes Service is challenging because both HTTP requests share the same IP and DNS at layer 4, making them indistinguishable unless you inspect the actual HTTP content.
Let's see an example of a simple Ingress resource:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingressexample
spec:
rules:
- http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: exampleservice
port:
number: 80The spec section consists of rules that are applied to all incoming requests. In the provided manifest example, any request starting with /example will be directed to the Kubernetes Service named exampleservice. External traffic routing to Kubernetes Services can be configured in two ways: Path-based and Host-based, or through a combination of both. The example above illustrates Path-based routing.
Each rule contains the following fields:
host: This field is optional. In the example above, with no host specified, the rule applies to all incoming HTTP traffic through the IP address specified in the Ingress configuration. If a host is provided, such asexample.com, the rules apply specifically to that host.paths: This is a list of paths, like/foo, each linked to a backend defined byservice.nameandservice.port.nameorservice.port.number. To direct traffic to the referenced service, both the host and path must match the content of an incoming request.backend: A backend is a combination of a Kubernetes Service and port names. If incoming HTTP(S) requests to the Ingress match the specified host and path of a rule, they are directed to the designated backend.
Path-based routing policies
Path-based routing in Kubernetes Ingress allows you to route traffic to different services based on the URL path of incoming requests. This is useful when you have multiple services running in your cluster and you want to direct traffic to specific services based on the path part of the URL.
Suppose you have two services in your Kubernetes cluster, a blog-service with a service port of 80 and an ecommerce-frontend-service with a service port of 80. Now, you want to use a single domain, say example.com, and route traffic such that requests to example.com/blog go to the blog-service, while requests to example.com/store go to the ecommerce-frontend-service. This can be achieved using path-based routing policy in an Ingress resource.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- host: example.com
http:
paths:
- path: /blog
pathType: Prefix
backend:
service:
name: blog-service
port:
number: 80
- path: /store
pathType: Prefix
backend:
service:
name: ecommerce-frontend-service
port:
number: 80
In the above example, a single rule with two paths is defined, featuring the following properties:
path: /blogspecifies that requests toexample.com/blogshould be directed to the backendblog-service, listening on port80.path: /storespecifies that requests toexample.com/storewill be directed to the backendecommerce-frontend-service, listening on port80.
The pathType in path-based routing within Kubernetes Ingress is used to specify how the defined path should be matched against the URL paths of incoming requests. The pathType field has two possible values: Prefix and ImplementationSpecific.
For pathType: Prefix, the path is matched if the URL path of the incoming request starts with the specified path. The specified path is considered a prefix, and the match is successful if the URL path starts with the specified prefix. For instance, If you have a path-based rule for /blog and another for /store, using pathType: Prefix ensures that requests to /blog/* go to blog-service, and requests to /store/* go to ecommerce-frontend-service. The official documentation provides in-depth information on different path types.
Host-based routing policies
Host-based routing in Kubernetes Ingress allows you to route traffic based on the host or domain name specified in the incoming request. This is useful when you have multiple services running in your cluster and you want to direct traffic to specific services based on the domain name.
Suppose you have two services in your Kubernetes cluster, a blog-service with a service port of 80 and an ecommerce-frontend-service with a service port of 80. Each of these services is serving a different application, and you want to use the same IP address but route traffic based on different domain names. Therefore, requests to blog.example.com go to blog-service, while requests to store.example.com should go to ecommerce-frontend-service. This can be achieved by using a host-based routing policy in an Ingress resource.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- host: blog.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: blog-service
port:
number: 80
- host: store.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ecommerce-frontend-service
port:
number: 80
In the above example, two rules are defined with the following properties:
Requests to the host
blog.example.comshould be directed to the backendblog-service, listening on port80.Requests to the host
store.example.comwill be directed to the backendecommerce-frontend-service, listening on port80.
Conclusion
In Kubernetes, Ingress resource is a tool that works in combination with Services to facilitate access to Pods. Ingress serves as a single entry point for the cluster, simplifying application management and routing issue troubleshooting.
An Ingress resource lets you define rules for directing incoming traffic into the cluster from the external world. It is the responsibility of the Ingress controller to implement and manage these rules.
With Ingress resource, you can define rules for directing incoming HTTP/HTTPS traffic to specific backend services. These rules specify hosts, paths, and the backend service to handle the traffic.
While Ingress operates at the application level (Layer 7) of the OSI model, Kubernetes Services function at the network level, dealing with IP addresses and ports (Layer 4).
Ingress is primarily used for managing and controlling external access to services within the Kubernetes cluster. It defines rules for routing incoming HTTP and HTTPS traffic from outside the cluster to internal services. Conversely, Services are designed for internal traffic management within the Kubernetes cluster.