What is Ingress?
An Ingress is a Kubernetes resource that manages external access to services in a cluster, typically HTTP/HTTPS traffic. It provides load balancing, SSL/TLS termination, and name-based virtual hosting. Unlike LoadBalancer Services (which provision one LB per service), Ingress consolidates routing rules into a single resource backed by a single load balancer.
Ingress vs LoadBalancer Service
- LoadBalancer Service: One cloud load balancer per service (~$20/month each). Simple but expensive at scale.
- Ingress: One load balancer for many services. Routes based on hostname and path. Supports TLS termination, rewrites, rate limiting.
Ingress Controllers
An Ingress resource on its own does nothing — you need an Ingress Controller to fulfill the Ingress rules. The controller runs as Pods in your cluster and watches for Ingress resources, then configures the underlying proxy (NGINX, Envoy, Traefik, etc.) accordingly.
Installing NGINX Ingress Controller
# 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 \
--set controller.replicaCount=2 \
--set controller.resources.requests.cpu=100m \
--set controller.resources.requests.memory=128Mi
# Verify installation
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
# Get the external IP/hostname
kubectl get svc ingress-nginx-controller -n ingress-nginx
Basic Ingress Resource
# basic-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-frontend
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-server
port:
number: 8080
- path: /docs
pathType: Prefix
backend:
service:
name: docs-service
port:
number: 3000
TLS Termination
# tls-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: secure-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
- api.example.com
secretName: app-tls-cert # cert-manager auto-creates this
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-frontend
port:
number: 80
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-server
port:
number: 8080
cert-manager for Automatic TLS
# Install cert-manager
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set installCRDs=true
# cluster-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-prod-key
solvers:
- http01:
ingress:
class: nginx
Advanced Ingress Annotations
# advanced-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: advanced-ingress
annotations:
# Rate limiting
nginx.ingress.kubernetes.io/limit-rps: "50"
nginx.ingress.kubernetes.io/limit-connections: "10"
# Request/response size limits
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
# Timeouts
nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
nginx.ingress.kubernetes.io/proxy-send-timeout: "120"
# CORS
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
# Websocket support
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Canary deployment (route 10% of traffic to canary)
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: web-frontend-canary
port:
number: 80
Key Takeaways
- Ingress consolidates HTTP routing rules behind a single load balancer
- You need an Ingress Controller (NGINX, Traefik, Envoy) to implement Ingress rules
- cert-manager automates TLS certificate provisioning from Let's Encrypt
- Annotations provide powerful configuration: rate limiting, CORS, canary deployments
- Use path-based and host-based routing to serve multiple services from one entry point