Skip to content

Instantly share code, notes, and snippets.

@shafinhasnat
Last active September 4, 2022 11:15
Show Gist options
  • Save shafinhasnat/744f8e781942b9a430eb7ed6e6859f55 to your computer and use it in GitHub Desktop.
Save shafinhasnat/744f8e781942b9a430eb7ed6e6859f55 to your computer and use it in GitHub Desktop.
Kubernetes ingress-nginx-controller with NodePort

Deploy k8s INGRESS with NodePort

There are 3 main service types in a kubernetes deployment- ClusterIP NodePort LoadBalancer. To expose services in production, using ClusterIP and NodePort is not a good practice. LoadBalancer can be used in this case. But using LoadBalancer service type in bare metal is problematic. We will explore around such a case in this blog post.

Preperation

In the first place, we will deploy a Nginx image in service type ClusterIP. This is a basic nginx welcome page.

# nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx

So, let's apply it-

kubectl apply -f nginx.yml

So it launches 2 pods and a service of type ClusterIP. We can check it using-

$ kubectl get services

NAME            TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
nginx-svc       ClusterIP   10.18.0.242   <none>        80/TCP         2d11h

We can check the content served using cluster ip:

$ curl -D- 10.18.0.242

HTTP/1.1 200 OK
Server: nginx/1.14.2

Nginx Ingresss

Installation & Setup Ingress Controller

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml

This will create a new namespace ingress-nginx. It will create 3 pods and 2 services. If we check the service now-

$ kubectl get service -n ingress-nginx
NAME                                         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                         AGE
service/ingress-nginx-controller             NodePort    10.18.0.66    <pending>        80:30243/TCP,443:32414/TCP   18h

we will see the external IP is in <pending> state. This is due to our cloud provider doesn't provide load balancer. Now, we will change the service type of ingress-nginx-controller pod to NodePort-

$ kubectl edit svc -n ingress-nginx ingress-nginx-controller

Change the type and save. If we check service now, we will see the external ip is now in <none> stage from <pending>.

$ kubectl get service -n ingress-nginx
NAME                                         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                         AGE
service/ingress-nginx-controller             NodePort    10.18.0.66    <none>        80:30243/TCP,443:32414/TCP      18h

Our nginx controller configration is done. Now it's time to create the rules for ingress resource.

Ingress Resource

In our ingress resource, we will serve our nginx welcome page which we deployed earlier using our hostname, e.g. web.shafinhasnat.me, later we will make this public. Create the yml file below-

# ingress.yml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: web.shafinhasnat.me
    http:
      paths:      
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-svc
            port:
              number: 80

Apply using-

kubectl apply -f ingress.yml

It will create an ingress called minimal-ingress. We can check it using-

$ kubectl get ingress

NAME              CLASS    HOSTS                 ADDRESS      PORTS   AGE
minimal-ingress   <none>   web.shafinhasnat.me   10.18.0.66   80      10h

Now, if we resolve the dns to the address, we will be able to see the content served by nginx pod-

$ curl --resolve web.shafinhasnat.me:80:10.18.0.66 -D- http://web.shafinhasnat.me

HTTP/1.1 200 OK
...

This can be done by editing /etc/hosts-

#add this line

10.18.0.66 web.shafinhasnat.me

We can check directly using the domain-

$ curl -D- web.shafinhasnat.me

HTTP/1.1 200 OK
...

So everything is working from the host machine. Now we will make this accessible from the internet.

Expose on Internet

Now, what we have to do is, reverse proxy incoming traffic to the ingress ip and port. Basically we will expose the reverse proxy service in the internet. We will use nginx in this case. First we will create an .conf file-

# nginx.conf

server {
  listen 80;
  server_name _;
  location / {
    proxy_set_header Host            $host;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_pass http://11.0.0.21:30243;
  }
}

Now, we will create a docker-compose.yml-

version: '3.8'
services:
  nginx:
    image: nginx
    ports:
    - 80:80
    volumes:
    - ./nginx.conf:/etc/nginx/conf.d/default.conf

Now simply deploy with-

docker-compose up -d

Make sure, this vm has internet connectivity and port 80 allowed in firewall. Now, if we check resolving dns to the ip of the vm, we will see our nginx welcome page form our kubernetes cluster is up and running.

$ curl http://web.shafinhasnat.me/ --resolve web.shafinhasnat.me:80:<your_public_ip>

HTTP/1.1 200 OK
Server: nginx/1.23.1
...

To make it public, just simply add the public ip in the A records of your domain name provider manager dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment