Skip to content

Ingress Controllers

An Ingress on its own does nothing. It’s a config object that needs an Ingress Controller — a real reverse proxy running as pods — to interpret it and terminate traffic.

Layered view

  1. Cloud LB / MetalLB binds a public IP and forwards to a NodePort or a pod (with hostNetwork).
  2. That LB targets the controller pods (nginx / Traefik / Envoy).
  3. The controller watches Ingress (or HTTPRoute) objects and rewrites its own config.
  4. Requests then hit Services → Pods.
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts: [api.example.com]
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api
port:
number: 80

nginx vs Traefik — the honest comparison

Section titled “nginx vs Traefik — the honest comparison”
Concernnginx-ingressTraefik
Config sourceIngress + ConfigMap + annotationsIngress or IngressRoute CRD
Reload behaviorConfig regen + graceful reloadHot reload (dynamic)
MetricsPrometheus (needs enabling)Prometheus (built-in)
Cert-manager integrationExcellentNative ACME + cert-manager both fine
Rate limitingAnnotationsMiddleware CRDs

The Gateway API is the standards-based replacement for Ingress. Same problem, better model:

httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api
spec:
parentRefs:
- name: shared-gateway
namespace: gateway-system
hostnames: ["api.example.com"]
rules:
- matches:
- path: { type: PathPrefix, value: /v1 }
backendRefs:
- name: api-v1
port: 80
- matches:
- path: { type: PathPrefix, value: /v2 }
backendRefs:
- name: api-v2
port: 80
Terminal window
kubectl -n ingress-nginx logs -l app.kubernetes.io/name=ingress-nginx --tail=100 -f