Skip to content

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

ValueMatches
ExactThe path string exactly, case-sensitive
PrefixSplit on /, element by element
ImplementationSpecificWhatever 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.