How to use Ingress & Ingress Controller to access applications running on a Kubernetes cluster?

Shashank Srivastava
9 min readMar 10, 2021

--

Learn how Ingress & Ingress Controllers are used in Kubernetes to access the applications running inside the pods in a cluster.

Introduction

In my previous article, I explained how we can set up a Kubernetes cluster on CentOS 7 servers. And taking advantage of this cluster, I’ll demonstrate how to use Ingress & Ingress Controller in this article.

I won’t focus much on what Ingress & Ingress Controller is. I will focus on how Ingress & Ingress Controller can be used to access the various applications that run inside the pods.

As you follow the steps in this article, you will see how Ingress & Ingress Controller works & see them in action.

This article is based on NGINX Ingress Controller, so please make sure you use NGINX only.

Requirements

  • A Kubernetes cluster (Minikube cluster will also work).
  • A Linux or macOS host to access the cluster & test the application(s). Windows hosts can also be used (the hosts file location is different).

Steps to perform

1. Deploy NGINX Ingress Controller.

As an Ingress Controller is needed to fulfill the Ingress, we will need to first deploy an Ingress Controller on our Kubernetes cluster.

In the nutshell, an Ingress Controller basically creates a pod that runs in the Kubernetes cluster & inside that pod, it runs the web-server/load-balancer/proxy software such as NGINX or HAProxy. Whatever configuration you have in your Ingress resource definition is translated to the configuration file of that software, e.g /etc/nginx/nginx.conf. I’ll show it to you later in this article.

Since I am using NGINX, I deployed the NGINX Ingress Controller using this command.

[shashank@k8s-master ~]$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.44.0/deploy/static/provider/baremetal/deploy.yamlnamespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
deployment.apps/ingress-nginx-controller created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
serviceaccount/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created

This deployment will create a bunch of stuff, along-with a deployment that will create a pod running NGINX.

Note that it will take a few minutes for the NGINX pods to be running because the worker node needs to pull the Docker image.

You can check the status of the pods using this command.

[shashank@k8s-master ~]$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
default itcalc-648b49c4cf-5bm8h 1/1 Running 1 7h51m
ingress-nginx ingress-nginx-admission-create-kr4nz 0/1 Completed 5 21m
ingress-nginx ingress-nginx-admission-patch-n7cmw 0/1 Completed 5 21m
ingress-nginx ingress-nginx-controller-67897c9494-2tc4t 1/1
Running 0 21m
kube-system coredns-74ff55c5b-8cltm 1/1 Running 2 24h
kube-system coredns-74ff55c5b-z54gp 1/1 Running 2 24h
kube-system etcd-k8s-master 1/1 Running 4 24h
kube-system kube-apiserver-k8s-master 1/1 Running 30 24h
kube-system kube-controller-manager-k8s-master 1/1 Running 49 24h
kube-system kube-flannel-ds-5gnbz 1/1 Running 1 7h53m
kube-system kube-flannel-ds-dgzt6 1/1 Running 1 7h53m
kube-system kube-proxy-745j2 1/1 Running 4 24h
kube-system kube-proxy-tkhht 1/1 Running 4 24h
kube-system kube-scheduler-k8s-master 1/1 Running 48 24h

2. Deploy an application

Now we will deploy an application on our cluster. As described in my last article, I am again using my own application (it gives me a sense of pride, even though the app needs improvements). The Docker image is small enough to be pulled easily (just around 9.5 MB). Feel free to use any image of your choice.

To deploy the application, create a YAML file that contains the information about the Kubernetes deployment & service.

[shashank@k8s-master ~]$ cat it-emi-calc.yml
apiVersion: v1
kind: Service
metadata:
name: incometax
labels:
app: itcalc
spec:
ports:
- port: 80
selector:
app: itcalc
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: itcalc
spec:
replicas: 1
selector:
matchLabels:
app: itcalc
template:
metadata:
labels:
app: itcalc
spec:
containers:
- image: shashankssriva/emi-incometax-calc
name: emi-incometax-calc
ports:
- containerPort: 80
name: itcalc

Now execute this file.

[shashank@k8s-master ~]$ kubectl apply -f it-emi-calc.yml

In a few seconds, the image should be pulled & the pod should be running. It will give you a deployment itcalc & a service incometax.

Below is how to check the service.

[shashank@k8s-master ~]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
incometax NodePort 10.105.76.145 <none> 80:32706/TCP 30h
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 46h

Before we create the Ingress resource, let’s take a few moments & review the Service section in it-emi-calc.yml file.

Here, we’re creating a Kubernetes service called incometax which is available over port 80 inside the pod. The type NodePort makes it available on the worker node over a different port. Now, we will create an Ingress resource that will enable us to access the application via load-balancer, which in this case is NGINX.

Also, note that the Ingress Controller (essentially the web-server/NGINX/load-balancer) exposes its own service via NodePort. It means that the NGINX process runs on port 80 inside the pod but can be accessed outside the pod using NodePort. Because we have to access our Kubernetes application using NGINX, we have to hit the NodePort of NGINX service. As with any load-balancer, we don’t access the backend servers directly. We use the hostname/FQDN/IP address of the load-balancer.

Armed with this knowledge, let’s create an Ingress resource for our deployment.

3. Create an Ingress resource.

Create another YAML file to define the Ingress resource it-emi-calc-ingress.yml.

[shashank@k8s-master ~]$ cat it-emi-calc-ingress.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: it-emi-calc-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: shashank.info
http:
paths:
- path: /
backend:
serviceName: incometax
servicePort: 80

Notice the rules here. We’re basically instructing Kubernetes that any request that lands on the root (/) path of the server (or host) shashank.info should be served by a service called incometax.

Execute the file using…

[shashank@k8s-master ~]$ kubectl apply -f it-emi-calc-ingress.yml
Warning: networking.k8s.io/v1beta1 Ingress is deprecated in v1.19+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.networking.k8s.io/it-emi-calc-ingress created

Let’s check the ingress now.

[shashank@k8s-master ~]$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
it-emi-calc-ingress <none> shashank.info 10.128.0.28 80 4h55m

So, if you enter http://shashank.info in your browser, you should be able to access the web application. BUT it will not happen just now because of 2 reasons.

  • Your browser doesn’t know/understand shashank.info address. Of-course this domain doesn’t exist. So, you can edit your /etc/hosts file & add a line.
10.128.0.28 shashank.info

10.128.0.28 is the IP address of my worker node. Feel free to use your own hostname & worker node IP address.

  • The NGINX service inside the pod is running on port 80 but port 80 is not available outside the pod. So, the NGINX Ingress Controller exposes it to a random port using NodePort. I’ve already explained it earlier.

To check the port NodePortused by NGINX Ingress Controller, enter the below command.

[shashank@k8s-master ~]$ kubectl get svc --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default incometax NodePort 10.105.76.145 <none> 80:32706/TCP 30h
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 45h
default mymusicstats NodePort 10.101.129.100 <none> 80:30732/TCP 140m
ingress-nginx ingress-nginx-controller NodePort 10.111.171.121 <none> 80:31469/TCP,443:31124/TCP 21h
ingress-nginx ingress-nginx-controller-admission ClusterIP 10.104.100.65 <none> 443/TCP 21h
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 45h

You can see that my NGINX service is exposed to port 31469, so I should be able to access my web application by entering http://shashank.info:31469 in my browser.

4. Access the application.

Open your browser & enter the hostname defined in your Ingress resource followed by the NodePort of your NGINX service (see above).

Check the screenshot below. See how I am able to access my web application.

5. Deploy another application

Now that we have seen our Ingress Controller in action, it is time to take it to the next level. We will deploy one more application on our cluster & add another Ingress resource so that we can access this other application on a different path.

Here, I am using another application that I have created. It’s called MyMusicStats & is written in pure vanilla JavaScript. You can also access my application over the internet here.

Like my previous application, I have created a Docker image of this & pushed it to Docker Hub & it also weighs just 10 MB.

[shashank@k8s-master ~]$ cat mymusicstats.yml
apiVersion: v1
kind: Service
metadata:
name: mymusicstats
labels:
app: mymusicstats
spec:
ports:
- port: 80
selector:
app: mymusicstats
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mymusicstats
spec:
replicas: 1
selector:
matchLabels:
app: mymusicstats
template:
metadata:
labels:
app: mymusicstats
spec:
containers:
- image: shashankssriva/mymusicstats:1.0
name: mymusicstats
ports:
- containerPort: 8008
name: mymusicstats

Once you execute this file, you will get a deployment & a service called mymusicstats.

[shashank@k8s-master ~]$ kubectl apply -f mymusicstats.yml
service/mymusicstats created
deployment.apps/mymusicstats created

So, we have 2 services (excluding kubernetes) now — mymusicstats & incometax.

[shashank@k8s-master ~]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
incometax NodePort 10.105.76.145 <none> 80:32706/TCP 27h
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 43h
mymusicstats NodePort 10.101.129.100 <none> 8008:32312/TCP 2m21s

Let’s create an Ingress resource for this new application.

6. Create an Ingress Resource for the second application.

[shashank@k8s-master ~]$ cat mymusicstats-ingress.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: mymusicstats-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: shashank.info
http:
paths:
- path: /mymusicstats
backend:
serviceName: mymusicstats
servicePort: 80

Notice how we’re instructing Kubernetes to serve incoming requests on shashank.info/mymusicstats by the service called mymusicstats.

Execute this file.

[shashank@k8s-master ~]$ kubectl apply -f mymusicstats-ingress.yml
Warning: networking.k8s.io/v1beta1 Ingress is deprecated in v1.19+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.networking.k8s.io/mymusicstats-ingress created

We should now have one more ingress mymusicstats-ingress.

[shashank@k8s-master ~]$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
it-emi-calc-ingress <none> shashank.info 10.128.0.28 80 130m
mymusicstats-ingress <none> shashank.info 10.128.0.28 80 45s

This other web application can now be accessed by visiting http://shashank.info:31469/mymusicstats in the browser. Of course, you’ll need to use your port number.

P. S — You can also modify the Ingress resource of the first application to add a different path instead of root (/). Below is how I did this.

shashank@k8s-master ~]$ cat it-emi-calc-ingress.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: it-emi-calc-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: shashank.info
http:
paths:
- path: /emicalc
backend:
serviceName: incometax
servicePort: 80

See how I changed the path from / to /emicalc.

To load the changes, apply the file again.

[shashank@k8s-master ~]$ kubectl apply -f it-emi-calc-ingress.yml
Warning: networking.k8s.io/v1beta1 Ingress is deprecated in v1.19+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.networking.k8s.io/it-emi-calc-ingress configured

Now, if you change the URL to http://shashank.info:31469/emicalc, you should be able to see the first web application.

So, now we have two different applications running on the same cluster served by two different services & accessible over two different paths.

http://shashank.info:31469/emicalc

http://shashank.info:31469/mymusicstats

--

--

Shashank Srivastava
Shashank Srivastava

Written by Shashank Srivastava

DevSecOps Architect @Virtualness. Music/Book/Photography/Fitness lover & Blogger.

No responses yet