From 342ba3a02a56d44173b10c21138e5c5d559f4893 Mon Sep 17 00:00:00 2001 From: alhendrickson Date: Thu, 30 Apr 2026 15:50:22 +0000 Subject: [PATCH 1/2] feat(helm): Add Jupyterhub ServiceMonitor --- .../templates/_helpers.tpl | 63 +++++++++++++++++++ .../templates/servicemonitor.yaml | 25 ++++++++ .../cogstack-jupyterhub-helm/values.yaml | 30 ++++++++- helm-charts/medcat-trainer-helm/values.yaml | 1 + 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 helm-charts/cogstack-jupyterhub-helm/templates/_helpers.tpl create mode 100644 helm-charts/cogstack-jupyterhub-helm/templates/servicemonitor.yaml diff --git a/helm-charts/cogstack-jupyterhub-helm/templates/_helpers.tpl b/helm-charts/cogstack-jupyterhub-helm/templates/_helpers.tpl new file mode 100644 index 0000000..a55c32b --- /dev/null +++ b/helm-charts/cogstack-jupyterhub-helm/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "cogstack-jupyterhub-helm.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "cogstack-jupyterhub-helm.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- $basename := $name | trimSuffix "-helm" }} +{{- if or (contains $name .Release.Name) (eq .Release.Name $basename) }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "cogstack-jupyterhub-helm.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cogstack-jupyterhub-helm.labels" -}} +helm.sh/chart: {{ include "cogstack-jupyterhub-helm.chart" . }} +{{ include "cogstack-jupyterhub-helm.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/part-of: cogstack +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "cogstack-jupyterhub-helm.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cogstack-jupyterhub-helm.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +ServiceMonitor selector labels for the jupyterhub hub Service. +This intentionally mirrors the JupyterHub chart's hub service labels. +*/}} +{{- define "jupyterhub.hubMatchLabels" -}} +component: {{ "hub" | quote }} +app: {{ "jupyterhub" | quote }} +release: {{ .Release.Name | quote }} +{{- end -}} diff --git a/helm-charts/cogstack-jupyterhub-helm/templates/servicemonitor.yaml b/helm-charts/cogstack-jupyterhub-helm/templates/servicemonitor.yaml new file mode 100644 index 0000000..cc8d7d7 --- /dev/null +++ b/helm-charts/cogstack-jupyterhub-helm/templates/servicemonitor.yaml @@ -0,0 +1,25 @@ +{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "cogstack-jupyterhub-helm.fullname" . }}-hub + namespace: {{ .Release.Namespace }} + labels: + {{- include "cogstack-jupyterhub-helm.labels" . | nindent 4 }} + {{- with .Values.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "jupyterhub.hubMatchLabels" . | nindent 6 }} + endpoints: + - port: {{ .Values.serviceMonitor.port }} + interval: {{ .Values.serviceMonitor.interval }} + path: {{ .Values.serviceMonitor.path }} + scheme: {{ .Values.serviceMonitor.scheme }} + {{- with .Values.serviceMonitor.tlsConfig }} + tlsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/helm-charts/cogstack-jupyterhub-helm/values.yaml b/helm-charts/cogstack-jupyterhub-helm/values.yaml index ff90d70..734df1d 100644 --- a/helm-charts/cogstack-jupyterhub-helm/values.yaml +++ b/helm-charts/cogstack-jupyterhub-helm/values.yaml @@ -1,4 +1,4 @@ -# Default values for the community jupyterhub helm chart +# Values for the community jupyterhub helm chart jupyterhub: hub: image: @@ -43,6 +43,18 @@ jupyterhub: }) # Allow root in notebooks c.KubeSpawner.args = ['--allow-root'] + # -- Allow /hub/metrics to be scraped without authentication + 01-prometheus-authentication: | + c.JupyterHub.authenticate_prometheus = False + networkPolicy: + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: prometheus + ports: + - protocol: TCP + port: http proxy: service: type: ClusterIP @@ -111,3 +123,19 @@ jupyterhub: enabled: false continuous: enabled: false + +# -- Create a Prometheus ServiceMonitor for jupyterhub. Requires the Prometheus Operator to be installed +serviceMonitor: + # -- Set to true to enable creation of a ServiceMonitor resource + enabled: false + # -- HTTP path where metrics are exposed. + path: /hub/metrics + # -- Scheme to use for scraping. + scheme: http + # -- Frequency at which Prometheus will scrape metrics. + interval: 30s + # -- Named port the serviceMonitor will scrape. + port: hub + # -- Additional labels to be added to the ServiceMonitor + labels: {} + tlsConfig: {} diff --git a/helm-charts/medcat-trainer-helm/values.yaml b/helm-charts/medcat-trainer-helm/values.yaml index cff1570..428c883 100644 --- a/helm-charts/medcat-trainer-helm/values.yaml +++ b/helm-charts/medcat-trainer-helm/values.yaml @@ -129,6 +129,7 @@ postgresql: repository: bitnamilegacy/postgresql # Pin legacy version of postgresql following bitnami change to remove free images. Match prefect version tag: 17.6.0-debian-12-r4 + fullnameOverride: "medcat-trainer-postgresql" persistence: media: From 77b4bca1f729ba8cb88a45ba89e8c2fef5ba7749 Mon Sep 17 00:00:00 2001 From: alhendrickson Date: Thu, 30 Apr 2026 15:52:02 +0000 Subject: [PATCH 2/2] feat(helm): Add Jupyterhub ServiceMonitor --- helm-charts/cogstack-jupyterhub-helm/README.md | 18 ++++++++++++++---- .../cogstack-jupyterhub-helm/values.yaml | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/helm-charts/cogstack-jupyterhub-helm/README.md b/helm-charts/cogstack-jupyterhub-helm/README.md index 7e8e493..aef2588 100644 --- a/helm-charts/cogstack-jupyterhub-helm/README.md +++ b/helm-charts/cogstack-jupyterhub-helm/README.md @@ -58,7 +58,7 @@ jupyterhub: The default configuration uses the JupyterHub `DummyAuthenticator` (not for production). -One option for you may be to setup the FirstUseAuthenticator. This will let any new user login and set their own passwords. +One option for you may be to setup the FirstUseAuthenticator. This will let any new user login and set their own passwords. ```yaml jupyterhub: @@ -100,11 +100,14 @@ See [Enabling OIDC Authentication](https://github.com/CogStack/cogstack-jupyter- | jupyterhub.hub.config.KubeSpawner.uid | int | `0` | | | jupyterhub.hub.config.Spawner.default_url | string | `"/lab/"` | | | jupyterhub.hub.config.Spawner.notebook_dir | string | `"/home/jovyan/work"` | | -| jupyterhub.hub.extraConfig | object | `{"00-custom-spawner":"# Custom environment variables for user pods\nc.KubeSpawner.environment = {\n 'GRANT_SUDO': '1',\n 'CHOWN_HOME': 'yes',\n 'CHOWN_HOME_OPTS': '-R',\n}\n# Allow root in notebooks\nc.KubeSpawner.args = ['--allow-root']\n"}` | Extra hub configuration for custom spawner settings | -| jupyterhub.hub.extraConfig.00-log-level | string | `"c.Application.log_level = 'DEBUG'\n"` | | +| jupyterhub.hub.extraConfig | object | `{"00-custom-spawner":"# Custom environment variables for user pods\nc.KubeSpawner.environment = c.KubeSpawner.environment or {}\nc.KubeSpawner.environment.update({\n 'GRANT_SUDO': '1',\n 'CHOWN_HOME': 'yes',\n 'CHOWN_HOME_OPTS': '-R',\n})\n# Allow root in notebooks\nc.KubeSpawner.args = ['--allow-root']\n","00-log-level":"c.Application.log_level = 'DEBUG'\n","01-prometheus-authentication":"c.JupyterHub.authenticate_prometheus = False\n"}` | Extra hub configuration for custom spawner settings | +| jupyterhub.hub.extraConfig.01-prometheus-authentication | string | `"c.JupyterHub.authenticate_prometheus = False\n"` | Allow /hub/metrics to be scraped without authentication | | jupyterhub.hub.image.name | string | `"cogstacksystems/jupyter-hub"` | Image repository for the JupyterHub hub. | | jupyterhub.hub.image.pullPolicy | string | `"IfNotPresent"` | Pull policy for the JupyterHub hub. | | jupyterhub.hub.image.tag | string | `"2.2.2"` | Image tag for the JupyterHub hub. | +| jupyterhub.hub.networkPolicy.ingress[0].from[0].podSelector.matchLabels."app.kubernetes.io/name" | string | `"prometheus"` | | +| jupyterhub.hub.networkPolicy.ingress[0].ports[0].port | string | `"http"` | | +| jupyterhub.hub.networkPolicy.ingress[0].ports[0].protocol | string | `"TCP"` | | | jupyterhub.prePuller.continuous.enabled | bool | `false` | | | jupyterhub.prePuller.hook | object | `{"enabled":false}` | Enable pulling the singleuser image before they are used to improve startup time | | jupyterhub.proxy.service.type | string | `"ClusterIP"` | | @@ -124,6 +127,13 @@ See [Enabling OIDC Authentication](https://github.com/CogStack/cogstack-jupyter- | jupyterhub.singleuser.storage.extraVolumeMounts.jupyter-examples.readOnly | bool | `true` | | | jupyterhub.singleuser.storage.extraVolumes | object | `{"jupyter-examples":{"configMap":{"name":"jupyter-examples"},"name":"jupyter-examples"}}` | NOTE: Prefer dictionary-form here to avoid Helm merge issues when this subchart is configured by a parent chart. | | jupyterhub.singleuser.uid | int | `0` | | +| serviceMonitor | object | `{"enabled":false,"interval":"30s","labels":{},"path":"/hub/metrics","port":"hub","scheme":"http","tlsConfig":{}}` | Create a Prometheus ServiceMonitor for the JupyterHub. Requires the Prometheus Operator to be installed | +| serviceMonitor.enabled | bool | `false` | Set to true to enable creation of a ServiceMonitor resource | +| serviceMonitor.interval | string | `"30s"` | Frequency at which Prometheus will scrape metrics. | +| serviceMonitor.labels | object | `{}` | Additional labels to be added to the ServiceMonitor | +| serviceMonitor.path | string | `"/hub/metrics"` | HTTP path where metrics are exposed. | +| serviceMonitor.port | string | `"hub"` | Named port the serviceMonitor will scrape. | +| serviceMonitor.scheme | string | `"http"` | Scheme to use for scraping. | ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2) +Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2) \ No newline at end of file diff --git a/helm-charts/cogstack-jupyterhub-helm/values.yaml b/helm-charts/cogstack-jupyterhub-helm/values.yaml index 734df1d..ba45d72 100644 --- a/helm-charts/cogstack-jupyterhub-helm/values.yaml +++ b/helm-charts/cogstack-jupyterhub-helm/values.yaml @@ -124,7 +124,7 @@ jupyterhub: continuous: enabled: false -# -- Create a Prometheus ServiceMonitor for jupyterhub. Requires the Prometheus Operator to be installed +# -- Create a Prometheus ServiceMonitor for the JupyterHub. Requires the Prometheus Operator to be installed serviceMonitor: # -- Set to true to enable creation of a ServiceMonitor resource enabled: false