Gateway api resources#865
Conversation
* feat: add consistent, off-by-default, gatewayAPI configuration options * fix: versions and docs
|
Hi folks, I'm happy to iterate as requested. |
jaygalvin
left a comment
There was a problem hiding this comment.
Hi Adam, thanks for this PR! I came here to add a kgateway example, but you beat me to it, AND added support for Gateway API to the chart.
Tested the kgateway track end-to-end on EKS (k8s 1.35, kgateway v2.2.4, AWS LB Controller v2.11) against a real Workbench release installed from this branch. The chart-native gatewayApi flow works well: the rendered HTTPRoute attached cross-namespace to the shared posit-shared Gateway in kgateway-system (Accepted + ResolvedRefs, listener attachedRoutes=1), kgateway's defaults provisioned an internal NLB, and HTTP routing to Workbench worked (GET / → 302 → sign-in page).
One gap worth addressing for the Posit-product use case: kgateway rejects WebSocket upgrades by default, and nothing in the HTTPRoute the chart renders can change that. Workbench and Connect interactive sessions (RStudio, Jupyter, VS Code, Shiny, Dash, Streamlit) all rely on websockets, so the example as-is will route the UI but break sessions.
Reproduced cleanly with an echo backend behind a bare HTTPRoute identical in shape to the chart's output (same gateway, same upgrade headers):
| Config | Plain HTTP | WebSocket upgrade |
|---|---|---|
Bare HTTPRoute, no policy |
200 |
403 Forbidden |
+ HTTPListenerPolicy{upgradeConfig: [websocket]} on the Gateway |
200 |
101 Switching Protocols |
Adding the policy flipped the same route from 403 → 101, so it's specifically the upgrade that's gated.
Since the policy targets the Gateway, a single one covers every product attached to the shared gateway. Suggest adding it to examples/gateway-api/kgateway/ (e.g. a httplistenerpolicy.yaml) and referencing it from the README:
apiVersion: gateway.kgateway.dev/v1alpha1
kind: HTTPListenerPolicy
metadata:
name: posit-shared-ws
namespace: kgateway-system
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: posit-shared
upgradeConfig:
enabledUpgrades:
- websocket
# Optional: don't drop idle interactive sessions.
streamIdleTimeout: "0s"Beyond WebSockets, three more Envoy behaviors that the bare HTTPRoute doesn't cover matter for these products. Each is a kgateway policy CRD that targets the Gateway, HTTPRoute, or Service — no change to the rendered route. Applicability:
| Knob | Resource → target | Workbench | Connect | Package Manager |
|---|---|---|---|---|
| WebSocket upgrades | HTTPListenerPolicy → Gateway |
Required | Required | – |
| Request / stream-idle timeout | TrafficPolicy → HTTPRoute |
Required | Required | Recommended |
| Buffer disable (large uploads) | TrafficPolicy → HTTPRoute |
Recommended | Required | Required |
| Session-affinity cookie | BackendConfigPolicy → Service |
multi-replica | multi-replica | – |
Timeouts + large uploads — Envoy's defaults (15s request, 5m stream-idle, and the request-body buffer cap) cut off long sessions/transfers and return 413 on big Connect bundles or PM packages. Gateway API has HTTPRoute.rules[].timeouts, but the gatewayApi values block doesn't render it — so the no-chart-change path is a TrafficPolicy targeting the chart's route by its generated name (<fullname>-gw-<index>). Timeouts and buffer can share one policy:
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
name: posit-connect-traffic
namespace: <release-namespace>
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: posit-connect-rstudio-connect-gw-0 # kubectl get httproute -n <ns>
timeouts:
request: "0s" # disable per-request timeout (or set a finite bound, e.g. "3600s")
streamIdle: "0s"
buffer:
disable: {} # stream large bodies instead of buffering (or buffer.maxRequestSize)Session affinity (only when replicas > 1) — Workbench/Connect keep per-user state on the serving pod, so users must stick to one backend. A BackendConfigPolicy on the Service does consistent-hash LB on a cookie kgateway sets:
apiVersion: gateway.kgateway.dev/v1alpha1
kind: BackendConfigPolicy
metadata:
name: posit-workbench-affinity
namespace: <release-namespace>
spec:
targetRefs:
- group: ""
kind: Service
name: posit-workbench-rstudio-workbench
loadBalancer:
ringHash:
hashPolicies:
- cookie: { name: posit-workbench-affinity, path: /, ttl: 86400s }
terminal: trueVerification notes (all on kgateway v2.2.4): WebSocket 403→101 and the affinity-cookie Set-Cookie … HttpOnly confirmed end-to-end; the combined TrafficPolicy (timeouts + buffer in one resource) reported Accepted/Attached, and the request timeout was functionally enforced against a delaying backend — request: "3s" returned 504 at 3.01s while a fast request passed, and request: "0s" let an 8s request complete (200). BackendConfigPolicy reported Accepted/Attached.
Happy to open a follow-up PR adding the HTTPListenerPolicy to examples/gateway-api/kgateway/ plus a "tuning for Posit products" section covering the above.
Uh oh!
There was an error while loading. Please reload this page.