From 5faf5854cba0ede927919b0bab98fb120b2f5791 Mon Sep 17 00:00:00 2001 From: Sam Cofer Date: Fri, 5 Jun 2026 13:35:59 -0500 Subject: [PATCH] Add Contour HTTPProxy ingress example for Workbench Adds a Workbench ingress example that uses Contour's HTTPProxy CRD (rendered via extraObjects), since Contour's Ingress annotations don't expose cookie-based session affinity. The HTTPProxy wires up TLS, websockets, long timeouts, and the X-Forwarded-Proto / X-RStudio-Request headers Workbench needs behind a TLS-terminating proxy. --- examples/workbench/ingress/contour.qmd | 17 ++++ .../rstudio-workbench-contour-ingress.yaml | 88 +++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 examples/workbench/ingress/contour.qmd create mode 100644 examples/workbench/ingress/rstudio-workbench-contour-ingress.yaml diff --git a/examples/workbench/ingress/contour.qmd b/examples/workbench/ingress/contour.qmd new file mode 100644 index 000000000..e68a56f3f --- /dev/null +++ b/examples/workbench/ingress/contour.qmd @@ -0,0 +1,17 @@ +--- +category: "Ingress" +--- + +# Configuring Posit Workbench with a Contour HTTPProxy + +This example deploys Posit Workbench behind [Contour](https://projectcontour.io) using an `HTTPProxy` instead of a standard Kubernetes `Ingress`. +Contour's `Ingress` annotations don't expose cookie-based session affinity, which Workbench requires when running more than one replica, so the chart's templated `Ingress` is disabled and an `HTTPProxy` is supplied via `extraObjects`. + +The `HTTPProxy` configures TLS, websockets (required for the RStudio IDE, VS Code, Positron, and Jupyter), long timeouts so idle sessions are not torn down by Envoy, and the `X-Forwarded-Proto` / `X-RStudio-Request` headers Workbench needs to generate correct redirect URLs. + +Please visit the [Contour HTTPProxy documentation](https://projectcontour.io/docs/main/config/fundamentals/) for more details specific to your use case. + +{{< include ../_prereqs.qmd >}} + +```{.yaml include="rstudio-workbench-contour-ingress.yaml" filename="values.yaml"} +``` diff --git a/examples/workbench/ingress/rstudio-workbench-contour-ingress.yaml b/examples/workbench/ingress/rstudio-workbench-contour-ingress.yaml new file mode 100644 index 000000000..b0317efe7 --- /dev/null +++ b/examples/workbench/ingress/rstudio-workbench-contour-ingress.yaml @@ -0,0 +1,88 @@ +# Using a license file with the helm chart: +# https://github.com/rstudio/helm/tree/main/charts/rstudio-workbench#license-file +# If you would like to use a license key see this documentation: +# https://github.com/rstudio/helm/tree/main/charts/rstudio-workbench#license-key +license: + file: + secret: posit-licenses # TODO: Change to the secret name in your cluster + secretKey: workbench.lic # TODO: Change to the secret key containing your Workbench license + +# Configures user home directory shared storage +homeStorage: + create: true + mount: true + storageClassName: nfs-sc-rwx # TODO: Change to a RWX StorageClass available in your cluster + # volumeName: wb-home-pv-name # Only needed if PVs have been statically provisioned, in which case this will need to match the PV name. + requests: + storage: 100G + +# Configures Workbench shared storage +sharedStorage: + create: true + mount: true + storageClassName: nfs-sc-rwx # TODO: Change to a RWX StorageClass available in your cluster + # volumeName: wb-shared-pv-name # Only needed if PVs have been statically provisioned, in which case this will need to match the PV name. + requests: + storage: 1G + +# Contour's `Ingress` annotations don't expose cookie session affinity, so the +# chart's templated Ingress is disabled and an HTTPProxy is rendered via +# extraObjects below. Envoy talks directly to this ClusterIP service. +service: + type: ClusterIP + port: 80 + targetPort: 8787 + +ingress: + enabled: false + +extraObjects: + - | + apiVersion: projectcontour.io/v1 + kind: HTTPProxy + metadata: + name: {{ include "rstudio-workbench.fullname" . }} + labels: + {{- include "rstudio-workbench.labels" . | nindent 8 }} + spec: + virtualhost: + fqdn: workbench.example.com # TODO: Change to your domain + tls: + secretName: posit-workbench-tls # TODO: Change to the name of your secret of type kubernetes.io/tls + minimumProtocolVersion: "1.2" + routes: + - conditions: + - prefix: / + services: + - name: {{ include "rstudio-workbench.fullname" . }} + port: 80 + # Cookie-based session affinity. Required when replicas > 1. + loadBalancerPolicy: + strategy: Cookie + # Required for the RStudio IDE, VS Code, Positron, Jupyter, and the + # job-status stream. + enableWebsockets: true + # Long timeouts so idle IDE sessions are not torn down by Envoy. + timeoutPolicy: + response: 1h + idle: 1h + idleConnection: 1h + requestHeadersPolicy: + set: + - name: X-Forwarded-Proto + value: https + - name: X-RStudio-Request + value: "https://workbench.example.com%REQ(:PATH)%" # TODO: Change to your domain + +# Tells Workbench it sits behind a TLS-terminating proxy so auth redirects use +# https://. The HTTPProxy above sets X-Forwarded-Proto and X-RStudio-Request. +config: + server: + rserver.conf: + ssl-enabled: 0 + www-frame-origin: same + secret: + database.conf: + provider: "postgresql" + connection-uri: "postgres://@:/?sslmode=require" # TODO: Change this URI to reach your Postgres database. + password: "" # TODO: Remove this line and instead set the password during helm install with --set config.secret.database\.conf.password=.