Understanding Ingress Controllers
Ingress Controllers are the front door to your Kubernetes cluster
They act as a Layer 7 load balancer, routing external HTTP/HTTPS traffic to the right services based on hostnames, paths, and other rules.
Internet
External traffic from users and clients hits your cluster's public endpoint.
Ingress Controller
L7 load balancer that inspects HTTP headers, paths, and hostnames to make routing decisions.
Ingress Rules
Declarative routing configuration that maps hosts and paths to backend services.
Services
Backend applications that receive the routed traffic from the Ingress Controller.
Why Ingress Controllers?
SSL/TLS Termination
Centralized HTTPS handling with automatic certificate management and secure connections.
Path-based Routing
Route requests based on URL paths, enabling microservice architectures with single entry point.
Virtual Hosting
Host multiple domains on the same cluster with intelligent host-based routing.
Load Balancing
Distribute traffic across backend services with health checks and failover capabilities.
URL Rewriting
Transform and manipulate URLs before forwarding to backend services.
Rate Limiting
Protect against DDoS attacks with configurable rate limiting and throttling.
Core Ingress Concepts
Basic Ingress Resource
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
Path Types Explained
- Exact: Matches the exact path only
- Prefix: Matches based on URL prefix
- ImplementationSpecific: Depends on the Ingress Controller
paths:
- path: /api/v1/users
pathType: Exact # Only /api/v1/users, nothing else
- path: /api/
pathType: Prefix # /api/anything matches
- path: /legacy
pathType: ImplementationSpecific # Controller decides
NGINX Ingress Controller
Installation
# Add NGINX Ingress repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
# Install NGINX Ingress Controller
helm install nginx-ingress ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.service.type=LoadBalancer \
--set controller.metrics.enabled=true
# Verify installation
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
Rate Limiting and Security
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: secure-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/limit-rps: "100"
nginx.ingress.kubernetes.io/limit-connections: "10"
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Frame-Options: SAMEORIGIN";
more_set_headers "X-Content-Type-Options: nosniff";
spec:
ingressClassName: nginx
tls:
- hosts:
- secure.example.com
secretName: secure-tls
rules:
- host: secure.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: secure-service
port:
number: 80
Canary Deployments
# Main Production Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: production-ingress
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-stable
port:
number: 80
---
# Canary Ingress (10% traffic)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: canary-ingress
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-canary
port:
number: 80
Traefik Ingress Controller
Installation and Configuration
# Add Traefik repository
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
# Install Traefik
helm install traefik traefik/traefik \
--namespace traefik \
--create-namespace \
--set dashboard.enabled=true \
--set service.type=LoadBalancer
# Access Dashboard (port-forward)
kubectl port-forward -n traefik \
$(kubectl get pods -n traefik --selector "app.kubernetes.io/name=traefik" -o name) \
9000:9000
Traefik IngressRoute
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: app-ingressroute
spec:
entryPoints:
- web
- websecure
routes:
- match: Host(`app.example.com`) && PathPrefix(`/api`)
kind: Rule
services:
- name: api-service
port: 8080
middlewares:
- name: api-stripprefix
- name: rate-limit
- match: Host(`app.example.com`)
kind: Rule
services:
- name: frontend-service
port: 80
tls:
certResolver: letsencrypt
Traefik Middlewares
# Strip Prefix Middleware
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: api-stripprefix
spec:
stripPrefix:
prefixes:
- /api
---
# Rate Limiting Middleware
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: rate-limit
spec:
rateLimit:
average: 100
burst: 50
---
# Security Headers
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: security-headers
spec:
headers:
frameDeny: true
sslRedirect: true
browserXssFilter: true
contentTypeNosniff: true
SSL/TLS Configuration
Automatic HTTPS with cert-manager
cert-manager automates certificate lifecycle
It watches for Ingress resources with specific annotations and automatically provisions and renews TLS certificates from Let's Encrypt or other ACME-compatible CAs.
# Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.0/cert-manager.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 automatic TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
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
Advanced Patterns
Blue-Green Deployments
# Blue Environment (Current)
apiVersion: v1
kind: Service
metadata:
name: app-blue-service
spec:
selector:
app: myapp
version: blue
ports:
- port: 80
---
# Green Environment (New)
apiVersion: v1
kind: Service
metadata:
name: app-green-service
spec:
selector:
app: myapp
version: green
ports:
- port: 80
---
# Ingress (Switch service name for deployment)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-blue-service # Change to app-green-service
port:
number: 80
API Gateway Pattern
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-gateway
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
nginx.ingress.kubernetes.io/rate-limit: "100"
nginx.ingress.kubernetes.io/auth-url: "http://auth-service.default.svc.cluster.local/verify"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /api/v1/users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 8080
- path: /api/v1/products
pathType: Prefix
backend:
service:
name: product-service
port:
number: 8080
- path: /api/v1/orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 8080
Controller Comparison
| Feature | NGINX Ingress | Traefik | HAProxy Ingress |
|---|---|---|---|
| Performance | Excellent | Good | Excellent |
| Configuration | Annotations | CRDs/Annotations | Annotations |
| Dashboard | None (3rd party) | Built-in | Basic stats |
| Let's Encrypt | Via cert-manager | Built-in | Via cert-manager |
| Canary Deployments | Native support | Weighted routing | Limited support |
| Best For | High-performance, mature | Dynamic config, modern | Enterprise, complex LB |
Security Best Practices
- Always use TLS/SSL in production environments
- Implement rate limiting to prevent abuse and DDoS attacks
- Use Web Application Firewall (WAF) for additional protection
- Regular security updates for Ingress Controllers
- Implement proper authentication and authorization
- Monitor and log all ingress traffic for security analysis
Practice Exercises
Easy Create a Basic Ingress Resource
Write an Ingress manifest that routes myapp.example.com to a service called myapp-svc on port 80.
You need an Ingress with a single host rule and one path entry using pathType Prefix.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-svc
port:
number: 80
Easy Add TLS to an Existing Ingress
Modify an Ingress resource to enable HTTPS using a TLS secret called myapp-tls and redirect HTTP to HTTPS.
Add a tls block to the spec and use the ssl-redirect annotation.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
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: myapp-svc
port:
number: 80
Medium Multi-Service Path Routing
Create an Ingress that routes /api to api-svc:8080, /admin to admin-svc:3000, and / to frontend-svc:80 under the same host.
Order matters: more specific paths should come first. Use Prefix pathType for all three.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-service-ingress
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 8080
- path: /admin
pathType: Prefix
backend:
service:
name: admin-svc
port:
number: 3000
- path: /
pathType: Prefix
backend:
service:
name: frontend-svc
port:
number: 80
Medium Set Up a Canary Deployment
Configure NGINX Ingress canary annotations to send 20% of traffic to a new version of your service while keeping 80% on the stable version.
You need two Ingress resources: one for the stable version and one with canary: "true" and canary-weight: "20" annotations.
# Stable Ingress (80% traffic)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: stable-ingress
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-stable
port:
number: 80
---
# Canary Ingress (20% traffic)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: canary-ingress
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-canary
port:
number: 80
Hard Design a Production API Gateway
Create a complete Ingress setup for a microservices API gateway with TLS, rate limiting, CORS, external auth, and routing to three services (users, products, orders).
Combine TLS configuration, NGINX annotations for rate limiting, CORS headers, and external auth-url, with multiple path rules.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-gateway
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE"
nginx.ingress.kubernetes.io/limit-rps: "50"
nginx.ingress.kubernetes.io/auth-url: "http://auth-svc.default.svc.cluster.local/verify"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /api/v1/users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 8080
- path: /api/v1/products
pathType: Prefix
backend:
service:
name: product-service
port:
number: 8080
- path: /api/v1/orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 8080
Pro Tip
Start with a simple single-service Ingress and build up complexity. Test each feature (TLS, path routing, annotations) independently before combining them into a production configuration.
Quick Reference
Common NGINX Annotations
| Annotation | Purpose | Example Value |
|---|---|---|
ssl-redirect |
Force HTTPS redirect | "true" |
limit-rps |
Rate limit per second | "100" |
enable-cors |
Enable CORS headers | "true" |
canary |
Enable canary routing | "true" |
canary-weight |
Traffic percentage to canary | "10" |
auth-url |
External auth endpoint | "http://auth-svc/verify" |
Essential kubectl Commands
# List all Ingress resources
kubectl get ingress --all-namespaces
# Describe an Ingress for debugging
kubectl describe ingress my-ingress
# Check Ingress Controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
# Verify TLS certificate
kubectl get secret my-tls-secret -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text
# Test Ingress routing
curl -H "Host: myapp.example.com" http://<ingress-ip>/api
Remember
An Ingress resource by itself does nothing. You need an Ingress Controller (NGINX, Traefik, etc.) running in your cluster to watch for Ingress resources and configure routing accordingly.