Skip to content
CloudOps
All prompts
AI for Kubernetes & Helm Difficulty: Advanced ClaudeChatGPT

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

  1. For design: clarify ownership boundaries before writing YAML.
  2. For migration: map Ingress fields to Gateway API fields one-by-one.
  3. For debugging: read each object’s status.conditionsAccepted, Programmed, ResolvedRefs.
  4. 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 traffichostname mismatch between Listener and HTTPRoute.
  • allowedRoutes restricts namespaces → Route in other ns can’t attach; relax or move.
  • Mixing regularexpression paths when controller only supports Exact/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

Newsletter

Get weekly AI workflows for DevOps engineers

Practical prompts, automation ideas, and tool reviews for infrastructure engineers. One email per week. No spam.