Creating a Kubernetes Nginx Ingress Controller and create a rule to a sample application
Whenever you are creating an application that you want to expose to the outside world, it's always smart to control the flow towards the application behind it. That's why Kubernetes has something called Kubernetes Ingress
. But what is it?
Kubernetes Ingress
Kubernetes Ingress allows you to expose HTTP and HTTPS routes from outside the cluster to services within the cluster. The traffic routing is then controlled by rules defined in the ingress sources.
For this article, I will explain how you can get started on creating your own Nginx Ingress Controller
. Of course this is not the only possibility, so feel free to check other ingress controllers such as Istio, HAProxy, Traefik, …
Some advantages of using an ingress controller:
- Rate limiting, Timeouts, …
- Authentication
- Content based routing
Sample Hello World application
Before we create our controller, let's get started on creating a simple demo application. The only thing our application will do is process the HTTP request, wait a couple of seconds and return a "Hello World" response.
Creating our sample app
I decided to create this application in Node.js. So if you have npm
and node
installed, run the following commands:
npm init -y
npm i express --save
Whereafter you can create an index.js
file with the following content:
const express = require('express')
const app = express()
const port = 3000
app.get('/', async (req, res) => {
console.log('Got request, waiting a bit');
await delay(15 * 1000);
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
const delay = async (timeout = 1000) => {
return new Promise((resolve, reject) => setTimeout(resolve, timeout));
}
Packaging it as a container
Since everything is created in terms of application code, we can package it all up into a Docker container by creating a Dockerfile:
Dockerfile
FROM node:latest
WORKDIR /usr/src/app
# Install deps
RUN apt-get update
# Create Certificate
RUN apt-get install ca-certificates
# Install Package.json dependendencies
COPY package.json .
RUN npm install
# Copy Source Code
ADD . /usr/src/app
CMD [ "npm", "run", "start" ]
EXPOSE 3000
That we can build with (choose one for your use-case):
# Local build (for local use)
# Note: when using minikube, make sure to run `eval $(minikube docker-env)` to build images in minikube context
docker build -t local/node-sample-helloworld .
# Remote build (to push to docker repository)
docker build -t thebillkidy/node-sample-helloworld .
docker push thebillkidy/node-sample-helloworld
Running it on Kubernetes
Once it is build, we can now run it on our Kubernetes cluster. For that we create a Deployment YAML file:
kubernetes.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: d-node-sample-helloworld
spec:
selector:
matchLabels:
app: node-sample-helloworld
replicas: 1
template:
metadata:
labels:
app: node-sample-helloworld
spec:
containers:
- name: main
image: thebillkidy/node-sample-helloworld:latest # if local, utilize local/node-sample-helloworld
imagePullPolicy: Always # if local, utilize Never
ports:
- containerPort: 3000
That we can apply with kubectl apply -f kubernetes.yaml
and should now show the following after running kubectl get deployments -A
:
NAME READY UP-TO-DATE AVAILABLE AGE
d-node-sample-helloworld 1/1 1 1 37s
Kubernetes is getting more popular everyday and it's no wonder why! When you are running applications on-premise or in-cloud, the possibility of having the applications in a portable way is a strong one! Removing the friction for scaling-out your application when you are ready for it, or even bursting scenarios.
Nginx Ingress Controller
We now have a simple Hello World application running, but it's only available internally! What we could do now is expose it through Kubernetes and a LoadBalancer, but let's actually utilize our Ingress Controller here! So let's get started creating this Ingress Controller.
Installation
The first step that we should do is create the NGINX Ingress controller. For this we can follow these steps:
Note: before the stable/nginx-ingress
chart was utilized. But this is now deprecated!
# ref: https://github.com/kubernetes/ingress-nginx (repo)
# ref: https://github.com/kubernetes/ingress-nginx/tree/master/charts/ingress-nginx (chart)
# 1. Create namespace
kubectl create namespace ingress-nginx
# 2. Add the repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
# 3. Update the repo
helm repo update
# 4. Install nginx-ingress through Helm
helm install ingress-controller ingress-nginx/ingress-nginx --namespace ingress-nginx
Once we ran the above, we should now be able to access the ingress controller by loading the external IP (kubectl -n ingress-nginx get svc
).
Note: when working with Minikube or others, we can utilizekubectl port-forward svc/ingress-controller-ingress-nginx-controller --namespace ingress-nginx --address 0.0.0.0 8000:80
and access it onhttp://localhost:8000
We are now ready to expose our application!
Exposing our Application
Once an ingress controller is created, we need to expose our application internally:
kubectl expose deployment d-node-sample-helloworld --name svc-node-sample-helloworld
and configure our Ingress controller to route traffic to it as defined in the Kubernetes Ingress API. By creating a YAML file:
ingress-node-sample-helloworld.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-node-sample-helloworld
annotations:
# Target URI where the traffic must be redirected
# More info: https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/rewrite/README.md
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
spec:
rules:
# Uncomment the below to only allow traffic from this domain and route based on it
# - host: my-host # your domain name with A record pointing to the nginx-ingress-controller IP
- http:
paths:
- path: / # Everything on this path will be redirected to the rewrite-target
backend:
serviceName: svc-node-sample-helloworld # the exposed svc name and port
servicePort: 3000
Which we apply with kubectl apply -f ingress-node-sample-helloworld.yaml
Now once this is applied, we should be able to execute a cURL request to access our application! So let's try this:
# Execute a GET request with the specified host and IP
# Note: the Host should match what is written in spec.rules.host
curl -k -X "GET" -H "Host: my-host" http://YOUR_IP
Or we can also open it in our browser and navigate to http://YOUR_IP
Note: If this is not working, check kubectl describe ing
and make sure that the configuration is correct
Conclusion
In this article a demonstration was made on how you can set up your own ingress controller for Kubernetes. This is of course a small step in the entire chain of use cases, where most often you want to do more such as rate limiting, or even monitoring it.
The next article will explain more in-depth how you are able to start monitoring what we have just set-up through Prometheus and visualize all of it in Grafana.