diff --git a/README.md b/README.md index 25ce005..8c78722 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,8 @@ For local development (optional): -f examples/vanilla-yaml/service.yaml kubectl port-forward svc/my-pack 8080:80 - # Or with Helm + # Or with Helm (fetch the nebari-app dependency first) + helm dependency build examples/basic-nginx/chart/ helm install test examples/basic-nginx/chart/ kubectl port-forward svc/test-my-pack 8080:80 @@ -144,11 +145,12 @@ software-pack-template/ README.md basic-nginx/ # Example 3: Simplest Helm chart chart/ - Chart.yaml - values.yaml + Chart.yaml # Has nebari-app as a dependency + Chart.lock + values.yaml # NebariApp config under nebariapp: templates/ _helpers.tpl # Name, label, selector helpers - nebariapp.yaml # NebariApp CRD (conditional) + nebariapp.yaml # Renders the NebariApp via nebari-app (conditional) deployment.yaml # Kubernetes Deployment service.yaml # ClusterIP Service NOTES.txt # Post-install instructions @@ -163,12 +165,12 @@ software-pack-template/ README.md wrap-existing-chart/ # Example 5: Wrapping podinfo via Helm chart/ - Chart.yaml # Has podinfo as a dependency + Chart.yaml # Has podinfo and nebari-app as dependencies Chart.lock values.yaml # Podinfo overrides + NebariApp config templates/ _helpers.tpl - nebariapp.yaml # Points to podinfo's service + nebariapp.yaml # Renders the NebariApp via nebari-app NOTES.txt README.md dev/ @@ -233,20 +235,60 @@ spec: ``` The NebariApp is just a Kubernetes resource. It can live in a plain YAML file, a -Kustomize base, or a Helm template. In Helm charts, you can make the NebariApp -conditional so the chart works both standalone and on Nebari: - -```yaml -{{- if .Values.nebariapp.enabled }} -apiVersion: reconcilers.nebari.dev/v1 -kind: NebariApp -... -{{- end }} -``` +Kustomize base, or a Helm template. With plain YAML or Kustomize, the NebariApp manifest is always present. When deploying standalone, simply skip that file or exclude it from your apply command. +### NebariApp in Helm charts + +To render the NebariApp in a Helm chart with the official +[`nebari-app` library chart](https://github.com/nebari-dev/nebari-operator/tree/main/charts/nebari-app): + +1. Add it as a dependency in `Chart.yaml`, then run `helm dependency build`: + + ```yaml + dependencies: + - name: nebari-app + repository: oci://quay.io/nebari/charts + version: ">=0.1.1" + ``` + +2. Set any NebariApp `spec` field under `nebariapp:` in `values.yaml`: + + ```yaml + nebariapp: + enabled: false + hostname: '{{ fail "nebariapp.hostname is required when nebariapp.enabled is true" }}' + service: + name: '{{ include "my-pack.fullname" . | toJson }}' + port: '{{ .Values.service.port }}' + ``` + +3. Render it in `templates/nebariapp.yaml`. The `if` makes the NebariApp optional, + so the chart works both standalone and on Nebari: + + ```yaml + {{- if .Values.nebariapp.enabled }} + {{- include "nebari-app.nebariApp" (dict + "metadata" (dict + "name" (include "my-pack.fullname" .) + "namespace" .Release.Namespace + "labels" (include "my-pack.labels" . | fromYaml) + ) + "spec" (omit .Values.nebariapp "enabled") + "tplCtx" . + ) -}} + {{- end }} + ``` + +When a `{{ ... }}` value renders a string, add `| toJson` at the end. It wraps the string in quotes so it's valid JSON: + +```yaml +name: '{{ include "my-pack.fullname" . | toJson }}' # works +name: '{{ include "my-pack.fullname" . }}' # fails to render +``` + ### Beyond the basics The fields shown above cover the common cases. The operator also supports several @@ -329,7 +371,7 @@ See [examples/kustomize-nginx/README.md](examples/kustomize-nginx/README.md) for ## Example 3: Helm - Basic Pack (Nginx) The simplest possible Helm-based pack. Deploys a stock nginx container with -optional Nebari integration via a conditional NebariApp template. +optional Nebari integration via the `nebari-app` library chart. **What it demonstrates:** - Minimum viable Helm chart structure @@ -337,6 +379,9 @@ optional Nebari integration via a conditional NebariApp template. - Toggling between standalone and Nebari modes ```bash +# Fetch the nebari-app dependency +helm dependency build examples/basic-nginx/chart/ + # Deploy standalone helm install test-basic examples/basic-nginx/chart/ kubectl port-forward svc/test-basic-my-pack 8080:80 @@ -386,6 +431,7 @@ def get_id_token(request: Request) -> str | None: docker run -p 8000:8000 ghcr.io/nebari-dev/software-pack-template/auth-fastapi-example:latest # Deploy on Nebari with auth +helm dependency build examples/auth-fastapi/chart/ helm install my-pack examples/auth-fastapi/chart/ \ --set nebariapp.enabled=true \ --set nebariapp.hostname=my-pack.nebari.example.com @@ -397,8 +443,7 @@ See [examples/auth-fastapi/README.md](examples/auth-fastapi/README.md) for the f **This is the most realistic Helm use case.** Most Helm-based packs wrap existing software - you don't write your own Deployment or Service. You add -the upstream chart as a dependency and create a NebariApp that points to its -service. +the upstream chart as a dependency and point the NebariApp at its service. **What it demonstrates:** - Chart.yaml dependency on an existing chart @@ -407,19 +452,22 @@ service. - No custom Deployment or Service templates needed ```yaml -# Chart.yaml - just add the dependency +# Chart.yaml - add the upstream chart next to nebari-app dependencies: + - name: nebari-app + repository: oci://quay.io/nebari/charts + version: ">=0.1.1" - name: podinfo version: 6.10.1 repository: oci://ghcr.io/stefanprodan/charts ``` -The only template you write is `nebariapp.yaml`, which points to podinfo's service: +The NebariApp points to podinfo's service from `values.yaml`: ```yaml -spec: +nebariapp: service: - name: {{ .Release.Name }}-podinfo # Upstream service + name: '{{ printf "%s-podinfo" .Release.Name | toJson }}' # Upstream service port: 9898 ``` @@ -708,6 +756,7 @@ kubectl apply -k examples/kustomize-nginx/overlays/production/ \ ### Option D: Helm install ```bash +helm dependency build ./chart/ helm install my-pack ./chart/ \ --namespace my-pack \ --create-namespace \ @@ -859,9 +908,17 @@ naming convention (usually `-`). kubectl logs -n envoy-gateway-system -l app=envoy-gateway ``` -### `helm dependency update` fails for wrapped charts +### `missing in charts/ directory: nebari-app` + +The Helm examples depend on the `nebari-app` chart. Fetch it before installing: + +```bash +helm dependency build examples/basic-nginx/chart/ +``` + +### `helm dependency update` fails -For OCI-based dependencies, ensure Helm 3.8+ is installed: +The dependencies are pulled from OCI registries, so ensure Helm 3.8+ is installed: ```bash helm version diff --git a/docs/site/src/content/docs/concepts.md b/docs/site/src/content/docs/concepts.md index b105b69..28db1bf 100644 --- a/docs/site/src/content/docs/concepts.md +++ b/docs/site/src/content/docs/concepts.md @@ -13,20 +13,20 @@ Every software pack has exactly one integration point with the Nebari platform: automatically configures routing, TLS, and authentication. The NebariApp is just a Kubernetes resource - it can live in a plain YAML file, a -Kustomize base, or a Helm template. In Helm charts, you typically make it conditional -so the chart works both standalone and on Nebari: +Kustomize base, or a Helm template. In Helm charts, render it with the template from the +official [`nebari-app` library chart](https://github.com/nebari-dev/nebari-operator/tree/main/charts/nebari-app). +You typically make it conditional so the chart works both standalone and on Nebari: ```yaml {{- if .Values.nebariapp.enabled }} -apiVersion: reconcilers.nebari.dev/v1 -kind: NebariApp -metadata: - name: {{ include "my-pack.fullname" . }} -spec: - hostname: {{ required "nebariapp.hostname is required" .Values.nebariapp.hostname }} - service: - name: {{ include "my-pack.fullname" . }} - port: 80 +{{- include "nebari-app.nebariApp" (dict + "metadata" (dict + "name" (include "my-pack.fullname" .) + "namespace" .Release.Namespace + ) + "spec" (omit .Values.nebariapp "enabled") + "tplCtx" . +) -}} {{- end }} ``` @@ -70,30 +70,33 @@ Best for: packs deployed to multiple environments with known configuration diffe ### Helm Helm is the most common choice for packs that wrap existing upstream software. You add -the upstream chart as a dependency and add a NebariApp template that points to its -service - you do not rewrite the app. +the upstream chart and `nebari-app` as dependencies, then point the NebariApp at the +upstream service in `values.yaml` - you do not rewrite the app. ```yaml -# Chart.yaml - add the upstream chart as a dependency +# Chart.yaml - add the upstream chart next to nebari-app dependencies: + - name: nebari-app + repository: oci://quay.io/nebari/charts + version: ">=0.1.1" - name: podinfo version: 6.10.1 repository: oci://ghcr.io/stefanprodan/charts ``` ```yaml -# templates/nebariapp.yaml - the only template you write -{{- if .Values.nebariapp.enabled }} -apiVersion: reconcilers.nebari.dev/v1 -kind: NebariApp -spec: - hostname: {{ .Values.nebariapp.hostname }} +# values.yaml - the NebariApp spec +nebariapp: + enabled: false + hostname: '{{ fail "nebariapp.hostname is required when nebariapp.enabled is true" }}' service: - name: {{ .Release.Name }}-podinfo # upstream service name + name: '{{ printf "%s-podinfo" .Release.Name | toJson }}' # upstream service name port: 9898 -{{- end }} ``` +`templates/nebariapp.yaml` is the same short `include` shown above. Run +`helm dependency build` before installing. + Best for: wrapping existing Helm charts and for packs with rich configuration needs. ## Template examples diff --git a/examples/auth-fastapi/README.md b/examples/auth-fastapi/README.md index aaa8ab0..eb2b7ec 100644 --- a/examples/auth-fastapi/README.md +++ b/examples/auth-fastapi/README.md @@ -66,6 +66,7 @@ spec: ### Helm install ```bash +helm dependency build ./chart/ helm install my-pack ./chart/ \ --set nebariapp.enabled=true \ --set nebariapp.hostname=my-pack.nebari.example.com \ @@ -117,10 +118,10 @@ an explanatory message when no IdToken is present. | `app/requirements.txt` | Python dependencies | | `app/templates/index.html` | HTML template for user info display | | `Dockerfile` | Multi-stage build for the FastAPI image | -| `chart/Chart.yaml` | Helm chart metadata | -| `chart/values.yaml` | Default config with auth enabled | +| `chart/Chart.yaml` | Helm chart metadata with the nebari-app dependency | +| `chart/values.yaml` | Default config, including the NebariApp spec with auth enabled | | `chart/templates/_helpers.tpl` | Name, label, and selector helpers | -| `chart/templates/nebariapp.yaml` | NebariApp CRD with auth configuration | +| `chart/templates/nebariapp.yaml` | Renders the NebariApp via nebari-app | | `chart/templates/deployment.yaml` | Kubernetes Deployment | | `chart/templates/service.yaml` | ClusterIP Service | | `chart/templates/NOTES.txt` | Post-install instructions | diff --git a/examples/basic-nginx/README.md b/examples/basic-nginx/README.md index 56dcb2c..2a04af5 100644 --- a/examples/basic-nginx/README.md +++ b/examples/basic-nginx/README.md @@ -6,7 +6,8 @@ container with optional Nebari platform integration via the NebariApp CRD. ## What This Example Shows - Minimum viable Helm chart structure for a Nebari pack -- The `nebariapp.yaml` template that creates a NebariApp custom resource +- Rendering the NebariApp custom resource with the official + [`nebari-app` library chart](https://github.com/nebari-dev/nebari-operator/tree/main/charts/nebari-app) - How to toggle Nebari integration on/off with `nebariapp.enabled` - Health probes, service, and deployment boilerplate @@ -65,6 +66,9 @@ This additionally creates: ### Helm install ```bash +# Fetch the nebari-app dependency +helm dependency build ./chart/ + # Deploy on Nebari helm install my-pack ./chart/ \ --set nebariapp.enabled=true \ @@ -80,6 +84,7 @@ helm install my-pack ./chart/ \ ## Local development (standalone, no Nebari) ```bash +helm dependency build ./chart/ helm install test-basic ./chart/ # Access via port-forward @@ -91,10 +96,10 @@ kubectl port-forward svc/test-basic-my-pack 8080:80 | File | Purpose | |------|---------| -| `chart/Chart.yaml` | Helm chart metadata | -| `chart/values.yaml` | Default configuration values | +| `chart/Chart.yaml` | Helm chart metadata with the nebari-app dependency | +| `chart/values.yaml` | Default configuration values, including the NebariApp spec under `nebariapp:` | | `chart/templates/_helpers.tpl` | Name, label, and selector helpers | -| `chart/templates/nebariapp.yaml` | NebariApp CRD (conditional on `nebariapp.enabled`) | +| `chart/templates/nebariapp.yaml` | Renders the NebariApp via nebari-app (conditional on `nebariapp.enabled`) | | `chart/templates/deployment.yaml` | Kubernetes Deployment for nginx | | `chart/templates/service.yaml` | ClusterIP Service | | `chart/templates/NOTES.txt` | Post-install instructions | diff --git a/examples/wrap-existing-chart/README.md b/examples/wrap-existing-chart/README.md index fcd24a8..e092405 100644 --- a/examples/wrap-existing-chart/README.md +++ b/examples/wrap-existing-chart/README.md @@ -2,8 +2,8 @@ This is the most realistic use case for a Helm-based Nebari Software Pack. Instead of writing your own Deployment and Service templates, you add an -existing Helm chart as a dependency and create a NebariApp resource that points -to its service. +existing Helm chart as a dependency and point the NebariApp resource at its +service. **Key lesson: You don't rewrite the app - you just connect it to Nebari.** @@ -11,7 +11,7 @@ to its service. - Adding an upstream Helm chart as a `Chart.yaml` dependency - Overriding upstream values via your own `values.yaml` -- Creating a NebariApp that points to the upstream chart's service +- Pointing the NebariApp at the upstream chart's service from `values.yaml` - No custom Deployment or Service templates needed ## How It Works @@ -19,18 +19,25 @@ to its service. ``` Chart.yaml dependencies: + - name: nebari-app # Official chart that provides the NebariApp template + repository: oci://quay.io/nebari/charts - name: podinfo # Upstream chart handles pods + services version: 6.10.1 repository: oci://ghcr.io/stefanprodan/charts +values.yaml + nebariapp: # NebariApp spec: points to podinfo's service + podinfo: # Overrides passed to the podinfo chart + templates/ - nebariapp.yaml # Points to podinfo's service -> Nebari routes to it + nebariapp.yaml # Short include of the nebari-app template (no deployment.yaml!) # Podinfo chart handles this (no service.yaml!) # Podinfo chart handles this ``` -The only template you write is `nebariapp.yaml`. Everything else comes from the -upstream chart. +The only template you write is a short `nebariapp.yaml` that calls the +[`nebari-app`](https://github.com/nebari-dev/nebari-operator/tree/main/charts/nebari-app) +template. Everything else comes from the upstream chart or `values.yaml`. ## Deploying to Nebari @@ -110,10 +117,10 @@ kubectl port-forward svc/test-wrap-podinfo 9898:9898 | File | Purpose | |------|---------| -| `chart/Chart.yaml` | Helm chart metadata with podinfo dependency | +| `chart/Chart.yaml` | Helm chart metadata with podinfo and nebari-app dependencies | | `chart/values.yaml` | NebariApp config + podinfo overrides | | `chart/templates/_helpers.tpl` | Name, label, and selector helpers | -| `chart/templates/nebariapp.yaml` | NebariApp CRD pointing to podinfo's service | +| `chart/templates/nebariapp.yaml` | Renders the NebariApp via nebari-app | | `chart/templates/NOTES.txt` | Post-install instructions | ## Adapting for Your Own Chart