skip to content

What shortcomings of the Kubernetes Ingress resource is the Gateway API designed to fix?

level: middleimportance: must knowfreq 50%

answer

  1. Ingress spec = host + path only, rest is annotations
  2. annotations: untyped, unvalidated, unportable
  3. no field-level RBAC → no role separation
  4. HTTP-only vs HTTPRoute/GRPCRoute/TCPRoute
  5. rich per-resource status conditions

basics

~20 s

Ingress can only express host and path rules, so everything else — rewrites, canary weights, header matching, timeouts — became vendor annotations that are untyped and unportable. It also has no role separation and only supports HTTP. Gateway API makes those first-class, typed, and role-split.

solid answer

~50 s

Four concrete gaps. 1. **Expressiveness.** Ingress matches on host and path only. Header-based routing, method matching, weighted traffic splits, rewrites and mirroring all had to live in controller-specific annotations such as `nginx.ingress.kubernetes.io/*`. Those are untyped strings the API server cannot validate, and moving controllers means rewriting them. 2. **Role separation.** One Ingress object holds TLS, hostname and app routing, so you cannot grant routing self-service without also granting certificate and hostname control. Gateway API splits this into operator-owned Gateway and developer-owned HTTPRoute, with `allowedRoutes` bounding attachment. 3. **Protocol scope.** Ingress is HTTP/HTTPS only; Gateway API adds GRPCRoute plus experimental TCP, UDP and TLS routes on the same listener model. 4. **Extensibility.** Gateway API is designed for extension — typed filters, `parametersRef`, and policy attachment — rather than every vendor inventing annotations. Ingress is not deprecated; it is frozen, and Gateway API is where new capability lands.

code

yaml · 40 lines
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  ingressClassName: nginx
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /api(/|$)(.*)
            pathType: ImplementationSpecific
            backend:
              service:
                name: api
                port:
                  number: 8080
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: shop
spec:
  parentRefs:
    - name: edge
  hostnames: ["shop.example.com"]
  rules:
    - matches:
        - path: {type: PathPrefix, value: /api}
      filters:
        - type: URLRewrite
          urlRewrite:
            path: {type: ReplacePrefixMatch, replacePrefixMatch: /}
      backendRefs:
        - {name: api, port: 8080, weight: 90}
        - {name: api-canary, port: 8080, weight: 10}

go deeper

for a junior

It is enough to say Ingress only does host and path, so everything else became vendor annotations, and Gateway API turns those into real fields.

for a middle

Name specific capabilities that were annotation-only — rewrites, canary weights, header matching — and explain why untyped annotations are unvalidated and unportable.

for a senior

Add the RBAC and multi-tenancy angle, the protocol scope, and how per-resource status conditions change day-to-day debugging.

for a principal

Weigh migration cost against benefit: which clusters genuinely need it, conformance-level risk across implementations, and a staged plan where Ingress and Gateway coexist behind the same DNS.

## The annotation problem The `networking.k8s.io/v1` `Ingress` resource expresses exactly one thing: for a given host and path, send traffic to a Service port. Everything else real production traffic needs — rewriting the path before it reaches the backend, splitting 5% of traffic to a canary, routing on a header, setting a timeout or body-size limit, enabling sticky sessions, adding CORS, forcing HTTPS redirects — has no field. Controllers solved this the only way they could: annotations. In practice an Ingress in a mature cluster is three lines of `spec` and fifteen lines of `nginx.ingress.kubernetes.io/...` or `alb.ingress.kubernetes.io/...` keys. Annotations are free-form strings on metadata. The API server cannot validate them, so a typo silently does nothing; there is no schema, no `kubectl explain`, and no defaulting. They are per-implementation, so an Ingress written for one controller is not portable to another — the `spec` moves, the behaviour does not. And because some annotations rewrite request paths or inject configuration snippets, they have been a recurring source of security findings when untrusted tenants can set them. The Gateway API's answer is to make the common cases typed API fields. Path rewriting is a `URLRewrite` filter. Header manipulation is a `RequestHeaderModifier` filter. Traffic splitting is a `weight` on each `backendRef`. Header, method and query matching are structured `matches`. Mirroring is a `RequestMirror` filter. These are validated by the API server, discoverable, and portable across conformant implementations. ## The ownership problem A single Ingress object contains the TLS Secret reference, the public hostname, the class selection, and the application's path rules. In a shared cluster those belong to different people. Because Kubernetes RBAC grants on resource kinds, not on fields, you cannot say "developers may edit paths but not `spec.tls`". Platform teams therefore either accepted the risk or built admission webhooks and templating layers to fake field-level control. Gateway API splits the object along ownership lines. The cluster operator owns the `Gateway` — listeners, ports, hostnames, certificates — and declares in `allowedRoutes` which namespaces and route kinds may attach. Application teams own `HTTPRoute` in their own namespace and reference the Gateway with `parentRefs`. Attachment is two-sided: the route must ask, and the listener must permit. Standard RBAC now expresses exactly the intended permission, with no webhook required. ## The scope problem Ingress models HTTP and HTTPS. Anything else — raw TCP, UDP, or TLS passthrough — was done with per-vendor ConfigMaps or extra Services. Gateway API keeps one listener model and layers protocol-specific route kinds on top: `HTTPRoute`, `GRPCRoute` (GA), and the experimental `TCPRoute`, `UDPRoute` and `TLSRoute`. A single Gateway can carry listeners for several protocols. ## The extensibility and observability problems Gateway API defines conformance levels — Core, Extended, Implementation-specific — so implementations advertise which typed features they support instead of inventing parallel annotation dialects. Implementation-specific behaviour still exists, but it is expressed through `ExtensionRef` filters and `parametersRef` that point at real, schema-bearing CRDs. Policy attachment lets cross-cutting concerns be modelled as separate objects targeting a Gateway or a route. Status is the other quiet improvement. Ingress status carries little more than a load-balancer address, so failures like "this controller ignored your object" or "your TLS Secret is missing" surface only in controller logs. Every Gateway API resource carries conditions: Gateways report `Accepted` and `Programmed` per listener plus `attachedRoutes`; routes report `Accepted` and `ResolvedRefs` per parent, with reasons such as `NotAllowedByListeners`, `NoMatchingListenerHostname` and `BackendNotFound`. Debugging becomes a `kubectl describe` instead of log archaeology. ## What Gateway API does not fix It is still CRDs you install and a controller you operate; it does not remove the data plane or its capacity planning. Not every implementation supports every Extended feature, so real portability requires checking conformance. And there is genuine cost: more objects, more indirection, and a migration for every existing Ingress. For a small single-team cluster with one hostname and simple paths, Ingress remains perfectly adequate — it is frozen, not deleted, and its long install base means it will be served for years.

  • Is Ingress deprecated now that Gateway API is GA?
    No. Ingress is feature-frozen, not deprecated or scheduled for removal. Bug and security fixes continue and existing objects keep working, but new routing capability is being added to Gateway API instead. For simple single-team setups Ingress remains a reasonable choice; the pressure to migrate comes from needing features that only exist as annotations today.
  • Give a concrete case where annotations actively hurt, beyond being ugly.
    Path-rewrite annotations that accept regular expressions or raw configuration snippets let anyone who can create an Ingress influence the shared proxy's config, which has produced real cross-tenant vulnerabilities. Because annotations are unvalidated strings, admission control has to parse them defensively. Typed filters with a schema remove that whole class of problem.

saying these in an interview costs you the question

  • Saying Ingress is deprecated — it is frozen, and still supported
  • Claiming annotations are just a style issue, ignoring that they are unvalidated and non-portable
  • Believing Gateway API removes the need for a controller or data plane
  • Assuming every Gateway API implementation supports every feature — conformance is tiered into Core, Extended and Implementation-specific
  • Saying Gateway API replaces Service objects; routes still send traffic to Services

context