Monday, April 20, 2020

Test drive Nginx ingress controller in Azure Kubernetes Service (AKS)

Architecture

Nginx ingress controller with Azure Kubernetes Service

Overview

This blog is part of a series that's inspired by one of my recent client engagements.  As I mentioned in my previous blog, Application gateway as ingress controller has direct access to all kubernetes pods and performs the layer 7 functions.  In contrast, in this next blog I cover the "in-cluster" ingress controller with nginx and AKS which performs the layer 7 functions. There is a great blog article here that explains the differences. In-cluster ingress controller creates the kubernetes services resource and the Azure Layer 4 load balancer as shown in the architecture.. In comparison to the Azure application gateway, the traffic flows an extra hop.

Test Drive 


Follow the link to test drive nginx ingress controller in Azure Kubernetes service.  Create your own sample deployments using the sample yaml manifests.
Fanout
http://akscolors.penguintrails.com  (default web site)
http://akscolors.penguintrails.com/cyan
http://akscolors.penguintrails.com/magenta
http://akscolors.penguintrails.com/yellow

Virtual Host
http://cyan.penguintrails.com
http://magenta.penguintrails.com
http://yellow.penguintrails.com
http://akscolors.eastus.cloudapp.azure.com   (default)

Github

Pre-requisites:

Working AKS cluster with nginx controller. Detailed documentation here

Link to my github repo:
https://github.com/nehalineogi/aks-nginx-ingress

Git clone my repository and off you go...
git clone https://github.com/nehalineogi/aks-nginx-ingress.git

# create ingress controller
#
# Create Namespace
kubectl create namespace ingress-ns

# Add the official stable repository
helm repo add stable https://kubernetes-charts.storage.googleapis.com/
#
# create ingress controlller
# Use Helm to deploy an NGINX ingress controller
#
helm install nginx-ingress stable/nginx-ingress \
    --namespace ingress-ns \
    --set controller.replicaCount=3 \
    --set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \
    --set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux

#
# Deployments
#
kubectl apply -f red-deployment.yaml
kubectl apply -f green-deployment.yaml
kubectl apply -f blue-deployment.yaml
kubectl apply -f white-deployment.yaml
#
# Ingress
#fanout
kubectl apply -f colors-fanout.yaml
#virtual host
kubectl apply -f colors-virtual-host.yaml

# Cleanup:
kubectl delete namespace ingress-ns
kubectl delete clusterrole nginx-ingress
kubectl delete clusterrolebinding nginx-ingress

Concepts - Ingress Deployments

Some ingress concepts here
Simple fanout

A fanout configuration routes traffic from a single IP address to more than one Service, based on the HTTP URI being requested. An Ingress allows you to keep the number of load balancers down to a minimum. For example, a setup like:

foo.bar.com -> 178.91.123.132 -> / foo    service1:4200
                                                       / bar    service2:8080
Name based virtual hosting

Name-based virtual hosts support routing HTTP traffic to multiple host names at the same IP address.

foo.bar.com --|                             |-> foo.bar.com service1:80
                       | 178.91.123.132  |
bar.foo.com --|                             |-> bar.foo.com service2:80

AKS Side

kubectl get nodes -o wide
NAME                                STATUS   ROLES   AGE   VERSION    INTERNAL-IP     EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
aks-nodepool1-96863235-vmss000000   Ready    agent   21d   v1.15.10   172.16.240.4    <none>        Ubuntu 16.04.6 LTS   4.15.0-1077-azure   docker://3.0.10+azure
aks-nodepool1-96863235-vmss000001   Ready    agent   21d   v1.15.10   172.16.240.15   <none>        Ubuntu 16.04.6 LTS   4.15.0-1071-azure   docker://3.0.10+azure
aks-nodepool1-96863235-vmss000002   Ready    agent   21d   v1.15.10   172.16.240.26   <none>        Ubuntu 16.04.6 LTS   4.15.0-1071-azure   docker://3.0.10+azure

kubectl get deploy,pods,services,ingress -o wide -n ingress-ns
NAME                                                  READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS                      IMAGES                                                                  SELECTOR
deployment.extensions/nginx-ingress-controller        3/3     3            3           4m52s   nginx-ingress-controller        quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0   app=nginx-ingress,release=nginx-ingress
deployment.extensions/nginx-ingress-default-backend   1/1     1            1           4m52s   nginx-ingress-default-backend   k8s.gcr.io/defaultbackend-amd64:1.5                                     app=nginx-ingress,release=nginx-ingress

NAME                                                 READY   STATUS    RESTARTS   AGE     IP              NODE                                NOMINATED NODE   READINESS GATES
pod/nginx-ingress-controller-f559556f9-cbmzq         1/1     Running   0          4m52s   172.16.240.14   aks-nodepool1-96863235-vmss000000   <none>           <none>
pod/nginx-ingress-controller-f559556f9-lhbfz         1/1     Running   0          4m52s   172.16.240.23   aks-nodepool1-96863235-vmss000001   <none>           <none>
pod/nginx-ingress-controller-f559556f9-tqgkl         1/1     Running   0          4m52s   172.16.240.29   aks-nodepool1-96863235-vmss000002   <none>           <none>
pod/nginx-ingress-default-backend-76b8f499cb-sw8pv   1/1     Running   0          4m52s   172.16.240.10   aks-nodepool1-96863235-vmss000000   <none>           <none>

NAME                                    TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                      AGE     SELECTOR
service/nginx-ingress-controller        LoadBalancer   10.20.8.97      52.170.163.131   80:31982/TCP,443:30146/TCP   4m52s   app.kubernetes.io/component=controller,app=nginx-ingress,release=nginx-ingress
service/nginx-ingress-default-backend   ClusterIP      10.20.137.158   <none>           80/TCP                       4m52s   app.kubernetes.io/component=default-backend,app=nginx-ingress,release=nginx-ingress

kubectl describe service nginx-ingress-controller -n ingress-ns
Name:                     nginx-ingress-controller
Namespace:                ingress-ns
Labels:                   app=nginx-ingress
                          chart=nginx-ingress-1.36.2
                          component=controller
                          heritage=Helm
                          release=nginx-ingress
Annotations:              <none>
Selector:                 app.kubernetes.io/component=controller,app=nginx-ingress,release=nginx-ingress
Type:                     LoadBalancer
IP:                       10.20.8.97
LoadBalancer Ingress:     52.170.163.131
Port:                     http  80/TCP
TargetPort:               http/TCP
NodePort:                 http  31982/TCP
Endpoints:                172.16.240.14:80,172.16.240.23:80,172.16.240.29:80
Port:                     https  443/TCP
TargetPort:               https/TCP
NodePort:                 https  30146/TCP
Endpoints:                172.16.240.14:443,172.16.240.23:443,172.16.240.29:443
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason                Age    From                Message
  ----    ------                ----   ----                -------
  Normal  EnsuringLoadBalancer  7m     service-controller  Ensuring load balancer
  Normal  EnsuredLoadBalancer   6m37s  service-controller  Ensured load balancer


kubectl describe service nginx-ingress-default-backend -n ingress-ns
Name:              nginx-ingress-default-backend
Namespace:         ingress-ns
Labels:            app=nginx-ingress
                   chart=nginx-ingress-1.36.2
                   component=default-backend
                   heritage=Helm
                   release=nginx-ingress
Annotations:       <none>
Selector:          app.kubernetes.io/component=default-backend,app=nginx-ingress,release=nginx-ingress
Type:              ClusterIP
IP:                10.20.137.158
Port:              http  80/TCP
TargetPort:        http/TCP
Endpoints:         172.16.240.10:8080
Session Affinity:  None
Events:            <none>


Azure Side (Load Balancer)

backend Pool with VMSS Nodes

Load Balancer Public IPs

Node Port for the Exposed nginx controller service

Rule showing the HTTP heath probe on the NodePort

LB Rules for tcp/80 




Deployments:


kubectl get deploy,pods,services,ingress -o wide -n colors-ns
NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS    IMAGES                SELECTOR
deployment.extensions/cyan-deployment      2/2     2            2           57s   cyan-app      hashicorp/http-echo   app=cyan
deployment.extensions/magenta-deployment   2/2     2            2           53s   magenta-app   hashicorp/http-echo   app=magenta
deployment.extensions/yellow-deployment    2/2     2            2           49s   yellow-app    hashicorp/http-echo   app=yellow

NAME                                      READY   STATUS    RESTARTS   AGE   IP              NODE                                NOMINATED NODE   READINESS GATES
pod/cyan-deployment-85c5fd4b7-49n25       1/1     Running   0          56s   172.16.240.13   aks-nodepool1-96863235-vmss000000   <none>           <none>
pod/cyan-deployment-85c5fd4b7-s2gx4       1/1     Running   0          56s   172.16.240.30   aks-nodepool1-96863235-vmss000002   <none>           <none>
pod/magenta-deployment-64fcd58c6f-9m4n8   1/1     Running   0          52s   172.16.240.32   aks-nodepool1-96863235-vmss000002   <none>           <none>
pod/magenta-deployment-64fcd58c6f-ljc2n   1/1     Running   0          52s   172.16.240.5    aks-nodepool1-96863235-vmss000000   <none>           <none>
pod/yellow-deployment-5ff564c666-8s9b6    1/1     Running   0          49s   172.16.240.12   aks-nodepool1-96863235-vmss000000   <none>           <none>
pod/yellow-deployment-5ff564c666-mswkf    1/1     Running   0          49s   172.16.240.6    aks-nodepool1-96863235-vmss000000   <none>           <none>

NAME                      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   SELECTOR
service/cyan-service      ClusterIP   10.20.140.182   <none>        8080/TCP   56s   app=cyan
service/magenta-service   ClusterIP   10.20.101.186   <none>        8080/TCP   52s   app=magenta
service/yellow-service    ClusterIP   10.20.46.169    <none>        8080/TCP   49s   app=yellow

Validations:


I've created a busybox container to run all the tests.  Let's validate connectivity to red pods and cluster serivce.

kubectl exec -it pingtest-b4b6f8cf-5xk7v sh

/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 16:2A:D2:E5:D0:13
          inet addr:172.16.240.20  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST RUNNING  MTU:1500  Metric:1
          RX packets:2273586 errors:0 dropped:0 overruns:0 frame:0
          TX packets:105 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:95504870 (91.0 MiB)  TX bytes:7271 (7.1 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # wget -qO- 172.16.240.13
wget: can't connect to remote host (172.16.240.13): Connection refused
/ # wget -qO- 172.16.240.13:8080
cyan
/ # wget -qO- 172.16.240.30:8080
cyan
/ # wget -qO- 10.20.140.182:8080
cyan

Ingress:

Fanout:
 kubectl apply -f colors-fanout.yaml
kubectl describe ingress colors-fanout-ingress -n colors-ns
Name:             colors-fanout-ingress
Namespace:        colors-ns
Address:          172.16.240.15,172.16.240.26,172.16.240.4
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host                         Path  Backends
  ----                         ----  --------
  akscolors.penguintrails.com
                               /cyan      cyan-service:8080 (172.16.240.13:8080,172.16.240.30:8080)
                               /magenta   magenta-service:8080 (172.16.240.32:8080,172.16.240.5:8080)
                               /yellow    yellow-service:8080 (172.16.240.12:8080,172.16.240.6:8080)
                                          cyan-service:8080 (172.16.240.13:8080,172.16.240.30:8080)
Annotations:
  kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"colors-fanout-ingress","namespace":"colors-ns"},"spec":{"rules":[{"host":"akscolors.penguintrails.com","http":{"paths":[{"backend":{"serviceName":"cyan-service","servicePort":8080},"path":"/cyan"},{"backend":{"serviceName":"magenta-service","servicePort":8080},"path":"/magenta"},{"backend":{"serviceName":"yellow-service","servicePort":8080},"path":"/yellow"},{"backend":{"serviceName":"cyan-service","servicePort":8080},"path":null}]}}]}}

Validations:

kubectl exec -it pingtest-b4b6f8cf-5xk7v sh
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 16:2A:D2:E5:D0:13
          inet addr:172.16.240.20  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST RUNNING  MTU:1500  Metric:1
          RX packets:2275879 errors:0 dropped:0 overruns:0 frame:0
          TX packets:191 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:95605042 (91.1 MiB)  TX bytes:13569 (13.2 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # wget -qO-  --header="Host:akscolors.penguintrails.com" http://10.20.8.97/cyan
cyan
/ # wget -qO-  --header="Host:akscolors.penguintrails.com" http://10.20.8.97/magenta
magenta
/ # wget -qO-  --header="Host:akscolors.penguintrails.com" http://10.20.8.97/yellow
yellow
/ # wget -qO-  --header="Host:akscolors.penguintrails.com" http://10.20.8.97/
cyan
/ #

Virtual Host

kubectl apply -f colors-virtual-host.yaml
ingress.extensions/colors-virtual-host-ingress created
 kubectl get ingress -o wide -n colors-ns
NAME                          HOSTS                                                                                   ADDRESS                                    PORTS   AGE
colors-fanout-ingress         akscolors.penguintrails.com                                                             172.16.240.15,172.16.240.26,172.16.240.4   80      19m
colors-virtual-host-ingress   cyan.penguintrails.com,magenta.penguintrails.com,yellow.penguintrails.com + 1 more...   172.16.240.15,172.16.240.26,172.16.240.4   80      74s


 kubectl describe ingress colors-virtual-host-ingress -n colors-ns
Name:             colors-virtual-host-ingress
Namespace:        colors-ns
Address:          172.16.240.15,172.16.240.26,172.16.240.4
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host                       Path  Backends
  ----                       ----  --------
  cyan.penguintrails.com
                                cyan-service:8080 (172.16.240.13:8080,172.16.240.30:8080)
  magenta.penguintrails.com
                                magenta-service:8080 (172.16.240.32:8080,172.16.240.5:8080)
  yellow.penguintrails.com
                                yellow-service:8080 (172.16.240.12:8080,172.16.240.6:8080)
  *
                                cyan-service:8080 (172.16.240.13:8080,172.16.240.30:8080)
Annotations:
  kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"colors-virtual-host-ingress","namespace":"colors-ns"},"spec":{"rules":[{"host":"cyan.penguintrails.com","http":{"paths":[{"backend":{"serviceName":"cyan-service","servicePort":8080}}]}},{"host":"magenta.penguintrails.com","http":{"paths":[{"backend":{"serviceName":"magenta-service","servicePort":8080}}]}},{"host":"yellow.penguintrails.com","http":{"paths":[{"backend":{"serviceName":"yellow-service","servicePort":8080}}]}},{"http":{"paths":[{"backend":{"serviceName":"cyan-service","servicePort":8080}}]}}]}}

  kubernetes.io/ingress.class:  nginx
Events:

Validations:
kubectl exec -it pingtest-b4b6f8cf-5xk7v sh

/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 16:2A:D2:E5:D0:13
          inet addr:172.16.240.20  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST RUNNING  MTU:1500  Metric:1
          RX packets:2278466 errors:0 dropped:0 overruns:0 frame:0
          TX packets:233 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:95716051 (91.2 MiB)  TX bytes:16907 (16.5 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # wget -qO-  --header="Host:cyan.penguintrails.com" http://10.20.8.97
cyan
/ # wget -qO-  --header="Host:magenta.penguintrails.com" http://10.20.8.97
magenta
/ # wget -qO-  --header="Host:yellow.penguintrails.com" http://10.20.8.97
yellow
/ # wget -qO-  http://10.20.8.97
cyan
/ #

Outbound from the PODS:

There is an outbound rule that gets created so all egress traffic from the pods get's SNAT'd to the load balancer Public IP address


 kubectl exec -it pingtest-b4b6f8cf-5xk7v sh
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 16:2A:D2:E5:D0:13
          inet addr:172.16.240.20  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST RUNNING  MTU:1500  Metric:1
          RX packets:2217728 errors:0 dropped:0 overruns:0 frame:0
          TX packets:36 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:93146060 (88.8 MiB)  TX bytes:2347 (2.2 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # wget -qO- icanhazip.com
52.152.246.245

1 comment:

erectile dysfunction medications said...

Hello friends, how is the whole thing, and what you would like to say regarding this piece of writing, in my view its actually awesome for me.