Ingress
A LoadBalancer Service gives you one external IP per Service. Thirty services
means thirty load balancers and thirty bills. Ingress exists to collapse that into
one entry point that routes by hostname and path.
The resource is only a declaration
This is the part that catches people out. An Ingress object is inert. It describes routing rules; it does not implement them. Without an ingress controller running in the cluster — ingress-nginx, Traefik, HAProxy, a cloud-native one — creating an Ingress does exactly nothing.
A minimal rule set
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: storefront
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
ingressClassName decides which controller claims this object. With two controllers
installed and no class set, either both claim it or neither does — both outcomes are
confusing to debug.
pathType matters more than it looks
| Value | Matches |
|---|---|
Exact | The path string exactly, case-sensitive |
Prefix | Split on /, element by element |
ImplementationSpecific | Whatever the controller decides |
Prefix compares path elements, not characters. /api matches /api and
/api/orders, but not /apiary. That distinction surprises people expecting a
plain string prefix.
ImplementationSpecific is where portability quietly dies — an ingress-nginx regex
path will not survive a move to a different controller.
TLS
spec:
tls:
- hosts:
- shop.example.com
secretName: shop-tls
The Secret must be type kubernetes.io/tls, must live in the same namespace as the
Ingress, and must already exist. A missing Secret does not block the Ingress from
being created — it just serves the controller's default self-signed certificate,
which looks like a certificate problem rather than a missing-object problem.
When Ingress is not enough
Ingress only models HTTP and HTTPS. Raw TCP, UDP, gRPC routing rules and weighted traffic splits all sit outside the spec, which is why every controller grew its own annotations — and why those annotations do not port between controllers.
The Gateway API is the successor that models these properly, with separate resources for infrastructure and routing. New clusters should look at it before committing to controller-specific annotations.