Ingress
So far, we’ve used Services (NodePort, LoadBalancer) to expose applications externally. But what if you have 10 microservices? You’d need 10 LoadBalancers — that’s expensive and hard to manage. Ingress solves this by providing a single entry point with HTTP/HTTPS routing to multiple Services.
What is Ingress?
Ingress is a Kubernetes resource that manages external HTTP/HTTPS access to Services. It provides:
- Path-based routing —
/api→ API Service,/web→ Web Service - Host-based routing —
api.example.com→ API Service,web.example.com→ Web Service - TLS termination — HTTPS with certificates
- Load balancing — Distribute traffic across backends
- Single entry point — One IP/domain for all Services
Internet
│
┌───────▼───────┐
│ Ingress │
│ Controller │
│ (nginx) │
└───┬───┬───┬───┘
│ │ │
/api │ │ │ /web
┌───────────┘ │ └───────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│API Svc │ │Auth Svc │ │Web Svc │
│ │ │ │ │ │
└─────────┘ └─────────┘ └─────────┘
Ingress vs. Service Types
| Feature | NodePort | LoadBalancer | Ingress |
|---|---|---|---|
| Layer | L4 (TCP/UDP) | L4 (TCP/UDP) | L7 (HTTP/HTTPS) |
| Cost | Free | $$$ per Service | $ (one LB for all) |
| Path routing | ❌ | ❌ | ✅ |
| Host routing | ❌ | ❌ | ✅ |
| TLS termination | ❌ | Cloud-dependent | ✅ |
| Best for | Development | Single service | Multiple HTTP services |
Ingress Controller
Important: An Ingress resource alone does nothing. You need an Ingress Controller — a reverse proxy that reads Ingress resources and configures routing.
Popular Ingress controllers:
| Controller | Notes |
|---|---|
| NGINX Ingress Controller | Most popular. Open source. |
| Traefik | Auto-discovery. Great for microservices. |
| HAProxy | High performance. Enterprise-ready. |
| Istio Gateway | Service mesh integration. |
| AWS ALB Ingress | Uses AWS Application Load Balancer. |
| GKE Ingress | Uses Google Cloud Load Balancer. |
Install NGINX Ingress Controller on Minikube
# Enable the Ingress addon in Minikube
minikube addons enable ingress
# Verify it's running
kubectl get pods -n ingress-nginx
Basic Ingress — Path-Based Routing
Route different URL paths to different Services:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /web
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
Path Types
| Type | Behavior | Example |
|---|---|---|
| Prefix | Matches URL path prefix | /api matches /api, /api/v1, /api/users |
| Exact | Matches the exact path only | /api matches only /api, not /api/v1 |
| ImplementationSpecific | Depends on the IngressClass | Controller decides |
Host-Based Routing
Route different domains to different Services:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-host-ingress
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- host: dashboard.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: dashboard-service
port:
number: 80
TLS / HTTPS
Create a TLS Secret
# Generate a self-signed certificate (for testing)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=myapp.example.com"
# Create the Secret
kubectl create secret tls myapp-tls --cert=tls.crt --key=tls.key
Configure TLS in Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
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-service
port:
number: 80
Traffic to https://myapp.example.com is terminated at the Ingress Controller, and forwarded as HTTP to the backend Service.
Default Backend
Handle requests that don’t match any rule:
spec:
defaultBackend:
service:
name: default-service
port:
number: 80
rules:
- host: api.example.com
# ...
Useful Annotations (NGINX)
| Annotation | Purpose |
|---|---|
nginx.ingress.kubernetes.io/rewrite-target: / |
Rewrite URL path |
nginx.ingress.kubernetes.io/ssl-redirect: "true" |
Force HTTPS |
nginx.ingress.kubernetes.io/proxy-body-size: "10m" |
Max upload size |
nginx.ingress.kubernetes.io/rate-limit: "10" |
Rate limiting |
nginx.ingress.kubernetes.io/cors-allow-origin: "*" |
CORS headers |
nginx.ingress.kubernetes.io/proxy-connect-timeout: "30" |
Backend timeout |
Hands-On: Complete Example with Minikube
# demo-ingress.yaml
# Backend Services
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-v1
spec:
replicas: 2
selector:
matchLabels:
app: hello
version: v1
template:
metadata:
labels:
app: hello
version: v1
spec:
containers:
- name: hello
image: hashicorp/http-echo
args: ["-text=Hello from V1!"]
ports:
- containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
name: hello-v1
spec:
selector:
app: hello
version: v1
ports:
- port: 80
targetPort: 5678
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-v2
spec:
replicas: 2
selector:
matchLabels:
app: hello
version: v2
template:
metadata:
labels:
app: hello
version: v2
spec:
containers:
- name: hello
image: hashicorp/http-echo
args: ["-text=Hello from V2!"]
ports:
- containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
name: hello-v2
spec:
selector:
app: hello
version: v2
ports:
- port: 80
targetPort: 5678
---
# Ingress routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: hello-v1
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: hello-v2
port:
number: 80
# Apply everything
kubectl apply -f demo-ingress.yaml
# Get the Ingress IP
kubectl get ingress hello-ingress
# In Minikube, get the Ingress IP
minikube ip
# Test routing
curl http://$(minikube ip)/v1 # Hello from V1!
curl http://$(minikube ip)/v2 # Hello from V2!
Inspecting Ingress
# List Ingress resources
kubectl get ingress
# Detailed info
kubectl describe ingress hello-ingress
# Check Ingress Controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller
Summary
- Ingress provides L7 (HTTP/HTTPS) routing to Services
- Requires an Ingress Controller (NGINX, Traefik, etc.)
- Supports path-based and host-based routing
- Handles TLS termination for HTTPS
- One Ingress can route to multiple Services — saves cost vs. multiple LoadBalancers
- Use annotations to configure controller-specific behavior
What’s Next?
Now that traffic can reach your Pods, let’s learn how to control which Pods can communicate with each other using Network Policies — Kubernetes’ built-in firewall rules.