Apache Superset
Deploy Apache Superset on Kubernetes — a modern business intelligence platform with 60+ database connectors, interactive dashboards, SQL editor, and chart builder. The chart deploys three independent components: a Gunicorn web server, Celery workers for async queries, and a Celery Beat scheduler for cache warming and alerts.
superset.secretKey is the Flask SECRET_KEY used to sign sessions and encrypt sensitive metadata. The chart
preserves an auto-generated key across upgrades, but uninstalling and reinstalling without an operator-owned Secret
loses it. Use superset.existingSecret in production and include the key in the PostgreSQL recovery plan.
Unlike most charts, Superset ships with postgresql.enabled: true and redis.enabled: true. No manual activation is
needed for a quick start. Set both to false and configure database.mode: external and redisConfig.mode: external
to use external services.
Key Features
- Three-component architecture — web (Gunicorn), worker (Celery), beat (Celery Beat)
- Init Job — runs
superset db upgradeand admin creation on every install/upgrade - Bundled PostgreSQL and Redis — both enabled by default
superset_config.pyoverride — arbitrary Python config viasuperset.extraConfig- Additional Python packages — optional database drivers shared by web, worker, beat, and init
- Configurable listener —
web.containerPortchanges the real Gunicorn bind port - Secure defaults — non-root, read-only containers with seccomp and dropped capabilities
- NetworkPolicy — web-listener ingress isolation with configurable peers and egress
- pg_dump backup — scheduled PostgreSQL S3 backup CronJob
Installation
HTTPS repository:
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install superset helmforge/superset -f values.yaml
OCI registry:
helm install superset oci://ghcr.io/helmforgedev/helm/superset -f values.yaml
Upgrading from Superset 4
Back up the metadata database and plan for migration downtime. The init Job runs superset db upgrade and superset init before the application workloads become ready. Superset 6 removes AUTH_OID; migrate those installations to
OAuth, LDAP, or database authentication before upgrading. Custom frontend extensions may also need changes for the
React upgrade introduced in Superset 5.
Review the upstream Superset 5 update notes and Superset 6 update notes before upgrading production.
Additional Database Drivers
Use superset.extraPythonPackages for development and simpler deployments that need optional Python database drivers.
Entries accept package names with optional version constraints and are installed consistently in the web, worker, beat,
and init processes. Pin a version that you have tested:
superset:
extraPythonPackages:
- clickhouse-connect==0.13.0
For Superset 6.1.0, clickhouse-connect>=0.13.0 is the recommended ClickHouse driver. Configure the database with a
clickhousedb://user:password@host:port/database SQLAlchemy URI.
Packages configured through extraPythonPackages are downloaded whenever a Superset container starts. For production,
build an immutable image with the tested drivers preinstalled, publish it under an immutable tag, and configure that
tag through image.repository and image.tag. Set superset.installPythonPackages: false so startup does not access
the package index.
FROM apache/superset:6.1.0
USER root
RUN . /app/.venv/bin/activate && \
uv pip install psycopg2-binary redis "clickhouse-connect==0.13.0"
USER superset
After publishing the image under an immutable tag, disable runtime package installation:
image:
repository: registry.example.com/superset
tag: 6.1.0-clickhouse-0.13.0
superset:
installPythonPackages: false
The custom image must contain psycopg2-binary, redis, and every configured extra package.
Deployment Examples
# values.yaml — Superset with bundled PostgreSQL + Redis (with persistence overrides)
superset:
adminUsername: admin
adminEmail: [email protected]
existingSecret: superset-secrets
existingSecretPasswordKey: admin-password
existingSecretSecretKeyKey: secret-key # Flask SECRET_KEY
postgresql:
enabled: true
auth:
database: superset
username: superset
password: 'strong-db-password'
standalone:
persistence:
storageClass: fast-storage
size: 20Gi
redis:
enabled: true
auth:
password: 'strong-redis-password'
standalone:
persistence:
storageClass: fast-storage
size: 8Gi
ingress:
enabled: true
ingressClassName: traefik
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: superset.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: superset-tls
hosts:
- superset.example.com# values.yaml — Superset with scaled web, workers, and beat scheduler
superset:
existingSecret: superset-secrets
web:
replicaCount: 2 # web server pods
workers: 4 # Gunicorn worker processes per web pod (NOT Celery workers)
timeout: 120
worker:
enabled: true
replicaCount: 3 # Celery worker pods
concurrency: 4 # simultaneous Celery tasks per worker pod
beat:
enabled: true # Celery Beat: cache warming, alerts, reports
postgresql:
enabled: true
auth:
password: 'strong-db-password'
redis:
enabled: true
auth:
password: 'strong-redis-password'
ingress:
enabled: true
ingressClassName: traefik
hosts:
- host: superset.example.com
paths:
- path: /
pathType: Prefix# values.yaml — Superset with external PostgreSQL and Redis
superset:
existingSecret: superset-secrets
postgresql:
enabled: false
redis:
enabled: false
database:
mode: external
external:
host: postgres.database.svc.cluster.local
port: 5432
name: superset
username: superset
existingSecret: superset-db-credentials
existingSecretPasswordKey: password
sslMode: verify-full
redisConfig:
mode: external
external:
host: redis.cache.svc.cluster.local
port: 6379
db: 0
tls: true
existingSecret: superset-redis-credentials
existingSecretPasswordKey: password
backup:
enabled: true
schedule: '0 3 * * *'
s3:
endpoint: https://s3.amazonaws.com
bucket: superset-backups
existingSecret: superset-s3-credentials
ingress:
enabled: true
ingressClassName: traefik
hosts:
- host: superset.example.com
paths:
- path: /
pathType: Prefix# values.yaml — Superset with OIDC/OAuth2 via superset.extraConfig
superset:
existingSecret: superset-secrets
extraConfig: |
from flask_appbuilder.security.manager import AUTH_OAUTH
AUTH_TYPE = AUTH_OAUTH
OAUTH_PROVIDERS = [
{
"name": "keycloak",
"token_key": "access_token",
"icon": "fa-key",
"remote_app": {
"client_id": "superset",
"client_secret": "my-client-secret",
"server_metadata_url": "https://auth.example.com/realms/myrealm/.well-known/openid-configuration",
"client_kwargs": {"scope": "openid email profile"},
"redirect_uri": "https://superset.example.com/oauth-authorized/keycloak",
},
}
]
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Gamma"
postgresql:
enabled: true
auth:
password: 'strong-db-password'
redis:
enabled: true
auth:
password: 'strong-redis-password'
ingress:
enabled: true
ingressClassName: traefik
hosts:
- host: superset.example.com
paths:
- path: /
pathType: PrefixRuntime Security
Superset containers run as UID/GID 1000 with a read-only root filesystem,
RuntimeDefault seccomp, no privilege escalation, and all Linux capabilities
dropped. EmptyDir volumes provide the required writable home and /tmp paths.
The initialization and backup Jobs do not receive Kubernetes API tokens.
Application pods receive a namespaced token only while init.enabled is true,
because their wait container reads the revisioned initialization Job.
NetworkPolicy is enabled by default. It permits ingress only on
web.containerPort and allows egress. Restrict networkPolicy.ingressFrom to
the ingress-controller namespace and replace the egress rules only after
including DNS, PostgreSQL, Redis, package-index access when runtime installs are
enabled, and every data source queried by Superset.
Connection URLs are built inside superset_config.py with URL-encoded Secret
values. Passwords are never stored in the ConfigMap. Treat
superset.extraConfig as trusted Python code.
Configuration Reference
Image
| Parameter | Type | Default | Description |
|---|---|---|---|
image.repository |
string | docker.io/apache/superset |
Superset image. |
image.tag |
string | "6.1.0" |
Image tag. |
Superset Application
| Parameter | Type | Default | Description |
|---|---|---|---|
superset.adminUsername |
string | admin |
Admin username created by the init Job. |
superset.adminPassword |
string | "" |
Admin password. Auto-generated if empty. Use existingSecret. |
superset.secretKey |
string | "" |
Flask SECRET_KEY. Auto-generated if empty. Use existingSecret. |
superset.existingSecret |
string | "" |
Existing secret with admin password and SECRET_KEY. |
superset.existingSecretPasswordKey |
string | admin-password |
Key for the admin password in the existing secret. |
superset.existingSecretSecretKeyKey |
string | secret-key |
Key for the Flask SECRET_KEY in the existing secret. |
superset.loadExamples |
boolean | false |
Load example dashboards during init (use for demos only). |
superset.extraConfig |
string | "" |
Extra Python appended to superset_config.py (OAuth, cache, features). |
superset.extraEnv |
array | [] |
Extra environment variables for all Superset containers. |
superset.installPythonPackages |
boolean | true |
Install Python dependencies when each Superset process starts. |
superset.extraPythonPackages |
array | [] |
Additional Python packages installed in every Superset process. |
Web Server
| Parameter | Type | Default | Description |
|---|---|---|---|
web.replicaCount |
integer | 1 |
Number of web server pods. |
web.containerPort |
integer | 8088 |
Actual Gunicorn listener port. |
web.workers |
integer | 2 |
Gunicorn worker processes per pod (not Celery workers). |
web.timeout |
integer | 120 |
Gunicorn worker timeout in seconds. |
web.resources |
object | {} |
CPU and memory requests/limits for web pods. |
Celery Worker
| Parameter | Type | Default | Description |
|---|---|---|---|
worker.enabled |
boolean | true |
Enable Celery worker Deployment. |
worker.replicaCount |
integer | 1 |
Number of Celery worker pods. |
worker.concurrency |
integer | 2 |
Simultaneous Celery tasks per worker pod. |
worker.resources |
object | {} |
CPU and memory requests/limits for worker pods. |
Celery Beat
| Parameter | Type | Default | Description |
|---|---|---|---|
beat.enabled |
boolean | true |
Enable Celery Beat scheduler (cache warming, alerts, reports). |
beat.resources |
object | {} |
CPU and memory requests/limits for the beat pod. |
Init Job
| Parameter | Type | Default | Description |
|---|---|---|---|
init.enabled |
boolean | true |
Enable the init Job. Runs superset db upgrade + admin creation on every install/upgrade. |
init.resources |
object | {} |
CPU and memory requests/limits for the init container. |
Database
The bundled PostgreSQL runs in standalone mode. Its PVC is configured under
postgresql.standalone.persistence; leave storageClass empty to use the cluster’s default StorageClass.
| Parameter | Type | Default | Description |
|---|---|---|---|
database.mode |
string | subchart |
Mode: subchart or external. |
database.external.host |
string | "" |
External database hostname. |
database.external.existingSecret |
string | "" |
Existing secret with database password. |
database.external.existingSecretPasswordKey |
string | password |
Key for the password in the existing secret. |
database.external.sslMode |
string | require |
PostgreSQL client SSL mode. |
postgresql.enabled |
boolean | true |
Deploy the bundled PostgreSQL subchart. |
postgresql.auth.password |
string | "" |
Password. Auto-generated if empty. |
postgresql.standalone.persistence.enabled |
boolean | true |
Enable the bundled PostgreSQL PVC. |
postgresql.standalone.persistence.storageClass |
string | "" |
StorageClass name. Empty uses the cluster default. |
postgresql.standalone.persistence.accessModes |
array | [ReadWriteOnce] |
Access modes for the bundled PostgreSQL PVC. |
postgresql.standalone.persistence.size |
string | 8Gi |
Size of the bundled PostgreSQL PVC. |
Redis
The bundled Redis also runs in standalone mode. Its PVC is configured under
redis.standalone.persistence; leave storageClass empty to use the cluster’s default StorageClass.
| Parameter | Type | Default | Description |
|---|---|---|---|
redisConfig.mode |
string | subchart |
Mode: subchart or external. |
redisConfig.external.host |
string | "" |
External Redis hostname. |
redisConfig.external.existingSecret |
string | "" |
Existing secret with Redis password. |
redisConfig.external.tls |
boolean | false |
Use a TLS-protected external Redis connection. |
redis.enabled |
boolean | true |
Deploy the bundled Redis subchart. |
redis.auth.password |
string | "" |
Password. Auto-generated if empty. |
redis.standalone.persistence.enabled |
boolean | true |
Enable the bundled Redis PVC. |
redis.standalone.persistence.storageClass |
string | "" |
StorageClass name. Empty uses the cluster default. |
redis.standalone.persistence.accessModes |
array | [ReadWriteOnce] |
Access modes for the bundled Redis PVC. |
redis.standalone.persistence.size |
string | 8Gi |
Size of the bundled Redis PVC. |
Service and Ingress
| Parameter | Type | Default | Description |
|---|---|---|---|
service.type |
string | ClusterIP |
Service type. |
service.port |
integer | 80 |
Service port. |
ingress.enabled |
boolean | false |
Enable an Ingress resource. |
ingress.ingressClassName |
string | traefik |
Ingress class name. |
networkPolicy.enabled |
boolean | true |
Create a NetworkPolicy. |
Security Context and ServiceAccount
| Parameter | Type | Default | Description |
|---|---|---|---|
serviceAccount.create |
boolean | true |
Create a dedicated ServiceAccount. |
serviceAccount.automountServiceAccountToken |
boolean | true |
Allow the init waiter to read the namespaced Job. |
podSecurityContext.seccompProfile.type |
string | RuntimeDefault |
Pod seccomp profile. |
securityContext.readOnlyRootFilesystem |
boolean | true |
Protect the container root filesystem. |
securityContext.allowPrivilegeEscalation |
boolean | false |
Block privilege escalation. |
Backup
Backup runs pg_dump on PostgreSQL. No backup for Redis data.
| Parameter | Type | Default | Description |
|---|---|---|---|
backup.enabled |
boolean | false |
Enable scheduled pg_dump S3 backup. |
backup.schedule |
string | "0 3 * * *" |
Cron schedule. |
backup.s3.endpoint |
string | "" |
S3-compatible endpoint URL. |
backup.s3.bucket |
string | "" |
Target bucket name. |
backup.s3.existingSecret |
string | "" |
Existing secret with S3 credentials. |
extraManifests |
array | [] |
Extra Kubernetes manifests. |