LFCE 142 ๐ง Kubernetes โ Ingress Controllers
An Ingress Controller is the running software that makes Ingress resources work. The Ingress resource is a rule set; the controller is the process that watches for those rules, translates them into the configuration of an actual proxy or load balancer, and routes the traffic. Without a controller, an Ingress manifest is accepted by the API server and does nothing. The Kubernetes documentation states this directly: “In order for an Ingress to work in your cluster, there must be an ingress controller running” .
This chapter covers the controller landscape: the controllers the Kubernetes project maintains, the third-party implementations that dominate production deployments, the IngressClass mechanism that selects which controller handles which Ingress, and the installation path for the two most common choices (NGINX and Traefik). It also covers the important context that the Ingress API is frozen and the project recommends Gateway API for new work.
Key point: The Kubernetes project has frozen the Ingress API and recommends Gateway API for new deployments. Ingress remains stable and will not be removed, but it will receive no further development. The controller you choose still matters, and the most widely deployed controller, ingress-nginx, reached end-of-life in March 2026 .
Why the controller choice matters
The API freeze problem. The Ingress API is generally available and subject to the stability guarantees of GA APIs, but it is no longer being developed. The Kubernetes documentation states: “The Ingress API is no longer being developed, and will have no further changes or updates made to it” . The project recommends Gateway API instead. A new deployment in 2026 should consider whether Ingress is the right choice or whether the Gateway API’s more expressive routing model is a better fit.
The implementation fragmentation problem. Kubernetes maintains only the AWS and GCE ingress controllers. Everything else is third-party. The list includes NGINX, Traefik, HAProxy, Contour, Kong, Istio, Cilium, and dozens more . Each controller has its own annotations, its own configuration model, and its own behavior for edge cases. The Ingress resource is the portable part; the controller-specific annotations are not.
The end-of-life problem. The ingress-nginx project reached end-of-life in March 2026. It no longer receives releases, bug fixes, or security updates. The OVHcloud documentation states: “The project no longer receives releases, bug fixes, or security updates and should not be deployed for new workloads” . A cluster still running ingress-nginx is running an unmaintained component that terminates TLS and routes all external traffic.
a. The IngressClass and controller selection
The IngressClass resource is how a cluster maps an Ingress to the controller that should implement it. The class has a spec.controller field that identifies the controller implementation, and an Ingress references the class by name with ingressClassName .
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
spec:
controller: k8s.io/ingress-nginx
A cluster can run multiple controllers. Each controller watches for Ingress resources with a matching class. An Ingress without a class uses the cluster’s default class if one exists, marked with the ingressclass.kubernetes.io/is-default-class: "true" annotation . If no default exists and the Ingress has no class, no controller processes it.
The NGINX Ingress Controller documentation notes that the controller “won’t start without an IngressClass resource” . This is a common installation failure: the controller Deployment is created, the Pods crash-loop, and the reason is a missing IngressClass.
b. Installing NGINX Ingress Controller
NGINX is the most widely deployed controller, but the installation path matters because the project is end-of-life. The F5 NGINX Ingress Controller (from nginx.org) is a different project from the Kubernetes ingress-nginx (from kubernetes.github.io). The F5 controller is actively maintained; the Kubernetes ingress-nginx is not.
The F5 controller is installed with Helm from the OCI registry:
helm install my-release oci://ghcr.io/nginx/charts/nginx-ingress --version 2.7.3
After installation, verify the IngressClass:
kubectl get ingressclasses
# NAME CONTROLLER AGE
# nginx nginx.org/ingress-controller 10m
The NGINX documentation warns that the Helm chart installs required CRDs, and without them the controller Pods will not become Ready . The --skip-crds flag is only appropriate if the custom resources are not used.
The Kubernetes ingress-nginx project, which is the one that reached EOL, was installed from the https://kubernetes.github.io/ingress-nginx Helm repository . That repository is no longer receiving updates.
c. Installing Traefik
Traefik is the controller that many migration guides recommend as the replacement for ingress-nginx. It is actively maintained, supports the Ingress resource, and is installed with Helm.
helm repo add traefik https://traefik.github.io/charts
helm repo update traefik
helm upgrade --install traefik traefik/traefik \
--version 41.0.2 \
--namespace traefik \
--create-namespace \
--wait --timeout 3m
The installation creates a LoadBalancer Service that provisions a cloud load balancer if the cluster supports it. The external IP is available in the Service status:
kubectl get service traefik -n traefik --watch
An Ingress that uses Traefik sets ingressClassName: traefik:
spec:
ingressClassName: traefik
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app
port:
number: 80
Traefik also supports cert-manager for automatic TLS certificate provisioning. The ClusterIssuer uses the traefik class for the HTTP-01 challenge solver .
Complete Example Session
# ============================================
# PART 1: THE INGRESSCLASS
# ============================================
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: traefik
spec:
controller: traefik.io/ingress-controller
# ============================================
# PART 2: INSTALL TRAEFIK
# ============================================
helm repo add traefik https://traefik.github.io/charts
helm repo update traefik
helm upgrade --install traefik traefik/traefik \
--namespace traefik \
--create-namespace \
--wait --timeout 3m
# ============================================
# PART 3: VERIFY THE CONTROLLER
# ============================================
kubectl rollout status deployment/traefik -n traefik
kubectl get ingressclasses
# NAME CONTROLLER AGE
# traefik traefik.io/ingress-controller 2m
# ============================================
# PART 4: CHECK THE EXTERNAL IP
# ============================================
kubectl get service traefik -n traefik --watch
# NAME TYPE EXTERNAL-IP
# traefik LoadBalancer 203.0.113.10
# ============================================
# PART 5: THE APPLICATION SERVICE
# ============================================
apiVersion: v1
kind: Service
metadata:
name: app
spec:
selector:
app: app
ports:
- port: 80
targetPort: 8080
# ============================================
# PART 6: THE INGRESS
# ============================================
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
ingressClassName: traefik
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app
port:
number: 80
# ============================================
# PART 7: VERIFY THE INGRESS
# ============================================
kubectl get ingress app-ingress
# NAME CLASS HOSTS ADDRESS PORTS
# app-ingress traefik app.example.com 203.0.113.10 80
# ============================================
# PART 8: TEST THE ROUTING
# ============================================
curl -H "Host: app.example.com" http://203.0.113.10/
# ============================================
# PART 9: CERT-MANAGER CLUSTERISSUER
# ============================================
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: admin@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: traefik
# ============================================
# PART 10: TLS ON THE INGRESS
# ============================================
spec:
ingressClassName: traefik
tls:
- hosts: [app.example.com]
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app
port:
number: 80
The ten parts covered the IngressClass, installing Traefik, verifying the controller, checking the external IP, the application Service, the Ingress, verification, testing, the ClusterIssuer, and TLS.
Quick Reference
Controller landscape
| Controller | Maintained by | Status |
|---|---|---|
| AWS Load Balancer Controller | Kubernetes project | Maintained |
| GCE Ingress Controller | Kubernetes project | Maintained |
| NGINX Ingress (F5) | F5/nginx.org | Maintained |
| ingress-nginx (Kubernetes) | Community | End-of-life (March 2026) |
| Traefik | Traefik Labs | Maintained |
| HAProxy | HAProxy Technologies | Maintained |
| Contour | Community | Maintained |
| Kong | Kong | Maintained |
IngressClass fields
| Field | Purpose |
|---|---|
metadata.name | The class name referenced by ingressClassName |
spec.controller | Identifies the controller implementation |
| Default annotation | ingressclass.kubernetes.io/is-default-class: "true" |
Installation commands
| Controller | Command |
|---|---|
| Traefik | helm upgrade --install traefik traefik/traefik --namespace traefik --create-namespace |
| NGINX (F5) | helm install my-release oci://ghcr.io/nginx/charts/nginx-ingress |
Verification
| Check | Command |
|---|---|
| IngressClass | kubectl get ingressclasses |
| Controller Pods | kubectl get pods -n <namespace> |
| External IP | kubectl get service <controller> -n <namespace> |
| Ingress status | kubectl get ingress |
Best Practices
โ Do This:
# Verify the IngressClass after installation
kubectl get ingressclasses # โ
# Set ingressClassName explicitly on every Ingress
spec:
ingressClassName: traefik # โ
# Use a maintained controller for new deployments
# Traefik, HAProxy, or F5 NGINX # โ
โ Don’t Do This:
# Deploy ingress-nginx for new workloads
# It reached end-of-life in March 2026 # โ
# Omit ingressClassName and assume a default exists
# If no default is marked, the Ingress is inert # โ
# Install a controller without checking the CRDs
# The Pods will not become Ready # โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Controller Pods crash-loop | Missing IngressClass or CRDs | Create the IngressClass; install the CRDs |
| Ingress has no effect | No controller matches the class | Check kubectl get ingressclasses and the ingressClassName |
External IP is <pending> | No cloud load balancer or MetalLB | Install a load balancer or use NodePort |
| 503 from the controller | Backend Service has no endpoints | Check kubectl get endpoints |
| Security vulnerabilities | ingress-nginx is EOL | Migrate to a maintained controller |
Real-World Examples
1. Traefik installation
helm upgrade --install traefik traefik/traefik --namespace traefik --create-namespace
2. Traefik IngressClass
kubectl get ingressclasses
3. Traefik Ingress
spec:
ingressClassName: traefik
4. NGINX (F5) installation
helm install my-release oci://ghcr.io/nginx/charts/nginx-ingress
5. NGINX IngressClass
spec:
controller: nginx.org/ingress-controller
6. Default class annotation
metadata:
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
7. Check controller Pods
kubectl get pods -n traefik
8. Check external IP
kubectl get service traefik -n traefik
9. Test routing
curl -H "Host: app.example.com" http://<external-ip>/
10. Migrate from ingress-nginx
ingress-nginx is EOL. Use Traefik or HAProxy.
Visual
The controller selection
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ INGRESS โ
โ ingressClassName: traefik โ
โ โ โ
โ โผ โ
โ INGRESSCLASS (traefik) โ
โ spec.controller: traefik.io/ingress-controller โ
โ โ โ
โ โผ โ
โ TRAEFIK CONTROLLER (running Pod) โ
โ watches Ingress resources with class "traefik" โ
โ configures the proxy โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The controller landscape (2026)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ MAINTAINED END-OF-LIFE โ
โ โ
โ Traefik ingress-nginx (Kubernetes) โ
โ HAProxy (EOL March 2026) โ
โ F5 NGINX โ
โ Contour โ
โ Kong โ
โ AWS/GCE (Kubernetes project) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Installation verification
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ helm install ... โ
โ โ โ
โ โผ โ
โ kubectl get ingressclasses โ
โ โ IngressClass exists? โ
โ โ โ
โ โผ โ
โ kubectl get pods -n <namespace> โ
โ โ Pods Running? โ
โ โ โ
โ โผ โ
โ kubectl get service -n <namespace> โ
โ โ External IP assigned? โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The EOL migration
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ingress-nginx (EOL) โ
โ โ โ
โ โโโ No security patches โ
โ โโโ No bug fixes โ
โ โโโ No releases โ
โ โ
โ Migration options: โ
โ โโโ Traefik (Ingress provider) โ
โ โโโ HAProxy Kubernetes Ingress Controller โ
โ โโโ Gateway API (the project's recommendation) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Controller purpose | Watches Ingress resources, configures the proxy |
| Required | Yes; Ingress is inert without a controller |
| IngressClass | Selects the controller by spec.controller |
| Default class | ingressclass.kubernetes.io/is-default-class: "true" |
| Kubernetes-maintained controllers | AWS, GCE |
| Third-party controllers | NGINX, Traefik, HAProxy, Contour, Kong, etc. |
| ingress-nginx status | End-of-life (March 2026) |
| API status | Frozen; Gateway API recommended for new work |
Key takeaways:
- An Ingress Controller is required for Ingress to work. The resource is a rule set; the controller is the running software that implements it. Without a controller, the Ingress is accepted by the API server and routes nothing .
- The Ingress API is frozen. The Kubernetes project has stopped developing it and recommends Gateway API for new work. Ingress remains stable and will not be removed, but new features will not be added .
- The IngressClass maps an Ingress to a controller. The class’s
spec.controllerfield identifies the implementation. An Ingress references the class by name. A default class can be marked with an annotation . - The controller installation must include the IngressClass and CRDs. The NGINX controller “won’t start without an IngressClass resource,” and the Helm chart installs CRDs that the Pods need to become Ready .
- ingress-nginx is end-of-life. The Kubernetes ingress-nginx project reached EOL in March 2026. It receives no security patches or bug fixes. New deployments should use a maintained controller like Traefik, HAProxy, or F5 NGINX .
- Traefik is a common migration target. It is actively maintained, supports the Ingress resource, and is installed with Helm. The installation creates a LoadBalancer Service, and an Ingress with
ingressClassName: traefikis routed by the controller.
Remember: The Ingress Controller is the component that turns the Ingress rules into real traffic routing. The resource declares the rules; the controller implements them. The IngressClass selects which controller handles which Ingress. The API is frozen and the most common implementation is end-of-life, so the controller choice in 2026 is also a decision about long-term maintenance. For new deployments, consider Gateway API, and if Ingress is required, choose a controller that is actively maintained.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!