Why the ingress controller you pick matters
Hey, want your cluster to actually serve traffic?
Kubernetes gives you the Ingress API, a way to declare “route this host and path to that service.” What it does not give you is the thing that carries out those rules. That is the ingress controller, and it is a choice you make, not something built in. Pick well and routing, TLS, and rate limiting mostly take care of themselves. Pick badly and you fight annotations and reloads for months.
It is a real decision, not a default
An Ingress resource with no controller behind it does nothing at all. So before you write a single routing rule, you decide which controller watches those rules and turns them into real load-balancing.
The problem with treating ingress as an afterthought
What’s the issue?
Teams often copy an ingress manifest from a tutorial without knowing which controller (or how many) is running. The result is subtle: rules that never take effect, two controllers both trying to own the same Ingress, or a pile of vendor-specific annotations nobody understands.
The real-world consequences
The classic incident is two ingress controllers installed in one cluster, both reconciling the same Ingress object because no ingressClassName was set, so requests route inconsistently depending on which one answered. The other slow-burn problem is annotation sprawl. Nginx behavior gets tuned entirely through dozens of annotations until the routing logic is effectively undocumented.
The three main options
Here’s how to fix it
All three controllers implement the same Ingress API but in very different ways. The controller sits between the internet and your services, terminates TLS, and routes by host and path.
Implementing each one
Nginx Ingress runs an Nginx proxy inside the cluster and is configured largely through annotations, including rate limiting. Traefik uses dynamic configuration with no reloads, ships a dashboard and a middleware system, and has Let’s Encrypt built in. The AWS Load Balancer Controller provisions a real Application Load Balancer and wires its target groups straight to your pods.
Tools and platforms
Whichever controller you choose, let cert-manager own TLS certificates rather than managing them by hand. It issues and renews certs (from Let’s Encrypt or another issuer) and hands them to the controller, so TLS termination stops being a manual chore.
Quick implementation steps
Quick takeaways
- Always set
ingressClassNameso exactly one controller owns each Ingress. - Use cert-manager for TLS instead of hand-managed certificates.
- Nginx for portability and control, Traefik for dynamic cloud-native ergonomics, ALB for native AWS on EKS.
- Keep annotations documented, or you will not remember what your routing does.
Avoiding the common pitfalls
Set an explicit ingress class on every Ingress to avoid controllers fighting over the same object, and be careful across upgrades. Annotation names and CRD versions do change between controller releases, so read the release notes before bumping a chart.
Benefits you feel quickly
Why it helps
Choosing deliberately means routing behaves predictably, TLS renews itself, and the person on call can actually reason about how a request reaches a pod. The controller stops being a mystery box and becomes a documented part of your platform.
Right tool, right environment
On EKS where you want AWS-native load balancing, WAF, and ACM certificates, the ALB controller is the natural fit. If you need portability across clouds or on-prem, Nginx travels anywhere. If you value dynamic configuration and a nice operational experience, Traefik earns its place.
What’s your approach?
Community discussion
What’s your take? Are you on Nginx, Traefik, the AWS ALB, or something else like Contour or Cilium’s Gateway? I am curious what drove the choice.
Share your experience
If you have migrated between ingress controllers, I would love to hear how the annotation and TLS translation went, since that is usually the painful part.









