17 - Ingress & Load Balancing
Why Ingress?
LoadBalancer Services give each service its own external IP/load balancer. With many services, this gets expensive and hard to manage. Ingress provides:
- Single entry point for multiple services
- Host-based and path-based routing
- TLS termination
- Centralized load balancing
Without Ingress: With Ingress:
LB ($) → svc-api Single LB ($)
LB ($) → svc-web │
LB ($) → svc-admin ▼
LB ($) → svc-docs Ingress Controller
├─ api.example.com → svc-api
3-4 load balancers = $$$ ├─ example.com → svc-web
├─ admin.example.com → svc-admin
└─ docs.example.com → svc-docs
1 load balancer = $
Ingress Components
- Ingress Resource: YAML defining routing rules
- Ingress Controller: The actual reverse proxy (nginx, traefik, etc.)
- IngressClass: Links Ingress resources to a specific controller
Ingress Controller
An Ingress resource does nothing without a controller. You must install one:
| Controller | Description | Best For |
|---|---|---|
| NGINX Ingress | Most popular, battle-tested | General purpose |
| Traefik | Auto-discovery, Let's Encrypt | Simple setups |
| HAProxy | High performance | Heavy traffic |
| AWS ALB Controller | Native AWS ALB | EKS |
| GCE Ingress | Native GCP LB | GKE |
| Istio Gateway | Service mesh gateway | Istio users |
| Contour | Envoy-based | Advanced routing |
bash# Install NGINX Ingress Controller kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.5/deploy/static/provider/cloud/deploy.yaml # Or with Helm helm install ingress-nginx ingress-nginx/ingress-nginx \ --namespace ingress-nginx --create-namespace
Basic Ingress Resource
Host-Based Routing
yamlapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: multi-host annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: ingressClassName: nginx rules: - host: api.example.com http: paths: - path: / pathType: Prefix backend: service: name: api-service port: number: 80 - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: web-service port: number: 80 - host: admin.example.com http: paths: - path: / pathType: Prefix backend: service: name: admin-service port: number: 80
Path-Based Routing
yamlapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: path-routing spec: ingressClassName: nginx rules: - host: example.com http: paths: - path: /api pathType: Prefix backend: service: name: api-service port: number: 80 - path: /admin pathType: Prefix backend: service: name: admin-service port: number: 80 - path: / pathType: Prefix backend: service: name: web-service port: number: 80
Path Types
| Type | Behavior | Example |
|---|---|---|
Prefix | Matches URL path prefix | /api matches /api, /api/users |
Exact | Exact URL path match | /api matches only /api |
ImplementationSpecific | Controller decides | Depends on controller |
TLS/HTTPS
yamlapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: tls-ingress annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" spec: ingressClassName: nginx tls: - hosts: - example.com - api.example.com secretName: tls-secret # Must contain tls.crt and tls.key rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: web-service port: number: 80
bash# Create TLS secret kubectl create secret tls tls-secret \ --cert=server.crt \ --key=server.key
Automatic TLS with cert-manager
bash# Install cert-manager kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml
yaml# 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 auto-TLS apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: auto-tls annotations: cert-manager.io/cluster-issuer: letsencrypt-prod spec: ingressClassName: nginx tls: - hosts: - example.com secretName: example-com-tls # cert-manager creates this rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: web-service port: number: 80
Common Annotations (NGINX)
yamlmetadata: annotations: # Rewrite URL path nginx.ingress.kubernetes.io/rewrite-target: /$2 # Rate limiting nginx.ingress.kubernetes.io/limit-rps: "10" # Request body size nginx.ingress.kubernetes.io/proxy-body-size: "50m" # Timeouts nginx.ingress.kubernetes.io/proxy-read-timeout: "300" nginx.ingress.kubernetes.io/proxy-send-timeout: "300" # CORS nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com" # Authentication nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: basic-auth # WebSocket support nginx.ingress.kubernetes.io/proxy-http-version: "1.1" nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr" # Redirect HTTP → HTTPS nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
Gateway API (The Future of Ingress)
Gateway API is the successor to Ingress with more features:
yaml# Gateway (replaces Ingress Controller config) apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: main-gateway spec: gatewayClassName: nginx # or istio, envoy, etc. listeners: - name: http port: 80 protocol: HTTP - name: https port: 443 protocol: HTTPS tls: mode: Terminate certificateRefs: - name: tls-secret --- # HTTPRoute (replaces Ingress rules) apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: api-route spec: parentRefs: - name: main-gateway hostnames: - "api.example.com" rules: - matches: - path: type: PathPrefix value: /v1 backendRefs: - name: api-v1 port: 80 weight: 90 - name: api-v2 port: 80 weight: 10 # Canary: 10% to v2
Gateway API advantages over Ingress:
- Native traffic splitting (canary/blue-green)
- Header-based routing
- TCP/UDP routing (not just HTTP)
- Role-based resource model
- Cross-namespace references
Default Backend
Handle requests that don't match any rule:
yamlspec: defaultBackend: service: name: default-backend port: number: 80
kubectl Commands
bash# List ingresses kubectl get ingress kubectl get ing # Describe kubectl describe ingress my-ingress # Get ingress controller IP kubectl get svc -n ingress-nginx # Check ingress class kubectl get ingressclass # Test curl -H "Host: api.example.com" http://<ingress-ip>/
FAANG Interview Angle
Common questions:
- "How do you expose HTTP services in Kubernetes?"
- "What's the difference between Ingress and LoadBalancer Service?"
- "How do you handle TLS in Kubernetes?"
- "What is an Ingress Controller?"
- "How would you do path-based routing in K8s?"
Key answers:
- Ingress for HTTP(S) routing with host/path rules; LoadBalancer for L4 (TCP/UDP)
- LoadBalancer = one LB per service ($$$). Ingress = one LB for many services via routing rules
- TLS Secret + Ingress TLS config, or cert-manager for automatic Let's Encrypt
- Ingress Controller is the reverse proxy (nginx, traefik) that implements Ingress rules
- Ingress with path-based rules or Gateway API HTTPRoute for advanced routing