Ingresses
A Service exposes one thing. An Ingress routes HTTP traffic to many things by hostname and path, and terminates TLS — which is what you actually want in front of a handful of web applications.
The crucial thing to know first: an Ingress does nothing on its own. It is a set of rules. Something has to read those rules and implement them, and that something is an ingress controller.
Reference
- https://kubernetes.io/docs/concepts/services-networking/ingress/
- https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/
- https://kubernetes.io/docs/concepts/services-networking/gateway/
Terminology
- Ingress controller — The component that watches Ingress objects and configures a real proxy. NGINX, Traefik, HAProxy, Contour, and cloud-specific ones. It runs as a Deployment and usually gets traffic through a Service of type
LoadBalancerorNodePort. ingressClassName— Which controller should implement this Ingress. With several installed, this is how you choose. A cluster normally marks one as the default.- Rule — A host and a set of paths, each pointing at a Service port. An Ingress with no rules is legal and does nothing useful.
pathType—Prefix(matches on path segments),Exact, orImplementationSpecific. Omit it and behaviour is controller-dependent, which is a bug waiting to happen.- Default backend — Where requests go when nothing matches. Without one, unmatched requests get a 404 from the controller.
- TLS block — Names a Secret containing a certificate and key. The controller terminates TLS; the backend gets plain HTTP.
The Shape of It
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
tls:
- hosts: [app.example.com]
secretName: web-tlsNote what is not here: no port on the ingress controller, no load balancer configuration, no certificate. All of that belongs to the controller and the annotation on the object.
Exercises
Find out whether your cluster has a controller. Without one, an Ingress is inert:
kubectl get ingressclass kubectl get pods -A | grep -i -E 'ingress|nginx|traefik'In your own cluster, you may need to install one:
helm upgrade --install ingress-nginx ingress-nginx \ --repo https://kubernetes.github.io/ingress-nginx \ --namespace ingress-nginx --create-namespaceRoute by hostname, and prove it from outside. Create a Deployment, a Service, and an Ingress for
web.example.com, then reach it through the controller. On a cluster with no external address, port-forward the controller itself and set theHostheader:kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 8080:80 curl -H 'Host: web.example.com' http://localhost:8080/Then delete the
host:line and see it match anything. A rule with no host is a catch-all, which is convenient in a lab and dangerous in production.Compare
PrefixandExact. Create paths for/apiwith each type and request/api/v1.Prefixmatches it;Exactdoes not. This is the difference between routing working and a confusing 404.Look at the TLS path. On the shared cluster, the controller is NGINX with cert-manager, and certificates are obtained automatically from a
ClusterIssuer:kubectl get certificate -A kubectl get secret web-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -subject -issuer -datesThe Secret named in the Ingress is created for you by cert-manager. Nothing in the Ingress manifest contains a certificate.
Ingress or Gateway API?
The Gateway API is the intended successor, and this course uses it for comparison rather than as the default. The difference is mainly about roles:
| Ingress | Gateway API | |
|---|---|---|
| Objects | one, with controller-specific annotations | GatewayClass, Gateway, HTTPRoute — separate objects |
| Who owns what | one object for everyone | infrastructure team owns the Gateway, application teams own routes |
| Protocols | HTTP and TLS termination | HTTP, TLS, TCP, UDP, gRPC, and traffic weighting |
| Annotations | how most real behaviour is expressed | expressed in the spec |
If your cluster has the Gateway API CRDs installed, create an HTTPRoute for the same backend and compare. The routing rules are more verbose and far more explicit, and there is no reliance on annotations a different controller would ignore.
Gotchas Worth Knowing
- An Ingress with no controller does nothing, silently. This is the most common cause of “my Ingress is not working” and it produces no events, because the object itself is valid.
- Annotations are controller-specific.
nginx.ingress.kubernetes.io/rewrite-targetmeans nothing to Traefik. Moving clusters means revisiting them. - The backend Service must be
ClusterIP. The controller is the thing facing the world; pointing at aNodePortorLoadBalancerService adds a hop and confuses debugging. pathTypeis not optional in practice. Omitting it makes matching behaviour depend on the controller’s implementation.- The Ingress does not create the Service or the certificate. It only references them, and a broken reference shows up as a 503 from the controller, not as an error on the Ingress.
What to Take Away
- An Ingress is a rule set; the controller is what makes it real.
ingressClassNameselects the controller, and the rules route by host and path.- TLS comes from a Secret that something else — usually cert-manager — maintains.
- If an Ingress appears to do nothing, check that a controller exists before anything else.