In this comprehensive ingress guide, you will learn how to setup Nginx ingress controller on Kubernetes and configure ingress using DNS.
If you want to understand how Kubernetes ingress works, read my Kubernetes Ingress Tutorial. for beginners. I have explained all the core ingress concepts including how an ingress object works with an ingress controller.
There are two Nginx ingress controllers.
We will be using the Kubernetes community Nginx controller.
Note: Today, you can get 25% discount on Kubernetes CKA, CKAD, CKS, KCNA certifications using code DCUBE20 at kube.promo/latest
Ingress & Nginx Ingress Controller Architecture
Here is a high-level architecture of Kubernetes ingress using the Nginx ingress controller. In this guide, we will learn to build the setup in the architecture.
(Note: Click the image to view in high resolution)
Prerequisites
- A Kubernetes cluster
- kubectl utility installed and authenticated to kubernetes cluster.
- Admin access to kubernetes cluster.
- A valid domain to point to ingress controller Load Balancer IP. (Optional)
If you are trying this setup on Google Cloud, assign admin permissions to your account to enable cluster roles.
ACCOUNT=$(gcloud info --format='value(config.account)')
kubectl create clusterrolebinding owner-cluster-admin-binding \
--clusterrole cluster-admin \
--user $ACCOUNT
Nginx Ingress Controller Kubernetes Manifests
All the kubernetes manifests used in this tutorial are hosted on the Github repository.
Clone it and you can deploy the YAML files directly as you follow along the guide. These manifests are taken from the official Nginx community repo.
git clone https://github.com/techiescamp/nginx-ingress-controller
First, we will understand all the associated Kubernetes objects by deploying Nginx controllers using YAML manifests. Once we have the understanding, we will deploy it using the Helm chart.
Note: If you want to understand all the Nginx ingress controllers objects and how they relate to each other, I suggest you create objects individually from the repo. Once you know how it works, you can use a single manifest or a helm chart to deploy it.
If you want to deploy all the objects on one go, open the cloned repo in termal.
cd in in to the manifest folder and execute the following command. It will deploy all the manifests explained in this blog.
kubectl apply -f .
Deploy Nginx Ingress Controller With Manifests
We need to deploy the following Kubernetes objects to have a working Nginx controller.
ingress-nginx
namespace- Service account/Roles/ClusterRoles for Nginx admission controller
- Validating webhook Configuration
- Jobs to create/update Webhook CA bundles
- Service account/Roles/ClusterRoles of Nginx controller deployment
- Nginx controller configmap
- Services for nginx controller & admission controller
- Ingress controller deployment
Note: You can create all the manifests yourself or use the Github repo. However, I highly suggest you go through every manifest and understand what you are deploying.
Need for Admission Controller & Validating Webhook
Kubernetes Admission Controller is a small piece of code to validate or update Kubernetes objects before creating them. In this case, it’s an admission controller to validate the ingress objects. The Admission Controller code is part of the Nginx controller that listens on the port 8443
.
Why do need the admission controller for ingress?
Without an admission controller, you can deploy ingress object that might contain wrong configurations. A wrong configuration can break all the ingress rules associated with the ingress controller.
With the admission controller in place, if you deploy a ingress object with wrong configurations, it will throw an error. This way you can ensure that the ingress object you create has the correct configurations and doesn’t break routing rules.
Here is how admission controllers work for Nginx.
- When you deploy an ingress YAML, the Validation admission intercepts the request.
- Kubernetes API then sends the ingress object to the validation admission controller service endpoint based on admission webhook endpoints.
- Service sends the request to the Nginx deployment on port 8443 for validating the ingress object.
- The admission controller then sends a response to the k8s API.
- If it is a valid response, the API will create the ingress object.
Now let’s get started by creating Kubernetes objects for the ingress controller.
Note: In the following sections you dont necessarily have to copy and create the YAML files. You can use the files from the repository directly and deploy it. I have given the full YAMLs here for reference.
Create a Namespace
We will deploy all the Nginx controller objects in the ingress-nginx
namespace.
Let’s create the namespace.
kubectl create ns ingress-nginx
Create Admission Controller Roles & Service Account
We need a Role and ClusterRole with required permissions and bind to ingress-nginx-admission
service account.
Create a file named admission-service-account.yaml
and copy the following contents.
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
annotations:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
Deploy the manifest.
kubectl apply -f admission-service-account.yaml
Create Validating Webhook Configuration
Create a file named validating-webhook.yaml
and copy the following contents.
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: ingress-nginx-controller-admission
namespace: ingress-nginx
path: /networking/v1/ingresses
failurePolicy: Fail
matchPolicy: Equivalent
name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
sideEffects: None
Create the ValidatingWebhookConfiguration
kubectl apply -f validating-webhook.yaml
Deploy Jobs To Update Webhook Certificates
The ValidatingWebhookConfiguration
works only over HTTPS. So it needs a CA bundle.
We use kube-webhook-certgen to generate a CA cert bundle with the first job. The generated CA certs are stored in a secret named ingress-nginx-admission
The second job patches the ValidatingWebhookConfiguration
object with the CA bundle.
Create a file named jobs.yaml
and copy the following contents.
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-create
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-create
spec:
containers:
- args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0
imagePullPolicy: IfNotPresent
name: create
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-patch
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-patch
spec:
containers:
- args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0
imagePullPolicy: IfNotPresent
name: patch
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
Create the jobs
kubectl apply -f jobs.yaml
Verify the job completion using the following command.
kubectl get jobs -n ingress-nginx
Once the jobs are executed, you can describe the ValidatingWebhookConfigurationand
, you will see the patched bundle.
kubectl describe ValidatingWebhookConfiguration ingress-nginx-admission
Create Ingress Controller Roles & Service Account
Create a file named ingress-service-account.yaml
and copy the following contents.
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resourceNames:
- ingress-controller-leader
resources:
- configmaps
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
Deploy the manifest.
kubectl apply -f ingress-service-account.yaml
Create Configmap
With this configmap, you can customize the Nginx settings. For example, you can set custom headers and most of the Nginx settings.
Please refer to the official community documentation for all the supported configurations.
Create a file named configmap.yaml
and copy the following contents.
---
apiVersion: v1
data:
allow-snippet-annotations: "true"
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller
namespace: ingress-nginx
Create the configmap.
kubectl apply -f configmap.yaml
Create Ingress Controller & Admission Controller Services
Create a file named services.yaml
and copy the following contents.
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
externalTrafficPolicy: Local
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: LoadBalancer
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller-admission
namespace: ingress-nginx
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
Create the services.
kubectl apply -f services.yaml
ingress-nginx-controller
service creates a Loadbalancer in the respective cloud platform you are deploying.
You can get the load balancer IP/DNS using the following command.
kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller
Note: For each cloud provider there are specific annotations you can use to map static IP address and other configs to the Loadbalancer. Check out GCP annotations here and AWS annoatations here.
Create IngressClass
Create a file named ingressclass.yaml
and copy the following contents.
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: nginx
spec:
controller: k8s.io/ingress-nginx
Deploy the ingress class.
kubectl apply -f ingressclass.yaml
It will create a ingress class named nginx. We have to use this ingress class name in Ingress objects we create.
Create Ingress Controller Deployment
Create a file named deployment.yaml
and copy the following contents.
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
spec:
containers:
- args:
- /nginx-ingress-controller
- --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: registry.k8s.io/ingress-nginx/controller:v1.9.5
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 90Mi
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
runAsUser: 101
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
Create the deployment.
kubectl apply -f deployment.yaml
To ensure that deployment is working, check the pod status.
kubectl get pods -n ingress-nginx
Validate Ingress Controller Deployment
You can validate the ingress controller deployment using the LoadBlancer endpoint created by the service.
Nginx Ingress controller has a default backend. All the requests that doesn’t have a entry in the ingress goes to this default backend.
We will validate out controller using the default backend.
Get your Loadbalancer endpoint the try to acess it. You should get a 404 error as shown below.
Now try to access the /heathz url using curl as given below. You should get a 200 response. Replace <LOAD-BALANCER-ENDPOINT> with your Loadbalancer endpoint.
curl http://<LOAD-BALANCER-ENDPOINT>/healthz
Nginx Ingress Controller Helm Deployment
If you are a Helm user, you can deploy the ingress controller using the community helm chart. ValidatingWebhookConfiguration
is disabled by default in values.yaml
.
Deploy the helm chart. It will create the namespace ingress-nginx
if not present.
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
Verify the helm release.
helm list -n ingress-nginx
To clean up the resources, uninstall the release.
helm uninstall ingress-nginx -n ingress-nginx
Map a Domain Name To Nginx Ingress Loadbalancer IP
The primary goal of Ingress is to receive external traffic to services running on Kubernetes. Ideally in projects, a DNS would be mapped to the ingress controller Loadbalancer IP.
This can be done via the respective DNS provider with the domain name you own.
Info: For internet-facing apps, it will be public DNS pointing to the public IP of the load balancer. If it’s an internal app, it will be an organization’s private DNS mapped to a private load balancer IP.
Single DNS Mapping
You can map a single domain directly as an A record to the load balancer IP. Using this you can have only one domain for the ingress controller and multiple path-based traffic routing.
For example,
www.example.com --> Loadbalancer IP
You can also have path-based routing using this model.
Few examples,
http://www.example.com/app1
http://www.example.com/app2
http://www.example.com/app1/api
http://www.example.com/app2/api
Wildcard DNS Mapping
If you map a wildcard DNS to the load balancer, you can have dynamic DNS endpoints through ingress.
Once you add the wildcard entry in the DNS records, you need to mention the required DNS in the ingress object and the Nginx ingress controller will take care of routing it to the required service endpoint.
For example, check the following two mappings.
*.example.com --> Loadbalancer IP
*.apps.example.com --> Loadbalancer IP
This way you can have multiple dynamic subdomains through a single ingress controller and each DNS can have its own path-based routing.
Few examples,
#URL one
http://demo1.example.com/api
http://demo1.example.com/api/v1
http://demo1.example.com/api/v2
#app specific urls
http://grafana.apps.example.com
http://prometheus.apps.example.com
#URL two
http://demo2.apps.example.com/api
http://demo2.apps.example.com/api/v1
http://demo2.apps.example.com/api/v2
For demo purposes, I have mapped a wildcard DNS to the LoadBalancer IP. Based on your DNS provider, you can add the DNS record.
The following image shows the DNS records I used for this blog demo. I used EKS so instead of Loadnbalacer IP, I have a DNS of network load balancer endpoint which will be a CNAME. In the case of GKE, you will get an IP and in that case, you need to create an A record.
Deploy a Demo Application
For testing ingress, we will deploy a demo application and add a ClusterIp service to it. This application will be accessible only within the cluster without ingress.
Step 1: Create a namespace named dev
kubectl create namespace dev
Step 2: create a file named hello-app.yaml and copy the following contents.
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-app
namespace: dev
spec:
selector:
matchLabels:
app: hello
replicas: 2
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: "gcr.io/google-samples/hello-app:2.0"
Step 3: Create the deployment using kubectl
kubectl create -f hello-app.yaml
Check the deployment status.
kubectl get deployments -n dev
Step 5: Create a file named hello-app-service.yaml
and copy the following contents and save the file.
apiVersion: v1
kind: Service
metadata:
name: hello-service
namespace: dev
labels:
app: hello
spec:
type: ClusterIP
selector:
app: hello
ports:
- port: 80
targetPort: 8080
protocol: TCP
Step 6: Create the service using kubectl.
kubectl create -f hello-app-service.yaml
Create Ingress Object for Application
Now let’s create an ingress object to access our hello app using a DNS. An ingress object is nothing but a set of routing rules.
If you are wondering how the ingress object is connected to the Nginx controller, the ingress controller pod connects to the Ingress API to check for rules and it updates its nginx.conf
accordingly.
Since I have wildcard DNS mapped (*.apps.mlopshub.com
) with the DNS provider, I will use demo.apps.mlopshub.com
to point to the hello app service.
Step 1: Create a file named ingress.yaml
Step 2: Copy the following contents and save the file.
Replace demo.apps.mlopshub.com
with your domain name. Also, we are creating this ingress object in the dev
namespace becuase the hello app is running in the dev
namespace.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: dev
spec:
ingressClassName: nginx
rules:
- host: "demo.apps.mlopshub.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-service
port:
number: 80
Step 3: Describe created ingress object created to check the configurations.
kubectl describe ingress -n dev
Now if I try to access demo.apps.mlopshub.com
domain, I will be able to access the hello app as shown below. (You should replace it with your domain name)
You might face https error in the browser. in that case you can use a curl command to verify ingress endpoint.
curl demo.apps.mlopshub.com
TLS With Nginx Ingress
You can configure TLS certificates with each ingress object. The TLS gets terminated at the ingress controller level.
The following image shows the ingress TLS config. The TLS certificate needs to be added as a secret object.
I have written a detailed article on Ingress TLS configuration.
👉 Take a look at the guide to configure ingress TLS on Kubernetes.
Conclusion
In this article, we have learned how to set up the Nginx ingress controller.
It is very easy to get started. However, for project implementation ensure that you go through all Nginx configurations and tune them according to the requirements.
With the Nginx controller configmap, you can configure all the Nginx settings without redeploying the controller.
I hope you enjoyed this guide on Nginx ingress controller.
Let me know your thoughts and queries in the comment section.
Also, if you are learning Kubernetes, check out my comprehensive Kubernetes tutorials.
34 comments
Hi there,
Followed these instructions and the one application that I want to expose (argocd) is working. However… What do I do to get another application (in a different namespace) to run under the same nginx controller? I’ve tried a number of things, but I just can’t seem to find the right combination of yaml contents to get things working correctly 🙁
Hi!
Thanks for the great guide :).
One thing I wanted to point out: at the stage where the user needs to create the ingress controller service, the guide suddenly assumes access to a cloud provider – this is not mentioned in the requirements section at the beginning. I was trying to do this in a test environment on my local machine and this was a little disappointing unfortunately.
Is it possible two switch out NGINX to Traefik v3.0?
Maybe a new article with Traefik & Let’s Encrypt in Kubernetes EKS and AWS Route53?
Hi I followed the instructions but I am getting the following error:
Normal Scheduled default-scheduler Successfully assigned loki/ingress-nginx-controller-79c4cbcdcc-5867v to aks-agentpool-11527042-vmss000001
Warning FailedMount (x23 over ) kubelet MountVolume.SetUp failed for volume “webhook-cert” : secret “ingress-nginx-admission” not found
Warning FailedMount (x16 over ) kubelet Unable to attach or mount volumes: unmounted volumes=[webhook-cert], unattached volumes=[], failed to process volumes=[]: timed out waiting for t
When I ran the ingress.yaml. What have I missed? Thanks so much for your great article and help!
I see quite a bit of comments on failing with LB external IP in pending state. This is the result of use of the kubeadm built clusters that do not have LB functionality at all. The same thing happens in EKS Anywhere – no LB. I recently stumbled over kubeadm build addition that adds LB functionality – https://metallb.universe.tf. I managed to complete your setup with wild card DNS access to the hello-world app using that metallb. Thanks so much for a great article!
Peter – appreciate the pointer to MetalLB. Helped me get past that point on my on-prem VM-based installation.
Bibin – thanks for posting this detailed guide. It was very helpful in getting nginx setup on my new cluster. I’d suggest adding a pointer to MetalLB in the “Create Ingress Controller & Admission Controller Services” section. You already have a note there about annotations needed by GCP & AWS, so an additional mention of MetalLB would be helpful for those of us setting up on-prem clusters.
THANK YOU. Tried several other tutorials and finally something I was able to follow all the way through. Running this on localhost with rancher desktop to learn.
Great article Bibin! I followed all the steps mentioned. Only difference in my environment is I use microk8s installed in a Azure VM, and not anything like AKS (Azure Kubernetes Service).
That being the case, when I create the service in ingress-nginx namespace, external IPs are pending. I did some reading in SO, looks like in microk8s we will not an external IP. Can you guide as to how to handle this situation? Many thanks.
Hi Sam,
I am not aware of microK8s implementation. Will have to practically try it 🙂 You can try the microK8s community. Would like to know the solution if you find any.
I used the ingress addon available in microk8s. That solved the problem.
Jo again 🙂
I’m puzzled with “LoadBalancer IP” as it is requiring external one we didn’t define along the tuto. So I understand all DNS mapping but my service for loadbalancer is still waiting in “pending” state for External-ip
Any clarification here will be helpfull.
cheers
Hi Jo,
If the load balancer provisioning is pending state, you need to check the permissions. If the load balancer is provided, you can use the IP in DNS.
Ideally, when you deploy a service with type Loadbalancer, it will deploy a Loadbalancer in the respect cloud platform and its IP will be associated with the service.
Hello
Quite good but as many many tuto, Some missing steps (not the worst one btw).
In : Create Ingress Object for Application
after step 2, what we do with “ingress yaml” ?
Step 3 give “No resources found in dev namespace” so I tried:
#> kubectl create -f ingress.yaml
and got below error message
Error from server (InternalError): error when creating “ingress.yaml”: Internal error occurred: failed calling webhook “validate.nginx.ingress.kubernetes.io”: failed to call webhook: Post “https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networking/v1/ingresses?timeout=10s”: dial tcp 10.98.37.172:443: connect: connection refused
So at this stage, don’t know if it works as expected.
Any help possible ? Yes i’m newbie and still need some clarification at this stage of my learning path;
Hi Jo,
I need to re-run all the steps and will update the guide with more info. Thanks for bringing it up.
hi , is there any update ?
Hi, I got 404 from nginx.
I post detailed question about it at SO : https://stackoverflow.com/q/73045250/5901318
In the Ingress Object, this property:
ingressClassName: nginx
What is “ngnix” in reference to? What ties this Ingress Object to the Ingress Controller that is created?
Hi CKA,
ingressClassName: nginx
is the default ingress class Name. It ties the ingress controllers to the object.If don’t specify the class, the ingress object refers to the default ingress class, ie nginx.If you want to have multiple Nginx ingress controllers, you need to create a ingressclass object that has the same name as
--controller-class
parameters referenced in the controller deployment.I will add the section and object to the blog. Thanks for the comment.
Great!
Worke here!
minikube start
minikube v1.25.2 on Ubuntu 22.04
…
Preparing Kubernetes v1.23.3 on Docker 20.10.12 …
…
Done!
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/cloud/deploy.yaml
minikube addons enable ingress
Error:
Exiting due to MK_ADDON_ENABLE: run callbacks: running callbacks: [sudo KUBECONFIG=/var/lib/minikube/kubeconfig /var/lib/minikube/binaries/v1.23.3/kubectl apply -f /etc/kubernetes/addons/ingress-deploy.yaml: Process exited with status 1
p.s. AWS on EKS
Thanks for the article.
It is still unclear how ingress controller connected to application in dev namespace. When I’m trying to reproduce steps in article I get 404 from ingress load balancer.
HI Lans,
The controller can be in any namespace. But the ingress object we create should be in the same namespace where were have the application.
How are you trying to access the endpoint? do you have a DNS configured? If you can provide you setup details, i can help
Excellent article.. Tried it in Azure Kubernetes service and worked with no issues
404 when the I run the app!
@srih@sriharijoshi:disqus is it a 404 from Nginx or from app?
Its working thanks.
I have followed the same steps to configure the nginx ingress controller and service type loadbalancer, which created the ELB at aws. But when i try to access from ELB IP, i am getting ERR_EMPTY_RESPONSE on my browser. Please help.
How do I know which one is my domain ?
I deployed the image to aws ecr , and the cluster is also deployed at aws.
Some help would be highly appreciated since I’ve been stuck at that stage for a ridiculously long time
It looks like the path has changed to https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
Thanks Nazneen for the update..Added the correct path
path is not accessible ..mandatory.yaml is throwing 404
Looks like the URL has changed..Updated the latest URL.
Please try and let us know.
It is excellent article about ingress controll and ingress rule. Thanks once again
Glad it helped Jitendra 🙂