Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion deploy/helm/jumpstarter/charts/jumpstarter-controller/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ class Grpc1(BaseModel):
None, description="Hostname for the controller to use for the controller gRPC"
)
routerHostname: Optional[str] = Field(
None, description="Hostname for the controller to use for the controller gRPC"
None, description="Hostname for the router to use for the router gRPC"
)
endpoint: Optional[str] = Field(
None,
Expand All @@ -243,13 +243,24 @@ class Grpc1(BaseModel):
None,
description="The endpoints are passed down to the services to know where to announce the endpoints to the clients",
)
additionalRouters: dict[str, Router] | None = Field(
None, description="Additional routers to deploy"
)
ingress: Optional[Ingress] = None
route: Optional[Route] = None
nodeport: Optional[Nodeport] = None
mode: Optional[Mode] = None
tls: Optional[Tls] = None


class Router(BaseModel):
model_config = ConfigDict(extra="forbid")
hostname: str | None = None
endpoint: str | None = None
labels: dict[str, str] | None = None
nodeSelector: dict[str, str] | None = None


class Model(BaseModel):
model_config = ConfigDict(extra="forbid")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{{ range $k, $v := .Values.grpc.additionalRouters }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jumpstarter-router-{{ $k }}
namespace: {{ default $.Release.Namespace $.Values.namespace }}
labels:
control-plane: controller-router-{{ $k }}
app.kubernetes.io/name: jumpstarter-controller
{{ if $.Values.global.timestamp }}
deployment.timestamp: {{ $.Values.global.timestamp | quote }}
{{ end }}
annotations:
argocd.argoproj.io/sync-wave: "1"
spec:
selector:
matchLabels:
control-plane: controller-router-{{ $k }}
replicas: 1
template:
metadata:
annotations:
kubectl.kubernetes.io/default-container: router
configmap-sha256: {{ include (print $.Template.BasePath "/cms/controller-cm.yaml") $ | sha256sum }}
labels:
control-plane: controller-router-{{ $k }}
{{ if $.Values.global.timestamp }}
deployment.timestamp: {{ $.Values.global.timestamp | quote }}
{{ end }}
spec:
# TODO(user): Uncomment the following code to configure the nodeAffinity expression
# according to the platforms which are supported by your solution.
# It is considered best practice to support multiple architectures. You can
# build your manager image using the makefile target docker-buildx.
# affinity:
# nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# nodeSelectorTerms:
# - matchExpressions:
# - key: kubernetes.io/arch
# operator: In
# values:
# - amd64
# - arm64
# - ppc64le
# - s390x
# - key: kubernetes.io/os
# operator: In
# values:
# - linux
{{ if $v.nodeSelector }}
nodeSelector:
{{ $v.nodeSelector | toYaml | indent 1 }}
{{ end }}
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- command:
- /router
env:
- name: GRPC_ROUTER_ENDPOINT
{{ if $v.endpoint }}
value: {{ $v.endpoint }}
{{ else if $v.hostname }}
value: {{ $v.hostname }}:{{ default 443 $.Values.grpc.tls.port }}
{{ else }}
value: router-{{ $k }}.{{ $.Values.global.baseDomain | required "set .global.baseDomain, or provide grpc.additionalRouters[...].endpoint/hostname" }}:{{ default 443 $.Values.grpc.tls.port }}
{{ end }}
- name: ROUTER_KEY
valueFrom:
secretKeyRef:
name: jumpstarter-router-secret
key: key
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace

image: {{ $.Values.image }}:{{ default $.Chart.AppVersion $.Values.tag }}
imagePullPolicy: {{ $.Values.imagePullPolicy }}
name: router
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- "ALL"
# livenessProbe:
# httpGet:
# path: /healthz
# port: 8081
# initialDelaySeconds: 15
# periodSeconds: 20
# readinessProbe:
# httpGet:
# path: /readyz
# port: 8081
# initialDelaySeconds: 5
# periodSeconds: 10
resources:
limits:
cpu: 2000m
memory: 1024Mi
requests:
cpu: 1000m
memory: 256Mi
Comment on lines +102 to +108

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must find the way to make this configurable at some point, the routers actually need very little. But seems like an ok default.

serviceAccountName: controller-manager
terminationGracePeriodSeconds: 10
{{ end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{{ if eq .Values.grpc.mode "ingress" }}
{{ range $k, $v := .Values.grpc.additionalRouters }}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
{{ if eq $.Values.grpc.tls.mode "passthrough" }}
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
{{ end }}
Comment on lines +12 to +14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Don't set a TLS secret when ssl-passthrough is enabled.

With NGINX ssl-passthrough, a secret must not be provided; doing so breaks TLS handshake at the ingress.

-  tls:
+  tls:
   - hosts:
       {{ if $v.hostname }}
       - {{ $v.hostname }}
       {{ else }}
       - router-{{ $k }}.{{ $.Values.global.baseDomain | required "a global.baseDomain or a grpc.routerHostname must be provided"}}
       {{ end }}
-    {{ if $.Values.grpc.tls.routerCertSecret }}
-    secretName: {{ $.Values.grpc.tls.routerCertSecret }}
-    {{ end }}
+    {{ if and $.Values.grpc.tls.routerCertSecret (ne $.Values.grpc.tls.mode "passthrough") }}
+    secretName: {{ $.Values.grpc.tls.routerCertSecret }}
+    {{ end }}

Also applies to: 36-45

🤖 Prompt for AI Agents
In
deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/additional-router-ingress.yaml
around lines 12-14 (and similarly lines 36-45), the template always sets a TLS
secret even when nginx ssl-passthrough is enabled, which breaks the TLS
handshake; update the template logic to omit the tls.secretName (and any tls
block) when $.Values.grpc.tls.mode == "passthrough" by wrapping the tls stanza
or secretName output in a conditional that only renders when mode is not
"passthrough".

name: jumpstarter-router-ingress-{{ $k }}
namespace: {{ default $.Release.Namespace $.Values.namespace }}
spec:
{{ if $.Values.grpc.ingress.class }}
ingressClassName: {{ $.Values.grpc.ingress.class }}
{{ end }}
rules:
{{ if $v.hostname }}
- host: {{ $v.hostname }}
{{ else }}
- host: router-{{ $k }}.{{ $.Values.global.baseDomain | required "a global.baseDomain or a grpc.routerHostname must be provided"}}
{{ end }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jumpstarter-router-grpc-{{ $k }}
port:
number: 8083
tls:
- hosts:
{{ if $v.hostname }}
- {{ $v.hostname }}
{{ else }}
- router-{{ $k }}.{{ $.Values.global.baseDomain | required "a global.baseDomain or a grpc.routerHostname must be provided"}}
{{ end }}
{{ if $.Values.grpc.tls.routerCertSecret }}
secretName: {{ $.Values.grpc.tls.routerCertSecret }}
{{ end }}
{{ end }}
{{ end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{{ if eq .Values.grpc.mode "route" }}
{{ range $k, $v := .Values.grpc.additionalRouters }}
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
labels:
external-exposed: "true"
shard: external
annotations:
haproxy.router.openshift.io/timeout: 2d
haproxy.router.openshift.io/timeout-tunnel: 2d
name: jumpstarter-router-route-{{ $k }}
namespace: {{ default $.Release.Namespace $.Values.namespace }}
spec:
{{ if $v.hostname }}
host: {{ $v.hostname }}
{{ else }}
host: router-{{ $k }}.{{ $.Values.global.baseDomain | required "a global.baseDomain or a grpc.routerHostname must be provided"}}
{{ end }}
port:
targetPort: 8083
tls:
{{ if eq $.Values.grpc.tls.mode "passthrough" }}
termination: passthrough
{{ end }}
{{ if eq $.Values.grpc.tls.mode "reencrypt" }}
termination: reencrypt
{{ end }}
insecureEdgeTerminationPolicy: None
{{ if $.Values.grpc.tls.routerCertSecret }}
externalCertificate:
name: {{ $.Values.grpc.tls.routerCertSecret }}
{{ end }}
Comment thread
NickCao marked this conversation as resolved.

to:
kind: Service
name: jumpstarter-router-grpc-{{ $k }}
weight: 100
wildcardPolicy: None
{{ end }}
{{ end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{{ range $k, $v := .Values.grpc.additionalRouters }}
---
apiVersion: v1
kind: Service
metadata:
labels:
control-plane: controller-router-{{ $k }}
app.kubernetes.io/name: jumpstarter-controller
name: jumpstarter-router-grpc-{{ $k }}
namespace: {{ default $.Release.Namespace $.Values.namespace }}
spec:
{{ if .Values.grpc.nodeport.enabled }}
type: NodePort
{{ end }}

ports:
- name: grpc
port: 8083
protocol: TCP
targetPort: 8083
appProtocol: h2c # HTTP/2 over cleartext for gRPC (fixes edge termination in ingress/router)
{{ if .Values.grpc.nodeport.enabled }}
nodePort: {{ .Values.grpc.nodeport.routerPort }}
{{ end }}
selector:
control-plane: controller-router-{{ $k }}
{{ end }}
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,17 @@ data:
{{ else }}
endpoint: router.{{ .Values.global.baseDomain }}:{{ .Values.grpc.tls.port }}
{{ end }}
{{ range $k, $v := .Values.grpc.additionalRouters }}
{{ $k }}:
{{ if $v.endpoint }}
endpoint: {{ $v.endpoint }}
{{ else if $v.hostname }}
endpoint: {{ $v.hostname }}:{{ $.Values.grpc.tls.port }}
{{ else }}
endpoint: router-{{ $k }}.{{ $.Values.global.baseDomain }}:{{ $.Values.grpc.tls.port }}
{{ end }}
{{ if $v.labels }}
labels:
{{ $v.labels | toYaml | indent 1 }}
{{ end }}
{{ end }}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ metadata:
deployment.timestamp: {{ .Values.global.timestamp | quote }}
{{ end }}
annotations:
configmap-sha256: {{ include (print $.Template.BasePath "/cms/controller-cm.yaml") . | sha256sum }}
argocd.argoproj.io/sync-wave: "1"
spec:
selector:
Expand All @@ -21,6 +20,7 @@ spec:
metadata:
annotations:
kubectl.kubernetes.io/default-container: manager
configmap-sha256: {{ include (print $.Template.BasePath "/cms/controller-cm.yaml") . | sha256sum }}
labels:
control-plane: controller-manager
{{ if .Values.global.timestamp }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ metadata:
labels:
app.kubernetes.io/name: jumpstarter-router
name: leader-election-role
namespace: {{ .Values.namespace }}
namespace: {{ default .Release.Namespace .Values.namespace }}
rules:
- apiGroups:
- ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ kind: RoleBinding
metadata:
labels:
app.kubernetes.io/name: jumpstarter-router
namespace: {{ .Values.namespace }}
namespace: {{ default .Release.Namespace .Values.namespace }}
name: leader-election-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
Expand All @@ -12,4 +12,4 @@ roleRef:
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: {{ .Values.namespace }}
namespace: {{ default .Release.Namespace .Values.namespace }}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ metadata:
deployment.timestamp: {{ .Values.global.timestamp | quote }}
{{ end }}
annotations:
configmap-sha256: {{ include (print $.Template.BasePath "/cms/controller-cm.yaml") . | sha256sum }}
argocd.argoproj.io/sync-wave: "1"
spec:
selector:
Expand All @@ -21,6 +20,7 @@ spec:
metadata:
annotations:
kubectl.kubernetes.io/default-container: router
configmap-sha256: {{ include (print $.Template.BasePath "/cms/controller-cm.yaml") . | sha256sum }}
labels:
control-plane: controller-router
{{ if .Values.global.timestamp }}
Expand Down
Loading
Loading