Containers

Kubernetes Ingress Controllers: Routing External Traffic the Right Way

Compare Kubernetes Ingress controllers -- nginx-ingress, Traefik, HAProxy, Contour. Learn path and host routing, automatic TLS with cert-manager, and the Gateway API.

A
Abhishek Patel7 min read

Infrastructure engineer with 10+ years building production systems on AWS, GCP,…

Kubernetes Ingress Controllers: Routing External Traffic the Right Way
Kubernetes Ingress Controllers: Routing External Traffic the Right Way

Getting Traffic Into Your Cluster

A Kubernetes Ingress controller is the component that actually routes external HTTP/HTTPS traffic to your Services. Kubernetes defines the Ingress resource as a declarative routing spec, but it does absolutely nothing on its own -- you need a controller running in the cluster to read those specs and configure a reverse proxy accordingly.

This distinction trips up nearly every newcomer. You create an Ingress manifest, apply it, and nothing happens. No error, no traffic, no feedback. That's because without a controller, an Ingress resource is just data sitting in etcd.

What Is a Kubernetes Ingress?

Definition: A Kubernetes Ingress is an API resource that defines rules for routing external HTTP(S) traffic to internal Services based on hostnames and URL paths. It requires an Ingress controller -- a reverse proxy running inside the cluster -- to implement these rules and handle the actual traffic routing, TLS termination, and load balancing.

Why Not Just Use a LoadBalancer Service?

You can expose each Service with type: LoadBalancer, and it works. But each one provisions a separate cloud load balancer, each with its own external IP and monthly cost. For 10 services, that's 10 load balancers at $15-20/month each on most clouds. An Ingress controller gives you one load balancer that routes to all your services based on rules.

ApproachExternal IPsTLS ManagementCost (10 services, AWS)
LoadBalancer per Service10Per-service~$180/month
Single Ingress Controller1Centralized~$18/month

Popular Ingress Controllers Compared

ControllerProxy EngineProtocol SupportConfig StyleBest For
ingress-nginxNGINXHTTP, HTTPS, gRPC, WebSocketAnnotationsGeneral purpose, most popular
TraefikTraefikHTTP, HTTPS, gRPC, TCP, UDPCRDs + annotationsAuto-discovery, middleware chains
HAProxy IngressHAProxyHTTP, HTTPS, TCPAnnotations + ConfigMapHigh-performance TCP workloads
ContourEnvoyHTTP, HTTPS, gRPCHTTPProxy CRDMulti-team clusters, delegation
Kong IngressKong (OpenResty)HTTP, HTTPS, gRPC, TCPCRDs + pluginsAPI gateway features built in

Pro tip: Start with ingress-nginx unless you have a specific reason not to. It's the most widely deployed, has the most community support, and handles 90% of use cases. Switch to Traefik if you need automatic Let's Encrypt or TCP/UDP routing without extra configuration.

Setting Up ingress-nginx: Step by Step

  1. Install the controller using Helm or the official manifests
  2. Verify the controller Pod is running and a LoadBalancer Service is created
  3. Create an Ingress resource with your routing rules
  4. Point your DNS to the controller's external IP
  5. Add TLS with cert-manager for automatic certificate management
# Install with Helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace
# Verify the controller is running
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

Path-Based Routing

Route different URL paths to different backend Services. This is the most common Ingress pattern:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /api(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: api-service
            port:
              number: 8080
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 3000

Host-Based Routing

Route different hostnames to different Services. Useful for microservices or multi-tenant architectures:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-host-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080
  - host: dashboard.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: dashboard-service
            port:
              number: 3000

TLS with cert-manager

cert-manager automates certificate issuance and renewal from Let's Encrypt (or other ACME providers). It watches Ingress resources for TLS configuration and automatically provisions certificates.

# Install cert-manager
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --set crds.enabled=true
# Create a ClusterIssuer for Let's Encrypt
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx
# Ingress with automatic TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: secure-ingress
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - myapp.example.com
    secretName: myapp-tls
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 3000

Watch out: Always test with Let's Encrypt's staging server first (https://acme-staging-v02.api.letsencrypt.org/directory). The production server has strict rate limits -- 50 certificates per registered domain per week. Hit that limit and you're locked out for 7 days.

Common Annotations for ingress-nginx

AnnotationPurposeExample Value
nginx.ingress.kubernetes.io/rewrite-targetRewrite URL path/$2
nginx.ingress.kubernetes.io/ssl-redirectForce HTTPS"true"
nginx.ingress.kubernetes.io/proxy-body-sizeMax request body"50m"
nginx.ingress.kubernetes.io/proxy-read-timeoutBackend timeout"120"
nginx.ingress.kubernetes.io/cors-allow-originCORS origin header"https://mysite.com"
nginx.ingress.kubernetes.io/rate-limit-rpsRequests per second"10"

Gateway API: The Future of Ingress

The Gateway API is an official Kubernetes project that's gradually replacing Ingress. It addresses several Ingress limitations: no standard for TCP/UDP routing, vendor-specific annotations, and no role-based resource model.

Key Differences from Ingress

  • Typed routes -- HTTPRoute, TCPRoute, GRPCRoute instead of one generic Ingress resource
  • Role-oriented -- GatewayClass (infra provider), Gateway (cluster operator), Routes (app developer)
  • Portable -- behavior defined in the spec, not in vendor annotations
  • Extensible -- policy attachment for things like rate limiting, authentication, and circuit breaking
# Gateway API example
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-route
spec:
  parentRefs:
  - name: my-gateway
  hostnames:
  - "myapp.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api
    backendRefs:
    - name: api-service
      port: 8080

Pricing and Cost Comparison

SolutionCostNotes
ingress-nginx (OSS)Free + 1 cloud LB (~$18/mo)Most popular, community maintained
Traefik (OSS)Free + 1 cloud LBBuilt-in Let's Encrypt, dashboard
Traefik EnterpriseCustom pricingHA, distributed rate limiting, OIDC
Kong Gateway (OSS)Free + 1 cloud LBPlugin ecosystem for API management
Kong EnterpriseFrom $15K/yearDeveloper portal, advanced analytics
AWS ALB Ingress ControllerALB pricing (~$22/mo + LCU)Native AWS integration, no extra pods

Frequently Asked Questions

What happens if I create an Ingress without an Ingress controller?

Nothing. The Ingress resource is stored in etcd, but no component reads or acts on it. There's no error message or warning -- Kubernetes accepts the resource. You need a controller running in the cluster to watch for Ingress resources and configure the actual reverse proxy.

Can I run multiple Ingress controllers in one cluster?

Yes. Use the ingressClassName field in your Ingress resource to specify which controller should handle it. This is common in large clusters where different teams or environments need different controller configurations. Each controller watches only for Ingress resources with its class name.

Is the Gateway API ready for production?

The core HTTPRoute and Gateway resources reached GA (v1) status in Kubernetes 1.28. Most major controllers (ingress-nginx, Traefik, Cilium, Contour) support Gateway API. It's production-ready for HTTP routing. TCP/UDP/gRPC routes are still evolving. New projects should consider starting with Gateway API directly.

How do I handle WebSocket connections through an Ingress?

ingress-nginx supports WebSockets out of the box -- no special configuration needed. For long-lived connections, increase the proxy timeouts: set nginx.ingress.kubernetes.io/proxy-read-timeout and proxy-send-timeout to higher values (e.g., "3600" for one hour). Traefik also handles WebSockets natively.

Should I use annotations or CRDs for Ingress configuration?

Annotations work for simple cases but become unmanageable with complex routing. If you need middleware chains, traffic splitting, or cross-namespace routing, use a controller with CRD support (Traefik IngressRoute, Contour HTTPProxy, or Gateway API HTTPRoute). CRDs are typed, validated, and version-controlled.

How do I migrate from Ingress to Gateway API?

Run both side by side. Install a Gateway API implementation, create equivalent HTTPRoute resources, and test them with a separate Gateway. Once verified, update your DNS to point to the new Gateway's external IP. Remove the old Ingress resources after traffic has fully migrated. Most controllers support both APIs simultaneously.

Conclusion

Install ingress-nginx, add cert-manager for automatic TLS, and use path-based or host-based routing. That covers 90% of real-world traffic routing needs. Keep your annotations minimal and well-documented. If you're starting a new cluster in 2024+, evaluate Gateway API -- it's the direction Kubernetes networking is heading, and the HTTP routing parts are production-ready today.

A

Written by

Abhishek Patel

Infrastructure engineer with 10+ years building production systems on AWS, GCP, and bare metal. Writes practical guides on cloud architecture, containers, networking, and Linux for developers who want to understand how things actually work under the hood.

Related Articles

Enjoyed this article?

Get more like this in your inbox. No spam, unsubscribe anytime.

Comments

Loading comments...

Leave a comment

Stay in the loop

New articles delivered to your inbox. No spam.