Skip to content

Deploying on Nebari

Updated 3 min read

With nebariapp.enabled: true the chart renders a NebariApp that the operator reconciles into an HTTPRoute, a TLS certificate, and, when auth is on, a Keycloak OIDC client. The certificate needs the operator to be running with a cluster issuer configured; without one it reports TLSReady: False with reason ClusterIssuerNotConfigured and falls back to the shared gateway listener.

nebariapp:
enabled: true
hostname: superset.example.com
routing:
tls:
enabled: true
routes:
- pathPrefix: /
pathType: PathPrefix
auth:
enabled: true
provisionClient: true
enforceAtGateway: false
redirectURI: "/oauth-authorized/keycloak"
scopes: [openid, profile, email]
gateway: public

hostname is required; the chart fails the render without it.

The chart’s default leaves routing commented out, and the operator treats its absence as “do not create routes”:

The routing section must be included for the operator to create HTTPRoutes and TLS certificates. Without it, no route or certificate will be provisioned.

This fails quietly at the surface. kubectl get nebariapp looks fine, the Ready condition is still True, and there is simply no HTTPRoute and no Certificate to find. But the operator does record the reason in the conditions, so ask it directly:

Terminal window
kubectl -n superset get nebariapp -o json \
| jq '.items[] | {name: .metadata.name, conditions: .status.conditions}'
kubectl -n superset get httproute,certificate

RoutingReady: False, reason RoutingNotConfigured, is the operator saying the block is missing. Check that before the hostname or DNS.

nebariapp:
gateway: public # or: internal

public attaches to the cluster’s internet-facing gateway; internal keeps Superset reachable only from inside the network perimeter. It is a sensible default for a BI tool holding warehouse credentials — decide deliberately rather than inheriting public.

A complete manifest is in examples/argocd-app.yaml.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: superset
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/nebari-dev/superset-pack
targetRevision: v0.4.0
path: chart
helm:
values: |
nebariapp:
enabled: true
hostname: superset.example.com
routing:
tls: { enabled: true }
routes:
- pathPrefix: /
pathType: PathPrefix
auth:
enabled: true
provisionClient: true
enforceAtGateway: false
redirectURI: "/oauth-authorized/keycloak"
groups: [superset-admin, superset-user, superset-public]
secretKey:
create: false # see below
destination:
server: https://kubernetes.default.svc
namespace: superset
syncPolicy:
managedNamespaceMetadata:
labels:
nebari.dev/managed: "true"
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
- SkipDryRunOnMissingResource=true

Two other things in that manifest are worth naming:

  • managedNamespaceMetadata applies nebari.dev/managed: "true", which is what makes the operator act on the NebariApp at all.
  • SkipDryRunOnMissingResource=true lets the first sync proceed before the NebariApp CRD is registered, which matters when the operator is installed by the same bootstrap.

The manifest sources path: chart from git at a pinned targetRevision. Pointing at the published Helm repository instead is equally valid; either way, keep the revision pinned, and check the releases for the current tag rather than copying the one above. examples/argocd-app.yaml in the repository is behind on both counts: it still pins v0.3.0, which predates the Superset 6.1.0 upgrade, and its repoURL still uses the pre-rename nebari-superset-pack, which only resolves because GitHub redirects it.

Groups listed in auth.groups are created in the realm by the operator:

nebariapp:
auth:
groups:
- superset-admin
- superset-user
- superset-public

Those names are not arbitrary — they are the keys in the AUTH_ROLES_MAPPING block that maps Keycloak group membership onto Superset roles. Change one side and change the other. See Keycloak OAuth.

An empty groups list means any authenticated realm user can log in, landing in the role named by AUTH_USER_REGISTRATION_ROLE (Gamma in the examples).

Commented out in the chart’s defaults; the argocd-app.yaml example shows the full block:

nebariapp:
landingPage:
enabled: true
displayName: "Apache Superset"
description: "Data exploration and visualization platform"
icon: "https://superset.apache.org/img/superset-logo-horiz.svg"
category: "Data Science"
priority: 10
healthCheck:
enabled: true
path: "/health"
intervalSeconds: 30
timeoutSeconds: 5
Terminal window
kubectl -n superset get nebariapp -o yaml
kubectl -n superset get httproute,certificate,securitypolicy
kubectl -n superset get secret superset-nebari-superset-oidc-client
kubectl get namespace superset -o jsonpath='{.metadata.labels}'

With enforceAtGateway: false there should be no SecurityPolicy — Superset owns the login. Seeing one means gateway enforcement got switched on, which double-authenticates and breaks the OAuth callback.

Bump the chart version and sync. Two cautions:

  • The superset-init-db job runs schema migrations. They are one-way; snapshot the metadata database before a major Superset version bump.
  • Confirm secretKey.create is still false under Argo CD after any values refactor. A reintroduced true rotates the key on the next sync.