Nginx Ingress Controller-Part01
Tags: kubernetes, nginx, aws, helm
Published: 2024-05-25 18:37:46

one of opensource projects for Kubernetes ingress controllers, for ex: nginx-ingress-controller

What you are truly deploying for your services is ingress resources, but ingress Controller is required so that ingress resources come to life.
So please keep in mind that ingress-resource is different from ingress-controller

What is Ingress?
Ingress is an API object for routing and load balancing requests to a kubernetes service. Ingress can run on HTTP or HTTPS protocols and performs redirection by applying the rules we define as developers.

What is Ingress Controller?
Ingress Controller is a backend service developed with the Ingress API. It reads Ingress objects and takes actions to properly route incoming requests. Ingress Controllers can perform load balancing as well as forwarding operations. There are many Ingress Controllers in use
[ingress-controllers](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/?source=post_page-----7b448f6314f6--------------------------------)

- **Install Ingress Controller
firstly, you need to deploy nginx-controller by helm chart**
```
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm upgrade --install ingress-nginx ingress-nginx \ 
             --repo https://kubernetes.github.io/ingress-nginx \ 
             --namespace ingress-nginx \
             --create-namespace
             --set-string controller.service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-type"="nlb"
```

-- the default type of chart service type is LoadBalancer: https://github.com/kubernetes/ingress-nginx/blob/3b1908e20693c57a97b55d8a563da284a5dbf36c/charts/ingress-nginx/values.yaml#L482
![nginx-ingress-helm-chart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kzjvef3wvkduujlm7u53.png)

-- and to define that created LoadBalancer should be NLB, it is defined as annotation at nginx-ingress-controller service: 
```
controller:
  service:
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
```

For example, if we have public domain "tools.com"
-- to Set SSL/TLS termination on AWS load balancer:
simply this is a way of abstracting TLS handling is to terminate on load balancer and have HTTP inside the cluster by default.
by requesting a public certificate for your custom domain `"api.tools.com"` and wildcard custom domain `"*.api.tools.com"`, and don't forget to record the certificate CNAME under your public hosted zone to validate it.
then use the ACM certificate arn in controller service annotation and define the ssl port as "https"
and of course, don't forget to record all needed sub domains `"api.tools.com"` and `"*.api.tools.com"` to route to your NLP as record type A but the certificate is CNAME
Now you can set not only one ingress controller, but multiples and each ingress-controller has its own NLP and hostname for example
hostnameA: ui.api.tools.com -> to route to all ui websites
hostnameB: services.api.tools.com -> to route to restful apis services 
and how the ingress resource knows which ingress-nginx-controller ?
--- each one will have unique nginx-controller-class

Another important note that ingress-controller should have the minimum permissions to allow it to create loadbalancer on aws, and this should use an IRSA role and passed as annotation to serviceAccount inside the helm chart
```
controller:
  service:
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:eu-central-1:55xxxxxxx:certificate/5k0c5513-a947-6cc5-a506-b3yxxx
      service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
```

-- Choosing Publicly Accessible 
This will configure the AWS load balancer for public access
```
controller:
  service:
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
```

-- NLB with NGINX Ingress Controller maybe overwrite client IP, how to retain actual client IP:
you need to have proxy protocol enabled on your NLB and have the appropriate configuration in ingress-nginx.

```
controller:
  config:
    use-proxy-protocol: "true"
    real-ip-header: "proxy_protocol"
    use-forwarded-headers: "true"
```

--So Finally maybe all you needs 

```
controller:
  config:
    use-proxy-protocol: "true"
    real-ip-header: "proxy_protocol"
    use-forwarded-headers: "true"
  service:
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-type: nlb
      service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:eu-central-1:55xxxxxxx:certificate/5k0c5513-a947-6cc5-a506-b3yxxx
      service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https
      service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
      service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
```

-- what the chart deploys:
-<u>ingress-nginx</u> namespace
-<u>ingress-nginx-controller-7ed7998c-j2er5</u> pod
-<u>ingress-nginx-controller</u> service of type LoadBalancer
-<u>ingress-nginx-controller-admission</u> service of type ClusterIP (Validating admission controller which helps in preventing outages due to wrong ingress configuration)
-EXTERNAL-IP -> in turn points to AWS Load Balancer DNS Name which gets created when the Ingress Controller is installed cause of service of type LoadBalancer created by the chart

-- In details:
The controller deploys, configures, and manages Pods that contain instances of nginx, which is a popular open-source HTTP and reverse proxy server. These Pods are exposed via the controller’s Service resource, which receives all the traffic intended for the relevant applications represented by the Ingress and backend Services resources. The controller translates Ingress and Services’ configurations, in combination with additional parameters provided to it statically, into a standard nginx configuration. It then injects the configuration into the nginx Pods, which route the traffic to the application’s Pods.
The Ingress-Nginx Controller Service is exposed for external traffic via a load balancer. That same Service can be consumed internally via the usual <u>ingress-nginx-controller.ingress-nginx.svc.cluster.local</u> cluster DNS name.

![nginx-ingress-controller-graph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d21518csvea39w3ln8vi.png)

- **Create Deployment and Expose it as a service**

```
# create deployment
kubectl create deployment demo --image=nginx --port=80 
# expose deployment as a service
kubectl expose deployment demo
# Create Ingress resource to route request to demo service
kubectl create ingress demo --class=nginx \
  --rule your-public-domain/=demo:80
```

![nginx-demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/95mbxjbd1weg5vwt8bww.png)


Refereces:
- https://kubernetes.github.io/ingress-nginx/
- https://aws.amazon.com/blogs/containers/exposing-kubernetes-applications-part-3-nginx-ingress-controller/
- https://repost.aws/questions/QUw4SGJL79RO2SMT-LbpDRoQ/nlb-with-nginx-ingress-controller-is-overwriting-client-ip-how-to-retain-actual-client-ip
- https://dev.to/zenika/kubernetes-nginx-ingress-controller-10-complementary-configurations-for-web-applications-ken
- https://aws.amazon.com/blogs/opensource/network-load-balancer-nginx-ingress-controller-eks/