Ingress
Route external HTTP/HTTPS traffic to multiple services with a single entry point and path-based rules.
myapp.local/api via Ingress, does the Ingress Controller forward the packet to the Service's ClusterIP, or does it bypass the Kubernetes service mesh routing? How does this impact load-balancing algorithms and connection keep-alives?The Problem with NodePort and LoadBalancer
NodePort: exposes a high-numbered port (30000β32767) on every node. Not suitable for production β users should not type myapp.com:31234.
LoadBalancer: creates one cloud load balancer per Service. If you have 10 microservices, you pay for 10 load balancers. That is expensive and hard to manage.
Ingress: N Services, One Entry Point
Ingress is a Kubernetes resource that defines HTTP/HTTPS routing rules. It acts like a virtual host configuration for a reverse proxy:
Internet β LoadBalancer β IngressController β (routing rules) β Service A
β Service B
β Service COne cloud load balancer handles all traffic. The IngressController applies your rules.
Two Components
| Component | What it is |
|---|---|
| Ingress resource | A Kubernetes object containing routing rules (host, path β Service) |
| IngressController | A running reverse proxy (nginx, Traefik, HAProxy, AWS ALB) that reads those rules and routes real traffic |
Important: creating an Ingress resource without an IngressController does nothing. The IngressController must be installed separately.
Path Types
| Type | Path `/api` matches |
|---|---|
Exact | Only /api (not /api/users) |
Prefix | /api, /api/users, /api/v2/items |
TLS Termination
Reference a kubernetes.io/tls Secret to enable HTTPS at the Ingress:
spec:
tls:
- hosts:
- myapp.local
secretName: myapp-tlsCreate the Secret with: kubectl create secret tls myapp-tls --cert=tls.crt --key=tls.key
The IngressController handles the TLS handshake. Backend Services receive plain HTTP β they do not need to know about TLS.
Annotations
Controller-specific behaviour (rate limiting, rewrites, auth) is configured via annotations:
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/limit-rps: "10"These are read by the IngressController β not by Kubernetes itself.
L7 Routing & TLS Termination Flow
[ Client HTTPS Request ]
(Host: myapp.local)
|
v
+------------------+-------------------+
| Cloud Load Balancer (TCP Pass-Through)|
+------------------+-------------------+
| (TLS Encrypted, Port 443)
v
+------------------+-------------------+
| Ingress-Nginx Controller |
| - TLS Handshake (SNI Match via SNI) |
| - Decrypts and injects headers |
| - Fetches Pod IPs from EndpointSlice| (Bypasses Service IP!)
+-------+---------------------+--------+
| |
v (Plain HTTP / L7) v (Plain HTTP / L7)
+-------+------------+ +----+---------------+
| Pod: Web-0 | | Pod: Web-1 |
| (10.244.1.5:80) | | (10.244.2.9:80) |
+--------------------+ +--------------------+Under the Hood: L7 Ingress Routing Internals
1. ClusterIP Bypass & Direct Endpoint Routing
Rather than proxying requests to the virtual IP (ClusterIP) of the backend Service, most Ingress Controllers bypass kube-proxy entirely. The Ingress Controller queries the API server for Endpoints or EndpointSlices associated with the target Service. It maintains a direct list of backend Pod IPs and forwards connections straight to them. This enables:
- Advanced L7 load-balancing algorithms (e.g., cookie-based session affinity, least-connections, hashing).
- Optimal TCP connection pooling and keep-alive management, avoiding the extra packet translation overhead of NAT routing.
2. SNI Match & TLS Handshake
For HTTPS ingress, client handshakes terminate directly at the Ingress Controller. Using Server Name Indication (SNI), the controller extracts the requested hostname from the ClientHello handshake packet. It loads the corresponding kubernetes.io/tls certificate, decrypts the request, injects standard proxy headers (X-Forwarded-For, X-Forwarded-Proto, and X-Real-IP), and streams the decrypted payload to the backend Pod endpoint.
3. Dynamic Reloading
Modern ingress controllers (like Ingress-Nginx) avoid restarting the web server process during endpoint updates. They use a Go sidecar or embedded Lua engines (OpenResty) to dynamically refresh backend Pod IPs in shared memory tables without dropping active TCP connections.