Skip to content

Commit a9edbb1

Browse files
authored
Merge pull request #3661 from manics/gateway
Add support for K8S Gateway API (`httpRoute` config)
2 parents de54d92 + 1db212d commit a9edbb1

File tree

8 files changed

+208
-2
lines changed

8 files changed

+208
-2
lines changed

.github/workflows/test-chart.yaml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,3 +394,92 @@ jobs:
394394
if: failure() && matrix.setup-postgresql-args
395395
run: |
396396
kubectl logs statefulset/postgresql
397+
398+
test-gateway-ingress:
399+
# The main test configures autohttps, but this conflicts with testing
400+
# ingress/gateway which assume they can directly connect to proxy-public
401+
# This is a minimal test that checks connections via a gateway is possible
402+
timeout-minutes: 20
403+
404+
strategy:
405+
# Keep running even if one variation of the job fail
406+
fail-fast: false
407+
matrix:
408+
ingress-type:
409+
- gateway
410+
- ingress
411+
412+
runs-on: ubuntu-24.04
413+
414+
steps:
415+
- uses: actions/checkout@v4
416+
with:
417+
# chartpress requires git history to set chart version and image tags
418+
# correctly
419+
fetch-depth: 0
420+
421+
# Enable Gateway API in K3s
422+
# https://github.com/k3s-io/k3s/issues/12183#issuecomment-2818989109
423+
# This will create gateway.networking.k8s.io/v1 kube-system/traefik-gateway
424+
- name: pre-configure k3s installation
425+
if: matrix.ingress-type == 'gateway'
426+
run: |
427+
sudo mkdir -p /var/lib/rancher/k3s/server/manifests
428+
sudo cp ci/traefik-config.yaml /var/lib/rancher/k3s/server/manifests/
429+
430+
# Starts a k8s cluster with NetworkPolicy enforcement and installs both
431+
# kubectl and helm
432+
#
433+
# ref: https://github.com/jupyterhub/action-k3s-helm/
434+
- uses: jupyterhub/action-k3s-helm@v4
435+
with:
436+
k3s-channel: stable
437+
metrics-enabled: false
438+
traefik-enabled: true
439+
docker-enabled: true
440+
441+
- uses: actions/setup-python@v5
442+
with:
443+
python-version: "3.11"
444+
445+
# Build our images if needed and update values.yaml with the tags
446+
- name: Install and run chartpress
447+
run: |
448+
pip3 install -r dev-requirements.txt
449+
chartpress
450+
env:
451+
DOCKER_BUILDKIT: "1"
452+
453+
- name: Install local chart (gateway)
454+
if: matrix.ingress-type == 'gateway'
455+
run: >-
456+
helm upgrade --install jupyterhub ./jupyterhub
457+
--set proxy.service.type=ClusterIP
458+
--set httpRoute.enabled=true
459+
--set httpRoute.gateway.name=traefik-gateway
460+
--set httpRoute.gateway.namespace=kube-system
461+
462+
# K3S traefik listens on host:80/443
463+
- name: Install local chart (ingress)
464+
if: matrix.ingress-type == 'ingress'
465+
run: >-
466+
helm upgrade --install jupyterhub ./jupyterhub
467+
--set proxy.service.type=ClusterIP
468+
--set ingress.enabled=true
469+
--set ingress.hosts[0]=localhost
470+
471+
- name: "Await local chart"
472+
uses: jupyterhub/action-k8s-await-workloads@v3
473+
with:
474+
timeout: 150
475+
max-restarts: 1
476+
477+
- name: Test ingress
478+
run: |
479+
curl -vL http://localhost/
480+
curl -vL http://localhost/ | grep '<title>JupyterHub</title>'
481+
482+
- name: Get traefik logs
483+
if: always()
484+
run: |
485+
kubectl -nkube-system logs deploy/traefik

ci/traefik-config.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
apiVersion: helm.cattle.io/v1
2+
kind: HelmChartConfig
3+
metadata:
4+
name: traefik
5+
namespace: kube-system
6+
spec:
7+
valuesContent: |-
8+
providers:
9+
kubernetesGateway:
10+
enabled: true
11+
gateway:
12+
listeners:
13+
web:
14+
# -- Routes are restricted to namespace of the gateway [by default](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.FromNamespaces
15+
namespacePolicy: All
16+
logs:
17+
access:
18+
enabled: true

jupyterhub/templates/NOTES.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,13 @@
6262
Try secure HTTPS access: https://{{ $host }}{{ $.Values.hub.baseUrl | trimSuffix "/" }}/
6363
{{- end }}
6464
{{- end }}
65+
{{- else if .Values.httpRoute.enabled }}
66+
{{- range $host := (.Values.httpRoute.hostnames | default (list "localhost")) }}
67+
Try insecure HTTP access: http://{{ $host }}{{ $.Values.hub.baseUrl | trimSuffix "/" }}/
68+
or secure HTTP access: https://{{ $host }}{{ $.Values.hub.baseUrl | trimSuffix "/" }}/ if supported by your Gateway
69+
{{- end }}
6570
{{- else }}
66-
You have not configured a k8s Ingress resource so you need to access the k8s
71+
You have not configured a k8s Ingress or Gateway resource so you need to access the k8s
6772
Service {{ $proxy_service }} directly.
6873
{{- println }}
6974

jupyterhub/templates/_helpers-names.tpl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,14 @@
230230
{{- end }}
231231
{{- end }}
232232

233+
{{- /* HTTPRoute */}}
234+
{{- define "jupyterhub.httpRoute.fullname" -}}
235+
{{- if (include "jupyterhub.fullname" .) }}
236+
{{- include "jupyterhub.fullname" . }}
237+
{{- else -}}
238+
jupyterhub
239+
{{- end }}
240+
{{- end }}
233241

234242

235243
{{- /*
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{{- if .Values.httpRoute.enabled -}}
2+
kind: HTTPRoute
3+
apiVersion: gateway.networking.k8s.io/v1
4+
metadata:
5+
name: {{ include "jupyterhub.httpRoute.fullname" . }}
6+
labels:
7+
{{- include "jupyterhub.labels" . | nindent 4 }}
8+
{{- with .Values.httpRoute.annotations }}
9+
annotations:
10+
{{- . | toYaml | nindent 4 }}
11+
{{- end }}
12+
spec:
13+
parentRefs:
14+
- kind: Gateway
15+
name: {{ .Values.httpRoute.gateway.name }}
16+
{{- with .Values.httpRoute.gateway.namespace }}
17+
namespace: "{{ . }}"
18+
{{- end }}
19+
{{- with .Values.httpRoute.hostnames }}
20+
hostnames:
21+
{{- . | toYaml | nindent 4 }}
22+
{{- end }}
23+
rules:
24+
- backendRefs:
25+
- name: proxy-public
26+
port: 80
27+
{{- end }}

jupyterhub/values.schema.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2790,6 +2790,47 @@ properties:
27902790
See [the Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types)
27912791
for more details about paths.
27922792
2793+
httpRoute:
2794+
type: object
2795+
additionalProperties: false
2796+
required: [enabled]
2797+
properties:
2798+
enabled:
2799+
type: boolean
2800+
description: |
2801+
Enable the creation of a Kubernetes HTTPRoute to the proxy-public service.
2802+
2803+
Requires support for the [Gateway API](https://gateway-api.sigs.k8s.io/).
2804+
2805+
A Gateway must already exist.
2806+
annotations:
2807+
type: object
2808+
additionalProperties: false
2809+
patternProperties: *labels-and-annotations-patternProperties
2810+
description: |
2811+
Annotations to apply to the HTTPRoute resource.
2812+
2813+
See [the Kubernetes
2814+
documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/)
2815+
for more details about annotations.
2816+
hostnames:
2817+
type: array
2818+
description: |
2819+
List of hosts to route requests to the proxy, if empty route all requests regardless of host.
2820+
gateway:
2821+
type: object
2822+
additionalProperties: false
2823+
required: [name]
2824+
properties:
2825+
name:
2826+
type: string
2827+
description: |
2828+
The name of your Gateway for this route.
2829+
namespace:
2830+
type: string
2831+
description: |
2832+
The namespace the Gateway is running in.
2833+
27932834
prePuller:
27942835
type: object
27952836
additionalProperties: false

jupyterhub/values.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,14 @@ ingress:
714714
tls: []
715715
extraPaths: []
716716

717+
httpRoute:
718+
enabled: false
719+
annotations: {}
720+
hostnames: []
721+
gateway:
722+
name: your-gateway
723+
namespace: "" # required for a gateway resource in another namespace
724+
717725
# cull relates to the jupyterhub-idle-culler service, responsible for evicting
718726
# inactive singleuser pods.
719727
#

tools/templates/lint-and-validate-values.yaml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ ingress:
580580
enabled: true
581581
annotations: *annotations
582582
ingressClassName: mock-ingress-class-name
583-
hosts:
583+
hosts: &ingress-hosts
584584
- mocked1.domain.name
585585
- mocked2.domain.name
586586
pathSuffix: dummy-pathSuffix
@@ -606,6 +606,16 @@ ingress:
606606
- mocked1.domain.name
607607
- mocked2.domain.name
608608

609+
httpRoute:
610+
# enabled set to false while awaiting HTTPRoute becoming available by default
611+
# in our testing infra
612+
enabled: false
613+
annotations: *annotations
614+
hostnames: *ingress-hosts
615+
gateway:
616+
name: gateway-name
617+
namespace: gateway-namespace
618+
609619
cull:
610620
enabled: true
611621
users: true

0 commit comments

Comments
 (0)