Kubernetes Gateway API Design & Debug Prompt
Design and debug Gateway API resources — GatewayClass, Gateway, HTTPRoute, ReferenceGrant — and migrate from Ingress to Gateway API.
- Target user
- Kubernetes platform engineers adopting Gateway API
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT
The prompt
You are a senior Kubernetes engineer who has migrated production Ingress workloads to Gateway API. You know the role split (GatewayClass: infra; Gateway: cluster operator; HTTPRoute: app team) and the cross-namespace ReferenceGrant model. I will provide: - The goal: design Gateway API config / migrate from Ingress / debug an existing Gateway API setup - Gateway controller in use (Istio, Cilium, NGINX, Contour, GKE Gateway, etc.) - Current Ingress resources (if migrating) - For debugging: GatewayClass, Gateway, and HTTPRoute objects + their statuses Your job: 1. **Understand the role split**: - **GatewayClass** — defines an implementation (e.g., `istio`, `cilium`, `nginx`). Infra team owns. - **Gateway** — instance of a class with listeners. Cluster ops team typically owns. References GatewayClass. - **HTTPRoute** — request matching + backendRefs. App teams own. References parent Gateway. - **ReferenceGrant** — explicit cross-namespace permission. Required for routes referencing Services / Gateways in other namespaces. 2. **Listeners on Gateway**: - Each Listener has: name, port, protocol (HTTP, HTTPS, TLS, TCP), hostname (optional), allowedRoutes (selector for which Routes can bind) - Multiple Listeners on one Gateway for multi-port / multi-hostname - HTTPS requires `tls.certificateRefs` to a Secret (or third-party like cert-manager via Gateway integration) 3. **HTTPRoute matching**: - `parentRefs` — Gateway(s) this Route attaches to - `hostnames` — list (intersected with the Gateway listener's hostname) - `rules` — list of (matches, filters, backendRefs) - `matches` — path (`PathPrefix`, `Exact`, `RegularExpression`), method, headers, query params - First-match-wins? No — precedence is by specificity (exact > prefix > shorter, then header count, etc. per spec) 4. **Status fields** (essential for debugging): - **Gateway**: `Accepted=True`, `Programmed=True`, listener-level conditions - **HTTPRoute**: per-parent-status `Accepted`, `ResolvedRefs` - `ResolvedRefs=False` → a backendRef doesn't exist or cross-NS without ReferenceGrant 5. **For cross-namespace routing**: - Route in `ns-a` wants to send traffic to Service in `ns-b` - Requires `ReferenceGrant` in `ns-b` allowing `ns-a` to reference the Service - Without it, `ResolvedRefs=False` and traffic returns 500 6. **For Gateway not programmed**: - Check GatewayClass `Accepted=True` (controller acknowledged it) - Gateway's `ParentRefs` to GatewayClass match - Controller pods running and logs clean 7. **For migrating from Ingress**: - 1 Ingress = 1 Gateway + 1 HTTPRoute (rough mapping) - Class annotation → `parentRefs` to a Gateway - `host:` → `hostnames:` - `paths` → `matches:` with `path:` - TLS Secret → Gateway listener's `tls.certificateRefs` - `ingressClassName` → `GatewayClassName` on Gateway - Backends — same Service refs - Path rewrite annotations (controller-specific in Ingress) → `URLRewrite` filter in HTTPRoute 8. **Controller-specific extensions**: - GEP (Gateway Enhancement Proposal) features may be experimental per controller - Common: ExtensionRefs for custom filters (rate limiting, auth) Mark DESTRUCTIVE: replacing an Ingress with a Gateway without overlap window (brief gap in traffic), deleting a Gateway with active connections, changing GatewayClass on a running Gateway. --- Goal: [design / migrate / debug] Gateway controller: [Istio / Cilium / NGINX / Contour / GKE / AWS Gateway API] Current Ingress resources (if migrating): ```yaml [PASTE] ``` Existing Gateway API objects (if debugging): ```yaml [PASTE Gateway, HTTPRoute, ReferenceGrant] ``` Statuses (`kubectl get gateway -o yaml | yq '.status'`, same for HTTPRoute): ``` [PASTE] ``` Controller logs (last 50 lines): ``` [PASTE] ```
Why this prompt works
Gateway API is a role-split replacement for Ingress with more rigorous separation: GatewayClass (infra), Gateway (ops), HTTPRoute (app). Each has its own status, and ReferenceGrant adds explicit cross-NS permission. This prompt walks the model so you don’t conflate roles.
How to use it
- For design: clarify ownership boundaries before writing YAML.
- For migration: map Ingress fields to Gateway API fields one-by-one.
- For debugging: read each object’s
status.conditions—Accepted,Programmed,ResolvedRefs. - For cross-NS routing: ReferenceGrant is not optional in practice.
Useful commands
# Inventory
kubectl get gatewayclass
kubectl get gateway -A
kubectl get httproute -A
kubectl get referencegrant -A
# Status
kubectl get gateway <name> -n <ns> -o yaml | yq '.status'
kubectl get httproute <name> -n <ns> -o yaml | yq '.status'
# Describe (shows conditions in readable form)
kubectl describe gateway <name>
kubectl describe httproute <name>
# Controller logs
kubectl -n <ctlr-ns> logs deploy/<controller>
# Migrate-aware tooling
kubectl ingress2gateway print --providers nginx -f my-ingress.yaml # experimental
Design patterns
Single Gateway, multiple HTTPRoutes
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: nginx
spec:
controllerName: gateway.nginx.org/nginx-gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: prod-gateway
namespace: gateway-system
spec:
gatewayClassName: nginx
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: https
port: 443
protocol: HTTPS
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: wildcard-tls
namespace: gateway-system
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
allow-routes: "true"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web
namespace: web
spec:
parentRefs:
- name: prod-gateway
namespace: gateway-system
hostnames:
- "web.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: web
port: 80
Cross-namespace with ReferenceGrant
# Route in app-ns references Service in svc-ns
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api
namespace: app-ns
spec:
parentRefs:
- name: prod-gateway
namespace: gateway-system
rules:
- backendRefs:
- name: api
namespace: svc-ns # cross-NS!
port: 8080
---
# In svc-ns: grant permission
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-app-routes
namespace: svc-ns
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app-ns
to:
- group: ""
kind: Service
Path-based routing with rewrite
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api
spec:
parentRefs:
- name: prod-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /api/v1
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: api
port: 8080
Ingress → Gateway migration
# OLD: Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: web.example.com
http:
paths:
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: api
port: { number: 8080 }
tls:
- hosts: [web.example.com]
secretName: web-tls
# NEW: Gateway + HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web
spec:
parentRefs:
- name: prod-gateway
hostnames: [web.example.com]
rules:
- matches:
- path:
type: PathPrefix
value: /api
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: api
port: 8080
Common findings this catches
- Gateway
Programmed=False→ controller can’t realize it; controller logs. - HTTPRoute
ResolvedRefs=False→ backend Service doesn’t exist or cross-NS without ReferenceGrant. - Route attached but no traffic →
hostnamemismatch between Listener and HTTPRoute. allowedRoutesrestricts namespaces → Route in other ns can’t attach; relax or move.- Mixing
regularexpressionpaths when controller only supportsExact/PathPrefix→ spec validation fails. - TLS Secret in different ns without ReferenceGrant → cert not loaded.
- Migration leaves orphan Ingress still serving traffic → double-routed; remove Ingress after Gateway works.
When to escalate
- Controller-specific extensions / GEPs in flight — engage controller maintainers; spec may shift.
- Gateway API + service mesh interaction (Istio Gateway API support) — mesh-specific docs.
- Performance regression after migration — capture metrics for both sides; compare LB latency.
Related prompts
-
Kubernetes Ingress Troubleshooting Prompt
Diagnose Ingress routing failures, controller misconfiguration, TLS issues, 404/502/503 cascades, and path-vs-host mismatches across NGINX, Traefik, Contour, and HAProxy controllers.
-
Kubernetes NetworkPolicy Debug Prompt
Diagnose why pod-to-pod, pod-to-service, or pod-to-external traffic is being dropped by NetworkPolicy — Calico, Cilium, Weave, or upstream defaults.
-
Kubernetes Istio Service Mesh Debugging Prompt
Diagnose Istio service mesh issues — sidecar injection failures, mTLS misconfiguration, traffic routing, AuthorizationPolicy denials, Envoy config errors.