Kubernetes – Routing Services with Ingress

Kubernetes Ingress simplifies the routing of our external traffic (http & https) to our internal services. It can handle traffics from multiple domains for us.

Ingress supports implementations from multiple vendors such as NGNix, Kong, HAProxy, Ambassador and many others. They add many useful features to manage the communication with the outside world. They include features like static page caching, TLS termination, size compression, session affinity etc.

The Ingress module mainly consists of an Ingress API object that defines the requirements. And, an Ingress controller that fulfills the Ingress.

How does it simplify routing ?

Suppose we have two domains for two of our applications as shown.

Ingress lets us develop our features as separate services. For publishing, we can simply keep adding our services (service IP and port ) against the desired url paths as shown. And, its that simple! The Ingress controller is capable handling the rest for us.

How does the controller handle the Ingress routing request ?

To make the traffics from both the domains reach the Ingress Host, we can assign both the domains as host names to our Ingress Host IP. It is know as virtual hosting.

As the traffic from both the domains hit Ingress host, the Ingress controller would read the destination url in the request header. Based on the traffic routing rules, it would rout our requests to appropriate K8s services.

What other benefits do we get out of this routing feature ?

First, it separates the design of our back-end services from the our desired presentation. The reward feature and the beta version, as shown, even being deployed separately, are exposed under the same game app. It’s as if they are deployed together.

Second, it lets us share our Layer 4 Load Balancers for multiple services. A load balancer can manage the apps and expose them as internal services on different ports. Ingress can expose these services to outside, on the desired domains and url paths.

A sample Ingress object

The Ingress object shows the routing rules for the above example. A couple of path has been removed to keep it short.

The annotation under the metadata specifies the Ingress controller to be used. Here, we have used – nginx.ingress.kubernetes.io . The ngnix supports to import different features separately. ‘rewrite-target’ is one such feature.

As we can deploy multiple Ingress Controllers, it is important to specify this to point to the correct one.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-routing-example
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: fungames.com
    http:
      paths:
      - path: /
        backend:
          serviceName: service-G1
          servicePort: 80
      - path: /reward
        backend:
          serviceName: service-G2
          servicePort: 8080
  - host: prettygifts.com
    http:
      paths:
      - path: /shop
        backend:
          serviceName: service-P1
          servicePort: 8090
  - http:
      paths:
      - path: /
        backend:
          serviceName: service-D
          servicePort: 8090
Secure a Service using TLS termination

This is another feature supported by Ingress. Using TLS termination, we can create a secured tls channel between the client and the Ingress load balancer.

The ingress and the secret API object shows the configuration for the TLS termination. The highlighted lines tell the host-name to secure and the secret to use. The keys tls.crt and tls.key in the secret are the certificate and private key for tls communication.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-tls-demo
  namespace: my-prortal
spec:
  tls:
  - hosts:
      - ssl.demoservice.com
    secretName: tls-secret
  rules:
  - host: ssl.demoservice.com
    http:
      paths:
      - path: /cart
        backend:
          serviceName: cart-service
          servicePort: 8080 
apiVersion: v1
kind: Secret
metadata:
  name: tls-secret
  namespace: my-prortal
data:
  tls.crt: [base64 encoded cert]
  tls.key: [base64 encoded key]
type: kubernetes.io/tls
Demo : How to expose a K8s Services using Ingress.

As we discussed above, its as simple as adding routing rule to our service. We will try this out using a simple hello-app application from google-samples.

Step 1: Deploy Ingress Controller

This maps the url to our service as per the mappings in the Ingress object.

Ingress controllers are not started by default, we need to start it on our cluster. Use the below command to enable and verify it on a minikube.

$ minikube addons enable ingress
* The 'ingress' addon is enabled

$ kubectl get pods -n kube-system | grep ingress
nginx-ingress-controller-6fc5bcc8c9-4ztcn   1/1     Running   0          2m36s
Step 2: Deploy the services on a NodePort and ensure its accessible

As we will map this service, we will ensure its working.

Follow the steps under these two tabs to deploy and verify the service.

$ kubectl create deployment hello --image=gcr.io/google-samples/hello-app:1.0
deployment.apps/hello created

$ kubectl expose deployment hello --type=NodePort --port=8080
service/hello exposed
$ kubectl get service hello
NAME   TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
hello NodePort   10.109.247.168   <none>        8080:32321/TCP   78s

//Easy way to get the url
$ minikube service hello --url
http://160.74.10.26:32321

//Verify if the service is working 
$ curl $(minikube service hello --url)
Hello, world!
Version: 1.0.0
Hostname: web-557f59c6cf-rt9cv
Step 3: Create host name for our minikube

We are creating a host name that hits our ingress controller deployed on minikube.

Check our minikube ip and add a host name to /etc/hosts as shown.

$ minikube ip
160.74.10.26


//Add this entry to /etc/hosts
160.74.10.26 greetings.org
Step 4: Create the Ingress Object, add the routing rule and deploy

We will add a mapping for our service to expose it on a desired url.

test-ingress.yaml

apiVersion: networking.k8s.io/v1beta1 # for versions before 1.14 use extensions/v1beta1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
   - host: greetings.org
     http:
       paths:
       - path: /say-hello
         backend:
           serviceName: hello
           servicePort: 8080

We have configured to access our hello app at http://greetings.org/say-hello.

Let us deploy using ‘apply’ command and verify :

$ kubectl apply -f ingress.yaml
ingress.networking.k8s.io/example-ingress created

$ kubectl get ingresses
NAME              HOSTS           ADDRESS       PORTS   AGE
example-ingress   greetings.org   160.74.10.26   80      3m36s

$ kubectl describe ingresses example-ingress |head -20
Name:             example-ingress
Namespace:        default
Address:          160.74.10.26
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host           Path  Backends
  ----           ----  --------
  greetings.org
                 /say-hello   hello:8080 (160.78.0.7:8080)

We can verify our rules as well as the Host address where the Ingress is deployed as highlighted.

Step 6 – Lets verify if we are able access our app on our rout path

Time to test our Ingress Routing!

$ curl greetings.org/say-hello
Hello, world!
Version: 1.0.0
Hostname: hello-6649fc6cf7-tnhcn

Our routing is working ! We are able to access our service on our configured path.

Conclusion

Sitting at the edge server the Ingress can manage lot of features required as part of our communication with the outside world.

The major one being the Ingress (HTTP & HTTPS) traffic routing. This feature allows us to build applications using simpler services. It enables us to share our load balancers between multiple services. In simple terms, it provides the flexibility to expose any of our service on any url path available.

We can use the Ingress Controllers from multiple vendors. As a reverse proxy they provide many features for managing traffic. The features include TLS routing, session affinity, static page caching, Denial of Service, size compression etc.