From 5126c2cdd6862a15c0b448f18ef4d51dd2437795 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Fri, 5 Jun 2026 11:38:01 +0100 Subject: [PATCH 1/4] docs: make values.yaml image references explicit and unambiguous Add an image reference map and per-site precedence notes so it is clear which image launches each pod, how profile image overrides resolve, how the nebi binary image is derived, and which tags bump_image_tags.py syncs. --- values.yaml | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/values.yaml b/values.yaml index 8a110d0..4097576 100644 --- a/values.yaml +++ b/values.yaml @@ -19,6 +19,17 @@ # * nebari-operator runs in the cluster and provisions the OIDC client # # ============================================================================= +# IMAGE REFERENCE MAP +# ============================================================================= +# Lab pod image (highest wins): profile_options.image.choices..image > +# profiles[N].kubespawner_override.image > singleuser.image (fallback, only +# when profiles == []). display_name is a cosmetic label, not the image. +# Hub pod: jupyterhub.hub.image (independent). +# nebi binary (init-container copy, NOT the lab image): custom.nebi-image, else +# nebi.image.repository:nebi.image.tag. +# scripts/bump_image_tags.py syncs hub + singleuser + all profile lab images; +# nebi / nfsServer / rbac.bootstrap images are bumped by hand. +# ============================================================================= # Keycloak — only the hostname is required for full zero-config. # ============================================================================= keycloak: @@ -188,6 +199,7 @@ sharedStorage: # nebari-dev/nebari-docker-images#230). We carry it for clusters that # cannot provide RWX storage natively; on NIC-managed clusters set # `sharedStorage.storageClass: longhorn` and leave nfsServer disabled. + # NFS server image; bump_image_tags.py ignores it. image: repository: quay.io/nebari/volume-nfs tag: "0.8-repack" @@ -213,14 +225,10 @@ sharedStorage: # ============================================================================= # Companion service (nebari-nebi-pack) deployed in its own namespace. nebi: - # Nebi binary image. An init container copies the nebi binary from this image - # into each JupyterLab pod, so the version is controlled at deploy time - # rather than baked into the JupyterLab image. + # nebi binary image (init container copies the binary into lab pods), NOT + # the lab image. Change the version via `tag`; bump_image_tags.py ignores it. image: repository: quay.io/nebari/nebi - # Pinned per chart release by CI (scripts/bump_image_tags.py); deployers - # can override to test a PR build or roll forward. Leave non-empty so - # the init container is wired by default. tag: "sha-32d0bc9" pullPolicy: IfNotPresent # External Nebi FQDN (browser-side, used for OIDC redirect). @@ -314,8 +322,8 @@ rbac: # lives at ``/admin/realms/...``). In-cluster service URL by # default; override if Keycloak sits at a different hostname. kcHost: "http://keycloak-keycloakx-http.keycloak.svc.cluster.local:8080" - # Image that runs ``files/keycloak_rbac_bootstrap.py``. The script - # uses only the standard library, so any small Python image works. + # Runs files/keycloak_rbac_bootstrap.py (stdlib only, any small Python + # image works); bump_image_tags.py ignores it. image: "python:3.12-slim" # JupyterHub configuration @@ -330,8 +338,7 @@ jupyterhub: # JupyterHub bind URL hostname. If empty, derived from nebariapp.hostname # (which itself defaults from keycloak.hostname + subdomains.hub). external-url: "" - # Nebi binary image (repository:tag) copied into singleuser pods. - # If empty, derived as `:`. + # Override for the nebi binary image. Empty = derive from nebi.image. nebi-image: "" nebi-image-pull-policy: "IfNotPresent" # External Nebi URL. If empty, derived from nebi.remoteURL (which @@ -384,21 +391,18 @@ jupyterhub: # kubespawner_override: # extra_resource_limits: # nvidia.com/gpu: 1 - # NOTE: when bumping singleuser.image.tag below, also bump the - # ``image: ...`` lines inside each profile_options.image.choices.default - # entry so the profile selector shows the right tag. (z2jh values.yaml - # cannot reference other values, so the duplication is unavoidable.) + # ------------------------------------------------------------------------- + # Lab image per profile (see IMAGE REFERENCE MAP at top). The outer + # kubespawner_override.image and the choices.default image must be kept + # equal: z2jh values cannot cross-reference, so the ref is repeated. profiles: - slug: small-instance display_name: "Small Instance" description: "1 CPU / 2 GB RAM — interactive notebooks, light data exploration, teaching." default: true kubespawner_override: - # Outer image is what jhub-apps' Create App reads for its image - # TextField (server-types.tsx: `type.kubespawner_override.image`). - # The same value sits inside profile_options.image.choices.default - # so the JupyterLab profile selector keeps showing it too. - # scripts/bump_image_tags.py syncs all three on every bump. + # Profile base image; also what jhub-apps "Create App" reads. Keep + # equal to choices.default below. image: quay.io/nebari/nebari-data-science-pack-jupyterlab:sha-46289ab cpu_limit: 1 cpu_guarantee: 0.5 @@ -409,14 +413,17 @@ jupyterhub: display_name: Image choices: default: + # display_name: cosmetic selector label, not the image pulled. display_name: "nebari-data-science-pack-jupyterlab:sha-46289ab" default: true kubespawner_override: + # Image used when this choice is picked. image: quay.io/nebari/nebari-data-science-pack-jupyterlab:sha-46289ab - slug: medium-instance display_name: "Medium Instance" description: "4 CPU / 8 GB RAM — pandas / scikit-learn workloads on medium datasets." kubespawner_override: + # Profile base image; keep equal to choices.default below. image: quay.io/nebari/nebari-data-science-pack-jupyterlab:sha-46289ab cpu_limit: 4 cpu_guarantee: 2 @@ -427,9 +434,11 @@ jupyterhub: display_name: Image choices: default: + # display_name: cosmetic selector label, not the image pulled. display_name: "nebari-data-science-pack-jupyterlab:sha-46289ab" default: true kubespawner_override: + # Image used when this choice is picked. image: quay.io/nebari/nebari-data-science-pack-jupyterlab:sha-46289ab # Terminal customization: controls Starship prompt in JupyterLab terminals. # When false, falls back to the default bash prompt. @@ -477,6 +486,7 @@ jupyterhub: # # here to add more or replace the default. # startup_apps: [] hub: + # Hub pod image (JupyterHub + jhub-apps), independent of the lab images. # Custom Nebari hub image with jhub-apps pre-installed. # Tag below is the PR-53 merge-commit SHA at the moment of pinning; the # corresponding immutable digest is @@ -574,6 +584,8 @@ jupyterhub: - port: 10202 # jhub-apps service port singleuser: + # Fallback lab image: only launches a pod when profiles == []. Otherwise + # each profile's image overrides it (see IMAGE REFERENCE MAP at top). image: name: quay.io/nebari/nebari-data-science-pack-jupyterlab tag: "sha-46289ab" From 75089ba5e3be8f252021df04b7ce9baf9bb417d0 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Fri, 5 Jun 2026 12:24:12 +0100 Subject: [PATCH 2/4] values: drop redundant profile_options image block A profile's kubespawner_override.image already drives both the native JupyterHub spawn form (override precedence) and the jhub-apps image box (server-types reads kubespawner_override.image, ignores profile_options). The single-choice profile_options block only re-stated that image and rendered a useless one-item dropdown, so remove it and document the one field that matters. --- values.yaml | 48 ++++++++++++------------------------------------ 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/values.yaml b/values.yaml index 4097576..935f352 100644 --- a/values.yaml +++ b/values.yaml @@ -21,14 +21,14 @@ # ============================================================================= # IMAGE REFERENCE MAP # ============================================================================= -# Lab pod image (highest wins): profile_options.image.choices..image > -# profiles[N].kubespawner_override.image > singleuser.image (fallback, only -# when profiles == []). display_name is a cosmetic label, not the image. -# Hub pod: jupyterhub.hub.image (independent). -# nebi binary (init-container copy, NOT the lab image): custom.nebi-image, else -# nebi.image.repository:nebi.image.tag. -# scripts/bump_image_tags.py syncs hub + singleuser + all profile lab images; -# nebi / nfsServer / rbac.bootstrap images are bumped by hand. +# Lab pod: each profile's kubespawner_override.image. (If profiles is empty, +# singleuser.image is used instead.) This one field feeds both the native +# spawn form and the jhub-apps image box. +# Hub pod: jupyterhub.hub.image. +# nebi binary (copied into lab pods by an init container, NOT the lab image): +# custom.nebi-image, else nebi.image.repository:nebi.image.tag. +# scripts/bump_image_tags.py syncs hub + singleuser + all profile images; +# nebi / nfsServer / rbac.bootstrap are bumped by hand. # ============================================================================= # Keycloak — only the hostname is required for full zero-config. # ============================================================================= @@ -392,54 +392,30 @@ jupyterhub: # extra_resource_limits: # nvidia.com/gpu: 1 # ------------------------------------------------------------------------- - # Lab image per profile (see IMAGE REFERENCE MAP at top). The outer - # kubespawner_override.image and the choices.default image must be kept - # equal: z2jh values cannot cross-reference, so the ref is repeated. + # The lab image for each profile is `kubespawner_override.image`. That one + # field drives both the native /hub/spawn form and the jhub-apps "Create + # App" image box. (Add `profile_options.image.choices` only if you want a + # user-selectable image dropdown; the native form alone honours it.) profiles: - slug: small-instance display_name: "Small Instance" description: "1 CPU / 2 GB RAM — interactive notebooks, light data exploration, teaching." default: true kubespawner_override: - # Profile base image; also what jhub-apps "Create App" reads. Keep - # equal to choices.default below. image: quay.io/nebari/nebari-data-science-pack-jupyterlab:sha-46289ab cpu_limit: 1 cpu_guarantee: 0.5 mem_limit: "2G" mem_guarantee: "1G" - profile_options: - image: - display_name: Image - choices: - default: - # display_name: cosmetic selector label, not the image pulled. - display_name: "nebari-data-science-pack-jupyterlab:sha-46289ab" - default: true - kubespawner_override: - # Image used when this choice is picked. - image: quay.io/nebari/nebari-data-science-pack-jupyterlab:sha-46289ab - slug: medium-instance display_name: "Medium Instance" description: "4 CPU / 8 GB RAM — pandas / scikit-learn workloads on medium datasets." kubespawner_override: - # Profile base image; keep equal to choices.default below. image: quay.io/nebari/nebari-data-science-pack-jupyterlab:sha-46289ab cpu_limit: 4 cpu_guarantee: 2 mem_limit: "8G" mem_guarantee: "4G" - profile_options: - image: - display_name: Image - choices: - default: - # display_name: cosmetic selector label, not the image pulled. - display_name: "nebari-data-science-pack-jupyterlab:sha-46289ab" - default: true - kubespawner_override: - # Image used when this choice is picked. - image: quay.io/nebari/nebari-data-science-pack-jupyterlab:sha-46289ab # Terminal customization: controls Starship prompt in JupyterLab terminals. # When false, falls back to the default bash prompt. terminal-customization: true From df2834d799df7cd75cbbbd8a2b8cee2ccc77ec7d Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Fri, 5 Jun 2026 12:47:31 +0100 Subject: [PATCH 3/4] docs: spell out when singleuser.image is the fallback Name the jupyterhub.custom.profiles key explicitly and state that the singleuser.image fallback applies only when that list is set to []. --- values.yaml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/values.yaml b/values.yaml index 484ab64..3adc689 100644 --- a/values.yaml +++ b/values.yaml @@ -21,9 +21,12 @@ # ============================================================================= # IMAGE REFERENCE MAP # ============================================================================= -# Lab pod: each profile's kubespawner_override.image. (If profiles is empty, -# singleuser.image is used instead.) This one field feeds both the native -# spawn form and the jhub-apps image box. +# Lab pod: set by the `kubespawner_override.image` of each entry under +# `jupyterhub.custom.profiles` (this chart ships Small + Medium entries, so +# that is the image users get). This one field feeds both the native spawn +# form and the jhub-apps image box. The `jupyterhub.singleuser.image` below +# is used ONLY if a deployer sets `jupyterhub.custom.profiles: []` (no +# profiles, i.e. the profile picker is turned off). # Hub pod: jupyterhub.hub.image. # nebi binary (copied into lab pods by an init container, NOT the lab image): # custom.nebi-image, else nebi.image.repository:nebi.image.tag. @@ -563,8 +566,10 @@ jupyterhub: - port: 10202 # jhub-apps service port singleuser: - # Fallback lab image: only launches a pod when profiles == []. Otherwise - # each profile's image overrides it (see IMAGE REFERENCE MAP at top). + # Fallback lab image, used ONLY when `jupyterhub.custom.profiles` is set to + # an empty list ([]). With the profiles this chart ships (Small + Medium), + # each profile's own `kubespawner_override.image` is used and this value is + # never what launches a pod. See IMAGE REFERENCE MAP at top. image: name: quay.io/nebari/nebari-data-science-pack-jupyterlab tag: "sha-46289ab" From a709cfa003fc1e44f1a947936f147367fd5bcb1a Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Fri, 5 Jun 2026 12:51:03 +0100 Subject: [PATCH 4/4] docs: move image notes inline, drop the top image map Document each image where its value lives instead of a separate map block. --- values.yaml | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/values.yaml b/values.yaml index 3adc689..38d3169 100644 --- a/values.yaml +++ b/values.yaml @@ -19,20 +19,6 @@ # * nebari-operator runs in the cluster and provisions the OIDC client # # ============================================================================= -# IMAGE REFERENCE MAP -# ============================================================================= -# Lab pod: set by the `kubespawner_override.image` of each entry under -# `jupyterhub.custom.profiles` (this chart ships Small + Medium entries, so -# that is the image users get). This one field feeds both the native spawn -# form and the jhub-apps image box. The `jupyterhub.singleuser.image` below -# is used ONLY if a deployer sets `jupyterhub.custom.profiles: []` (no -# profiles, i.e. the profile picker is turned off). -# Hub pod: jupyterhub.hub.image. -# nebi binary (copied into lab pods by an init container, NOT the lab image): -# custom.nebi-image, else nebi.image.repository:nebi.image.tag. -# scripts/bump_image_tags.py syncs hub + singleuser + all profile images; -# nebi / nfsServer / rbac.bootstrap are bumped by hand. -# ============================================================================= # Keycloak — only the hostname is required for full zero-config. # ============================================================================= keycloak: @@ -566,10 +552,9 @@ jupyterhub: - port: 10202 # jhub-apps service port singleuser: - # Fallback lab image, used ONLY when `jupyterhub.custom.profiles` is set to - # an empty list ([]). With the profiles this chart ships (Small + Medium), - # each profile's own `kubespawner_override.image` is used and this value is - # never what launches a pod. See IMAGE REFERENCE MAP at top. + # Fallback lab image, used ONLY when jupyterhub.custom.profiles is []. With + # the profiles this chart ships, each profile's kubespawner_override.image + # wins and this is never used. Tag synced by scripts/bump_image_tags.py. image: name: quay.io/nebari/nebari-data-science-pack-jupyterlab tag: "sha-46289ab"