Skip to content

Kubernetes Ingress Controllers: NGINX, Traefik & Advanced Routing

DodaTech 5 min read

In this tutorial, you'll learn about Kubernetes Ingress Controllers: NGINX, Traefik & Advanced Routing. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Kubernetes Ingress controllers route external HTTP and HTTPS traffic to services inside the cluster, providing TLS termination, path-based routing, and Load Balancing without exposing individual service ports.

What You'll Learn

This tutorial covers deploying and configuring NGINX and Traefik ingress controllers, path and host-based routing, TLS certificate management, canary deployments, Rate Limiting, and troubleshooting ingress issues.

Why It Matters

Without an ingress controller, each service needs its own LoadBalancer, which is expensive and hard to manage. A single ingress controller handles routing for all services, reducing cloud costs and centralizing TLS, auth, and Rate Limiting policies.

Real-World Use

Cloudflare uses custom ingress configurations to route traffic to over 200 Microservices with per-service Rate Limiting and TLS policies. Shopify runs NGINX ingress controllers across multiple Kubernetes clusters handling 50,000 requests per second with custom annotations for traffic splitting during canary deployments.

graph LR
  A[Internet] --> B[LoadBalancer]
  B --> C[Ingress Controller]
  C --> D{Ingress Rules}
  D --> E[Path: /api -> Service A]
  D --> F[Path: /web -> Service B]
  D --> G[Host: app.example.com -> Service C]
  E --> H[Pod A1]
  E --> H2[Pod A2]
  F --> I[Pod B1]
  G --> J[Pod C1]

Expected output: diagram showing traffic flow from internet through LoadBalancer to Ingress Controller, then routing to different services based on path and host rules.

Deploying NGINX Ingress Controller

NGINX is the most widely adopted ingress controller for Kubernetes.

# Deploy NGINX Ingress Controller with Helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace

# Verify the controller is running
kubectl -n ingress-nginx get pods

Expected output: the ingress-nginx-controller pod shows 1/1 Ready. A LoadBalancer service is created with an external IP.

Path-Based Routing

Route traffic to different services based on URL paths.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: shop.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080
      - path: /web
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: static-service
            port:
              number: 80
# Apply the ingress
kubectl apply -f ingress-path.yaml

# View ingress details
kubectl get ingress app-ingress

# Test routing
curl -H "Host: shop.example.com" http://<EXTERNAL-IP>/api/health
curl -H "Host: shop.example.com" http://<EXTERNAL-IP>/web/index.html

Expected output: requests to /api/* reach the api-service, /web/* reaches web-service, and / reaches static-service.

TLS Termination

Secure ingress with TLS certificates.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: secure-ingress
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: app-tls
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80
# Create a self-signed certificate for testing
kubectl create secret tls app-tls \
  --cert=tls.crt --key=tls.key

# Or use cert-manager for automated certificates
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml

# Create a ClusterIssuer for Let's Encrypt
kubectl apply -f letsencrypt-issuer.yaml
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-key
    solvers:
    - http01:
        ingress:
          class: nginx

Expected output: the ingress shows the TLS secret name. Accessing https://app.example.com returns a valid TLS handshake, and cert-manager automatically provisions and renews certificates.

Canary Deployments with Annotations

Route a percentage of traffic to a new version.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service-v2
            port:
              number: 80
# Apply canary ingress
kubectl apply -f ingress-canary.yaml

# Verify canary weight
kubectl describe ingress app-ingress-canary

# Expected annotations
# nginx.ingress.kubernetes.io/canary: "true"
# nginx.ingress.kubernetes.io/canary-weight: "10"

Expected output: 10 percent of traffic routes to app-service-v2 while 90 percent continues to the original service defined in the primary ingress.

Traefik Ingress Controller

Traefik offers automatic service discovery and a built-in dashboard.

# Deploy Traefik with Helm
helm repo add traefik https://helm.traefik.io/traefik
helm install traefik traefik/traefik \
  --namespace traefik --create-namespace

# Access the Traefik dashboard
kubectl port-forward -n traefik svc/traefik 9000:9000
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: rate-limit
spec:
  rateLimit:
    average: 100
    burst: 50
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: traefik-app
  annotations:
    traefik.ingress.kubernetes.io/router.middlewares: default-rate-limit@kubernetescrd
spec:
  ingressClassName: traefik
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

Practice Questions

  1. What is the difference between an Ingress and an Ingress Controller? An Ingress is a Kubernetes API resource that defines routing rules. An Ingress Controller is a pod that implements those rules by configuring a reverse proxy like NGINX or Traefik.

  2. How do you terminate TLS at the ingress level? Specify the tls section in the Ingress spec with host names and a secret name containing the certificate and key. The ingress controller terminates TLS and forwards plain HTTP to backend services.

  3. What annotation enables canary deployments with NGINX ingress? The nginx.ingress.kubernetes.io/canary: "true" annotation combined with canary-weight to specify the traffic percentage to the canary service.

Frequently Asked Questions

Which ingress controller should I use for production?

NGINX is the most battle-tested with the largest community and ecosystem of annotations. Traefik offers easier configuration with CRDs and an automatic dashboard. Choose NGINX for complex routing rules and maximum control. Choose Traefik for simplicity, automatic Let's Encrypt, and built-in observability.

How do I debug ingress routing issues?

Check the ingress controller logs with kubectl logs -n ingress-nginx deploy/ingress-nginx-controller. Verify ingress status with kubectl describe ingress. Test backend services directly with kubectl port-forward to bypass the ingress. Check the ingress-nginx ConfigMap for global settings. Enable debug logging by adding --v=5 to the controller startup arguments.

Can I run multiple ingress controllers in one cluster?

Yes, but each must use a different ingressClassName. Deploy one NGINX controller for internal traffic and one Traefik for external traffic, or use different controllers for different namespaces. Each controller only processes Ingress resources with its matching ingressClassName field.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro