Ingress and Gateway API
The idea in one sentence
Section titled “The idea in one sentence”Ingress describes Layer-7 HTTP(S) routing rules for getting external traffic to internal Services, but those rules do nothing until an Ingress controller is actually running to implement them.
Ingress: routing rules, not a router
Section titled “Ingress: routing rules, not a router”A LoadBalancer Service works well for one application, but provisioning a separate cloud load balancer per app gets expensive and does not let you route by hostname or URL path. Ingress solves this at Layer 7: one entry point that inspects the HTTP request and routes based on host and path.
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: shop annotations: nginx.ingress.kubernetes.io/rewrite-target: /spec: ingressClassName: nginx rules: - host: shop.example.com http: paths: - path: /api pathType: Prefix backend: service: name: api-svc port: number: 80 - path: / pathType: Prefix backend: service: name: frontend-svc port: number: 80That manifest expresses two things at once: host-based routing (only requests for shop.example.com match this rule at all) and path-based routing (/api goes to one Service, everything else goes to another).
An Ingress object alone does nothing
Section titled “An Ingress object alone does nothing”This is the part that trips people up: creating an Ingress object does not, by itself, cause any traffic to be routed anywhere. Ingress is just a declaration of intent — it requires an Ingress controller, a separate piece of software actually running in the cluster (an nginx-based controller, a cloud provider’s controller, or others), watching Ingress objects and programming a real proxy or load balancer to match. No controller running means the Ingress resource just sits there, inert.
# An Ingress with no controller watching it accomplishes nothingkubectl get ingress shopkubectl get pods -n ingress-nginx # this is what actually does the routingWhen more than one controller is installed in a cluster, ingressClassName (backed by an IngressClass object) tells Kubernetes which controller should implement a given Ingress:
apiVersion: networking.k8s.io/v1kind: IngressClassmetadata: name: nginxspec: controller: k8s.io/ingress-nginxGateway API: a more expressive successor
Section titled “Gateway API: a more expressive successor”Gateway API is a newer, role-oriented model for the same problem, built from three resources instead of one:
- GatewayClass — the implementation, analogous to
IngressClass(provided by a controller vendor). - Gateway — a listener: an actual point of entry (protocol, port, hostname), typically owned by the platform/infrastructure team.
- HTTPRoute (and GRPCRoute) — the routing rules attached to a Gateway, typically owned by application teams.
apiVersion: gateway.networking.k8s.io/v1kind: Gatewaymetadata: name: shop-gatewayspec: gatewayClassName: example-gateway-class listeners: - name: http protocol: HTTP port: 80---apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: shop-routespec: parentRefs: - name: shop-gateway hostnames: - "shop.example.com" rules: - matches: - path: type: PathPrefix value: /api backendRefs: - name: api-svc port: 80That split matters in practice: a platform team can own and lock down the Gateway (which ports and TLS certs are exposed) while individual application teams safely own their own HTTPRoute objects without needing access to the shared listener at all. Gateway, GatewayClass, and HTTPRoute (along with GRPCRoute) have reached General Availability at gateway.networking.k8s.io/v1, and Gateway API is the direction the ecosystem is moving for new, more advanced routing needs — but Ingress remains extremely widely deployed, fully supported, and perfectly adequate for straightforward host/path routing. Neither is going away soon.
flowchart LR ext["External client"] --> ctrl["Ingress controller\n(e.g. nginx)"] ctrl -->|"host/path rules"| ing["Ingress object"] ing --> svcA["Service: api-svc"] --> podA["Pods"] ing --> svcB["Service: frontend-svc"] --> podB["Pods"]