Creating an Ingress resource alone does nothing. You need an Ingress Controller running in your cluster. It watches for Ingress resources and configures routing accordingly.
Ingress
Route external HTTP/HTTPS traffic to your services. Path-based routing, TLS termination, and virtual hosts.
🧒 Simple Explanation (ELI5)
Think of a hotel front desk. Guests (HTTP requests) arrive at one entrance (one public IP). The front desk (Ingress) looks at who they're looking for — "I'm here for the conference" goes to the ballroom, "I need room 301" goes to floor 3. Without a front desk, you'd need a separate entrance for every department (a separate LoadBalancer for every service).
🤔 Why Use Ingress?
- Single entry point: One LoadBalancer/IP for many services instead of one per service
- Path-based routing:
/api→ api-service,/web→ web-service - Host-based routing:
api.example.com→ api,web.example.com→ web - TLS termination: Handle HTTPS at the Ingress level, not in each pod
- Cost savings: One cloud LB instead of many
🔧 Technical Explanation
Ingress Components
| Component | Role |
|---|---|
| Ingress Resource | YAML definition of routing rules (host, path → service mapping) |
| Ingress Controller | Actual software that implements the rules (NGINX, Traefik, HAProxy, cloud-native). Must be installed separately. |
📊 Visual: Ingress Routing
⌨️ Hands-on
Install NGINX Ingress Controller
# Using 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 # Or using kubectl kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.4/deploy/static/provider/cloud/deploy.yaml # Verify kubectl get pods -n ingress-nginx kubectl get svc -n ingress-nginx
Path-based Routing
# ingress-path.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
TLS / HTTPS
# Create TLS secret kubectl create secret tls app-tls \ --cert=tls.crt --key=tls.key
# ingress-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress-tls
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: app-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
# Apply and verify kubectl apply -f ingress-tls.yaml kubectl get ingress kubectl describe ingress app-ingress-tls
Use cert-manager to automatically provision and renew TLS certificates from Let's Encrypt. Add annotation cert-manager.io/cluster-issuer: letsencrypt-prod and cert-manager handles everything.
🐛 Debugging Scenarios
Scenario 1: Routing Not Working — 404 for All Paths
# Check ingress is created kubectl get ingress # Check ingress controller is running kubectl get pods -n ingress-nginx # Check ingress controller logs kubectl logs -n ingress-nginx deployment/ingress-nginx-controller # Common causes: # - ingressClassName missing or wrong # - Host doesn't match request (check DNS) # - Backend service name/port wrong # - Backend service has no endpoints # Verify backend service works kubectl get svc api-service kubectl get endpoints api-service
Scenario 2: HTTPS Not Working
- Secret doesn't exist or is in wrong namespace:
kubectl get secret app-tls - Certificate and key mismatch in the TLS secret
- Missing
ssl-redirectannotation — HTTP isn't redirecting to HTTPS - cert-manager certificate not ready:
kubectl get certificate,kubectl describe certificate
Scenario 3: 502 Bad Gateway
Cause: Ingress controller can reach the Service but the backend pods are unhealthy.
- Check pod readiness:
kubectl get pods -l app=api - Check if targetPort matches the port your app listens on
- Check ingress controller logs for upstream errors
🎯 Interview Questions
Beginner
An Ingress is a Kubernetes resource that manages external HTTP/HTTPS access to services. It provides routing rules (host-based and path-based), TLS termination, and load balancing at Layer 7 (HTTP). Unlike LoadBalancer Services (one LB per service), Ingress routes multiple services through a single entry point.
An Ingress Controller is the software that implements Ingress rules. It watches for Ingress resources and configures a reverse proxy (NGINX, Traefik, HAProxy) accordingly. Kubernetes doesn't include one by default — you must install it. Popular choices: NGINX Ingress Controller, Traefik, AWS ALB Ingress Controller.
LoadBalancer Service: one cloud LB per service, Layer 4 (TCP/UDP), no path-based routing. Ingress: one LB for many services, Layer 7 (HTTP/HTTPS), supports path/host routing, TLS termination, rewrites. Use Ingress for HTTP services; LoadBalancer for non-HTTP (databases, gRPC, custom TCP).
TLS termination means the Ingress controller decrypts HTTPS traffic and forwards plain HTTP to backend services. This centralizes TLS certificate management and offloads encryption overhead from application pods. The traffic between Ingress and pods is typically unencrypted (within the cluster network).
Yes. You can have multiple Ingress resources, even for the same hostname with different paths. The Ingress controller merges compatible rules. You can also run multiple Ingress controllers (e.g., NGINX for public, Traefik for internal) using ingressClassName to target specific controllers.
Intermediate
Prefix: Matches based on URL path prefix split by /. /api matches /api, /api/, /api/users. Exact: Only matches the exact path. /api matches /api only, not /api/users. There's also ImplementationSpecific where behavior depends on the controller.
Key annotations: nginx.ingress.kubernetes.io/rewrite-target (URL rewriting), ssl-redirect (force HTTPS), proxy-body-size (max upload size), rate-limit-connections (rate limiting), auth-url (external auth), cors-allow-origin (CORS), proxy-connect-timeout (timeout tuning). Annotations are controller-specific.
cert-manager watches for Ingress resources with specific annotations (e.g., cert-manager.io/cluster-issuer: letsencrypt). It automatically creates a Certificate resource, completes the ACME challenge (HTTP-01 or DNS-01), obtains the certificate from Let's Encrypt, stores it as a TLS Secret, and renews it before expiry. Fully automated TLS.
Gateway API is the successor to Ingress. It provides more expressive routing (header-based, weighted), better role separation (infrastructure provider → cluster admin → developer), and native support for TCP/UDP. It uses Gateway, HTTPRoute, and GatewayClass resources. It's more extensible and avoids the annotation sprawl problem of Ingress.
NGINX Ingress supports WebSockets by default (HTTP Upgrade headers pass through). For long-lived connections, increase timeouts: nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" and proxy-send-timeout: "3600". Ensure session affinity if multiple Ingress controller replicas exist (or use sticky sessions).
Scenario-Based
Classic redirect loop: the Ingress controller redirects HTTP→HTTPS, but the backend app also redirects to HTTPS (seeing the forwarded request as HTTP). Fix: 1) Tell the app it's behind a proxy: set X-Forwarded-Proto headers. 2) Configure the app to trust the proxy's headers. 3) Or add annotation nginx.ingress.kubernetes.io/ssl-redirect: "false" if the app handles its own HTTPS logic.
Create an Ingress with path-based routing. Use pathType: Prefix for each path. Important: add the rewrite-target annotation to strip the prefix before forwarding (so service-a sees / not /a). Test each path independently. Order matters with some controllers — more specific paths should be listed first.
1) Check DNS: does domain B resolve to the Ingress controller's external IP? 2) Check ingressClassName — both must target the same controller. 3) Check the Ingress controller logs for domain B requests. 4) Verify the backend service for domain B has endpoints. 5) Check for conflicting Ingress rules (same host, different namespaces can cause issues).
The NGINX Ingress controller defaults to 1MB max body size. Add annotation: nginx.ingress.kubernetes.io/proxy-body-size: "50m" on the Ingress resource. Also check if your backend has its own body size limit. For very large uploads, consider direct-to-storage uploads (signed URLs) to bypass the Ingress entirely.
NGINX Ingress supports canary annotations. Create a second Ingress resource with: nginx.ingress.kubernetes.io/canary: "true" and canary-weight: "10" (routes 10% traffic to canary). You can also route by header: canary-by-header: X-Canary. This allows gradual rollout testing before full deployment. For more advanced needs, use Argo Rollouts or Flagger.
🌍 Real-World Use Case
A multi-tenant SaaS platform uses Ingress to route 200+ customer domains:
- Wildcard cert:
*.platform.comTLS certificate via cert-manager - Host-based routing: Each customer gets
customer.platform.comrouted to their namespace - Rate limiting: NGINX annotations limit requests per customer to prevent abuse
- WAF: ModSecurity rules via NGINX annotations for OWASP protection
- Canary: New features rolled out to 5% of traffic first via canary annotations
📝 Summary
- Ingress provides Layer 7 routing (HTTP/HTTPS) to ClusterIP services
- Requires an Ingress Controller (NGINX, Traefik, etc.) to be installed
- Supports path-based, host-based routing, and TLS termination
- Use cert-manager for automated TLS certificate management
- Saves cost vs multiple LoadBalancer services