
September 09, 2026
10 min read
By Kokil Thapa | Last reviewed: September 2026
Kubernetes Ingress Controllers Explained starts with a gap most teams hit after their first deploy: Pods are reachable inside the cluster, but nobody on the internet can hit your app by hostname. A Service of type LoadBalancer gives you one IP per app. That gets expensive fast. An Ingress sits on top of your cluster networking layer and maps hostnames and URL paths to backend Services. The controller is the process that watches those rules and programs a real reverse proxy. This guide walks through how that works, which controller to pick, and what breaks in production.
What is a Kubernetes ingress controller and how does it work?
An Ingress resource in Kubernetes is declarative routing configuration. It does nothing by itself. The ingress controller is a Pod (often a Deployment) that watches Ingress objects across the cluster. When rules change, the controller updates its proxy config and reloads.
Think of it as two layers. The API layer stores intent. The controller layer enforces it on the data plane.
The control loop in plain terms
Every ingress controller runs the same basic loop:
- Watch Ingress, Service, EndpointSlice, and sometimes Secret objects via the Kubernetes API.
- Build an internal model of which hostname and path map to which backend port.
- Render that model into proxy configuration (NGINX conf, Envoy xDS, Traefik dynamic config).
- Apply the config and signal a graceful reload so existing connections stay alive.
If the controller Pod dies, another replica takes over. Existing connections may drop briefly unless you run multiple replicas behind an external load balancer. That HA pattern matters for production clusters serving real traffic.
The official Kubernetes documentation describes Ingress as an API specification, not a built-in implementation. You must install a controller separately. Managed clusters often ship one (AWS Load Balancer Controller on EKS, GCE Ingress on GKE). Self-managed clusters on Ubuntu with Linux system administration duties fall on your team to pick and maintain one.
How does an ingress controller differ from a Kubernetes Service?
Services provide stable cluster-internal networking. An Ingress adds L7 routing on top. They solve different problems and are usually used together.
| Feature | Service (ClusterIP / NodePort / LB) | Ingress + Controller |
|---|---|---|
| OSI layer | L4 (TCP/UDP ports) | L7 (HTTP host, path, headers) |
| Routing | One Service = one port mapping | Many hostnames/paths → many Services |
| TLS termination | Not built in (passthrough only on some LBs) | Native HTTPS with cert references |
| Cost on cloud | LoadBalancer Service = one cloud LB each | One LB fronting one controller for many apps |
| Typical use | Internal microservice mesh, DB proxies | Public web apps, APIs, admin panels |
A common pattern on a production Laravel API I have worked on: three Deployments, three ClusterIP Services, one Ingress with three path rules. One external IP handles api.example.com/v1, api.example.com/admin, and docs.example.com. Without Ingress you would pay for three cloud load balancers at roughly Rs 3,000–5,000/month each (~USD 22–37).
NodePort exposes a port on every worker. That works for lab setups with Minikube or kind. It is a poor public entry point. You still need something to distribute traffic and terminate TLS.
Which Kubernetes ingress controller should you choose in 2026?
No single controller wins every scenario. Pick based on cloud provider, team skills, and whether you need advanced traffic management.
Popular controllers compared
| Controller | Best fit | Trade-offs |
|---|---|---|
| ingress-nginx | General-purpose HTTP, largest community, works everywhere | Config via annotations can sprawl; reload-based, not hot xDS |
| Traefik | k3s default, auto Let's Encrypt, good for small teams | Complex routing rules harder to debug at scale |
| HAProxy Ingress | High throughput, low latency, familiar HAProxy ops | Smaller ecosystem than NGINX for K8s-specific docs |
| AWS LB Controller | EKS with ALB/NLB integration, target-type IP | AWS-only; IngressClass semantics differ from NGINX |
| Cilium Ingress | Clusters already on Cilium eBPF networking | Younger feature set vs mature NGINX annotations |
| Gateway API | New projects wanting typed, extensible L4/L7 routes | Migration path from classic Ingress still evolving |
Gateway API is the long-term direction Kubernetes SIG Network is pushing. It splits concerns into GatewayClass, Gateway, and HTTPRoute resources. Many teams still run classic Ingress in 2026 because every controller supports it and the YAML is well understood.
For a booking platform like Adventure Third Pole Trek, I would default to ingress-nginx on a VPS cluster with MetalLB unless the client is already on EKS. It is boring, documented, and easy to hand off.
How do you install and configure an NGINX Ingress Controller?
The community-maintained ingress-nginx project is the most copied install path. Below is a minimal production-oriented setup on a generic cluster.
Step 1: Install the controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml
Verify the controller Pod is running and the Service has an external address:
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx ingress-nginx-controller
On bare metal without a cloud LB, pair this with MetalLB in L2 mode so the controller Service gets a routable IP on your LAN or public subnet.
Step 2: Define an IngressClass
IngressClass tells the cluster which controller should reconcile a given Ingress. Modern manifests include one by default named nginx.
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
spec:
controller: k8s.io/ingress-nginx
Step 3: Create a sample Ingress
This routes shop.example.com to a Service named web on port 80:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop-ingress
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "20m"
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
Validate YAML structure with a JSON or YAML formatter before applying. A single indentation error sends you hunting through controller logs.
Step 4: Add TLS with cert-manager
HTTPS belongs at the Ingress layer for most web apps. Install cert-manager, create a ClusterIssuer for Let's Encrypt, then reference a TLS Secret in the Ingress. Full walkthrough is in the companion post on Kubernetes Ingress and TLS with cert-manager.
spec:
tls:
- hosts:
- shop.example.com
secretName: shop-example-com-tls
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
Point your DNS A record at the controller's external IP. Wait for the ACME HTTP-01 or DNS-01 challenge to complete. Test with curl -I https://shop.example.com before announcing go-live.
Annotations that matter in production
nginx.ingress.kubernetes.io/proxy-body-size— raise for file uploads on legal-tech portals with document uploads.nginx.ingress.kubernetes.io/rate-limit— basic abuse protection on public forms.nginx.ingress.kubernetes.io/ssl-redirect— force HTTPS when TLS is configured.nginx.ingress.kubernetes.io/whitelist-source-range— lock admin paths to office IPs.
Store sensitive values in Kubernetes Secrets done right, not in annotation plaintext. For a Laravel app on Kubernetes, set APP_URL to the public HTTPS hostname the Ingress exposes.
What are common mistakes when running ingress controllers in production?
Most ingress outages I have seen are configuration or capacity issues, not Kubernetes bugs. The controller is a single choke point. Treat it accordingly.
Wrong or missing IngressClass
If no controller claims your Ingress, it sits in limbo. No address, no routing. Always set spec.ingressClassName explicitly. Multiple controllers in one cluster require distinct IngressClass names.
Service port mismatches
The Ingress backend port is the Service port number, not the container port. A Service exposing port 80 that targets containerPort 8080 is valid. Pointing the Ingress at 8080 when the Service only exposes 80 yields 502 Bad Gateway. Check with kubectl describe ingress and kubectl get endpoints.
Undersized controller pods
TLS termination and gzip eat CPU. Set resource requests and limits on the controller Deployment. Run at least two replicas. Use horizontal pod autoscaling if traffic spikes during campaigns.
Ignoring network policy
Lock down the ingress namespace so only the controller can reach app Pods on their Service ports. Broader policies are covered in Kubernetes network policies explained.
Skipping backup of routing config
Ingress objects live in etcd. A bad kubectl delete --all ingress hurts. GitOps with Argo CD or plain Git-backed manifests plus Velero backup gives you a restore path.
For teams building REST APIs in Nepal or globally, the ingress layer is also where you attach CORS headers, request size limits, and optional WAF rules before traffic hits PHP-FPM or Node workers.
Key Takeaways
- An Ingress is a routing rule; the ingress controller is the daemon that enforces it on a reverse proxy.
- Use ClusterIP Services for backends and a single Ingress controller to multiplex many hostnames through one load balancer.
- ingress-nginx remains the default choice for self-managed clusters; use vendor controllers on EKS, GKE, and AKS.
- Always set
ingressClassName, match Service ports correctly, and run at least two controller replicas with resource limits. - Automate TLS with cert-manager and store certificates in Secrets referenced by the Ingress spec.
- Monitor 5xx rates at the proxy, back up Ingress manifests, and restrict traffic with NetworkPolicy.
People Also Ask
Do I need an ingress controller if I use a cloud LoadBalancer Service?
Not strictly, but you will spend more and lose L7 features. A LoadBalancer per Service works for one or two apps. Beyond that, an ingress controller saves cost and centralises hostname routing, TLS, and redirects.
What is the difference between Ingress and Gateway API?
Ingress is a single resource with annotations for extensions. Gateway API splits routing into GatewayClass, Gateway, and route types with clearer role separation. Both need a controller. Ingress is still the practical default in 2026; Gateway API is the forward path.
Can one ingress controller handle gRPC and WebSockets?
Yes. NGINX and Traefik support WebSocket upgrade headers and gRPC over HTTP/2. You may need specific annotations for long-lived connections and timeout values higher than the defaults.
How do I debug a 502 Bad Gateway from my ingress controller?
Check Endpoints first: empty endpoints mean no healthy Pods. Then verify Service port vs containerPort. Finally read controller logs with kubectl logs -n ingress-nginx deploy/ingress-nginx-controller. Most 502s are backend connectivity, not Ingress syntax.
Put ingress routing on solid ground
Kubernetes Ingress Controllers Explained boils down to one idea: separate routing intent from the proxy that executes it. Pick a controller that matches your infrastructure, front it with automated TLS, and treat the controller Deployment as production-critical infrastructure. If you are moving a Laravel or eCommerce workload onto Kubernetes and want the ingress, TLS, and ongoing maintenance handled end to end, get in touch via the contact page. For related reading, see debugging CrashLoopBackOff, enterprise application development, and Quick And Easy Nepalese Grocery for a Laravel eCommerce reference deployment.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

