Skip to content

Latest commit

 

History

History
746 lines (578 loc) · 64.3 KB

README.md

File metadata and controls

746 lines (578 loc) · 64.3 KB

RHDH Helm Chart for OpenShift and Kubernetes

Version: 3.5.13 Type: application

A Helm chart for deploying Red Hat Developer Hub, which is a Red Hat supported version of Backstage.

The telemetry data collection feature is enabled by default. Red Hat Developer Hub sends telemetry data to Red Hat by using the backstage-plugin-analytics-provider-segment plugin. To disable this and to learn what data is being collected, see https://docs.redhat.com/en/documentation/red_hat_developer_hub/1.10/html-single/telemetry_data_collection_and_analysis/index

Homepage: https://developers.redhat.com/products/rhdh

Productized RHDH

This repository now provides the productized RHDH chart. For the Generally Available version of this chart, see:

Maintainers

Name Email Url
Red Hat https://redhat.com

Source Code

TL;DR

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add redhat-developer https://redhat-developer.github.io/rhdh-chart

helm install my-rhdh redhat-developer/redhat-developer-hub --version 3.5.13

Introduction

This chart bootstraps a Red Hat Developer Hub deployment on a Kubernetes cluster using the Helm package manager.

Unlike the legacy backstage chart, this chart owns all Kubernetes templates directly (Deployment or StatefulSet, Service, ConfigMap, etc.) without depending on an upstream Backstage subchart. The Backstage pod specification is shared across workload kinds via a common template. It uses an "add, don't replace" pattern: system-required volumes, volume mounts, environment variables, and init containers are hardcoded in the pod template, while user-provided values (extraVolumes, extraVolumeMounts, extraEnv, extraInitContainers, extraContainers) are always appended — never replacing the defaults.

Prerequisites

Usage

Charts are available in the following formats:

Note

Up-to-date instructions on installing RHDH through the chart can be found in the installation docs.

Installing from the Chart Repository

The following command can be used to add the chart repository:

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add redhat-developer https://redhat-developer.github.io/rhdh-chart

Once the chart has been added, install this chart. However before doing so, please review the default values.yaml and adjust as needed.

  • To get proper connection between frontend and backend of Backstage please update the apps.example.com to match your cluster host:

    openshift:
      clusterRouterBase: apps.example.com

    Tip: you can use helm upgrade -i --set openshift.clusterRouterBase=apps.example.com ... instead of a value file

  • If your cluster doesn't provide PVCs, you should disable PostgreSQL persistence via:

    postgresql:
      primary:
        persistence:
          enabled: false
helm upgrade -i <release_name> redhat-developer/redhat-developer-hub

Installing from an OCI Registry

Charts are also available in OCI format. The list of available releases can be found here.

Install one of the available versions:

helm upgrade -i <release_name> oci://quay.io/rhdh/chart --version=<version>

Tip: List all releases using helm list

Testing a Release

Once an Helm Release has been deployed, you can test it using the helm test command:

helm test <release_name>

This will run a simple Pod in the cluster to check that the application deployed is up and running.

You can control whether to disable this test pod or customize the image, pull policy, and security context it uses. See the test.enabled, test.image, and test.securityContext parameters in the values.yaml file.

Tip: Disabling the test pod will not prevent the helm test command from passing later on. It will simply report that no test suite is available.

Below are a few examples:

Disabling the test pod
helm install <release_name> <repo_or_oci_registry> \
  --set test.enabled=false
Customizing the test pod image
helm install <release_name> <repo_or_oci_registry> \
  --set test.image.repository=curl/curl-base \
  --set test.image.tag=8.11.1

Uninstalling the Chart

To uninstall/delete the my-rhdh deployment:

helm uninstall my-rhdh

The command removes all the Kubernetes components associated with the chart and deletes the release.

Upgrading from the backstage chart (RHDH 1.y)

If you are upgrading from the legacy backstage chart (used in RHDH 1.y), the new redhat-developer-hub chart is a clean break. The values structure has changed significantly — all global.* and upstream.backstage.* nesting has been flattened to root-level keys. You cannot pass your old values file directly to the new chart; you must migrate your values first, then helm upgrade the release in place.

See the Migration guide for step-by-step instructions and a complete values mapping reference.

Requirements

Kubernetes: >= 1.31.0-0

Repository Name Version
https://charts.bitnami.com/bitnami common 2.41.0
oci://registry-1.docker.io/bitnamicharts postgresql 16.2.5

Values

Key Description Type Default
affinity Affinity rules for pod assignment. object {}
appConfig Inline Backstage app-config YAML. Rendered into a ConfigMap and mounted as app-config-from-configmap.yaml. object Default config with base URLs, CORS, database connection, and backend auth.
argsOverride Override the container arguments entirely. When set, system config arguments are NOT added automatically; you must include them yourself. list []
auth Service-to-service authentication configuration. object {"backend":{"enabled":true,"existingSecretRef":{"key":"backend-secret","name":""},"value":""}}
auth.backend.enabled Enable backend service-to-service authentication. Generates a random secret unless existingSecretRef is set or value is provided. Disable if you inject the secret via extraEnvFrom or extraEnv instead. bool true
auth.backend.existingSecretRef Reference an existing Secret instead of generating one. When not set, the chart auto-generates a random token. object {"key":"backend-secret","name":""}
auth.backend.existingSecretRef.key Key within the Secret that holds the backend auth token. string "backend-secret"
auth.backend.existingSecretRef.name Name of the existing Secret. When empty, the chart generates one. string ""
auth.backend.value Use a specific value instead of generating one. string ""
autoscaling Horizontal Pod Autoscaler configuration. object {"enabled":false,"maxReplicas":3,"minReplicas":1,"targetCPUUtilizationPercentage":80}
catalogIndex Catalog index configuration for automatic plugin discovery. object {"extraImages":[],"image":{"digest":"","registry":"quay.io","repository":"rhdh/plugin-catalog-index","tag":"next"}}
catalogIndex.extraImages Extra catalog index images for additional plugin discovery in the Extensions UI. Each item must include registry, repository, and tag fields; name and digest are optional. Only catalog entities are extracted from extra images (no dynamic-plugins.default.yaml handling). list []
commandOverride Override the container command. list []
commonAnnotations Annotations applied to ALL chart resources. object {}
commonLabels Labels applied to ALL chart resources. object {}
containerSecurityContext Security context for the main RHDH container (not the Lightspeed Core sidecar or init containers). object {"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}
deploymentAnnotations Annotations for the Deployment resource (not the pod). object {}
dynamicPlugins Dynamic plugin system configuration. object {"includes":["dynamic-plugins.default.yaml"],"initContainer":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"resources":{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{}},"maxEntrySize":40000000,"plugins":[],"volume":{"emptyDir":{},"ephemeral":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"pvc":{"claimName":""},"statefulSetPVC":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"type":"ephemeral"}}
dynamicPlugins.includes Array of YAML files listing dynamic plugins to include. Relative paths are resolved from the working directory of the initContainer (/opt/app-root/src). list ["dynamic-plugins.default.yaml"]
dynamicPlugins.initContainer Configuration for the install-dynamic-plugins init container. object {"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"resources":{"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}},"securityContext":{}}
dynamicPlugins.initContainer.argsOverride Override the default arguments. Leave empty to use the defaults. list []
dynamicPlugins.initContainer.commandOverride Override the default command. Leave empty to use the default (./install-dynamic-plugins.sh /dynamic-plugins-root). list []
dynamicPlugins.initContainer.extraArgs Extra arguments appended after the default arguments. Ignored when argsOverride is set. list []
dynamicPlugins.initContainer.extraEnv Extra environment variables appended after the system env vars (NPM_CONFIG_USERCONFIG, MAX_ENTRY_SIZE, CATALOG_INDEX_IMAGE, etc.). list []
dynamicPlugins.initContainer.extraVolumeMounts Additional volume mounts appended after the system mounts (dynamic-plugins-root, npmrc, registry-auth, npmcacache, extensions-catalog, temp). list []
dynamicPlugins.initContainer.resources Resource requests and limits. object {"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"256Mi"}}
dynamicPlugins.initContainer.securityContext Security context for the init container. object Same as containerSecurityContext
dynamicPlugins.maxEntrySize Maximum uncompressed size (in bytes) of a single dynamic plugin entry. int 40000000
dynamicPlugins.plugins List of dynamic plugins. Every item defines the plugin package as a NPM package spec or OCI reference. list []
dynamicPlugins.volume Volume configuration for the dynamic plugins root directory. object {"emptyDir":{},"ephemeral":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"pvc":{"claimName":""},"statefulSetPVC":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""},"type":"ephemeral"}
dynamicPlugins.volume.emptyDir Raw Kubernetes emptyDir volume spec. Used when type is "emptyDir". object {}
dynamicPlugins.volume.ephemeral Ephemeral volume configuration. Used when type is "ephemeral". The chart builds the full ephemeral.volumeClaimTemplate.spec from these fields. object {"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""}
dynamicPlugins.volume.ephemeral.accessModes Access modes for the ephemeral PVC. list ["ReadWriteOnce"]
dynamicPlugins.volume.ephemeral.resources Resource requests for the ephemeral PVC. object {"requests":{"storage":"5Gi"}}
dynamicPlugins.volume.ephemeral.storageClassName StorageClass for the ephemeral volume. When empty, uses global.defaultStorageClass or the cluster default. string ""
dynamicPlugins.volume.pvc Raw Kubernetes persistentVolumeClaim volume spec. Used when type is "pvc". object {"claimName":""}
dynamicPlugins.volume.statefulSetPVC StatefulSet-owned PVC volume spec. Used when type is "statefulSetPVC". object {"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":""}
dynamicPlugins.volume.statefulSetPVC.accessModes Access modes for the StatefulSet-owned PVC. list ["ReadWriteOnce"]
dynamicPlugins.volume.statefulSetPVC.resources Resource requests for the StatefulSet-owned PVC. object {"requests":{"storage":"5Gi"}}
dynamicPlugins.volume.statefulSetPVC.storageClassName StorageClass. When empty, uses global.defaultStorageClass or the cluster default. string ""
dynamicPlugins.volume.type Volume type: "ephemeral" (auto-provisioned PVC per pod), "emptyDir" (scratch space, lost on pod restart), "pvc" (pre-existing PersistentVolumeClaim), or "statefulSetPVC" (StatefulSet volumeClaimTemplate; requires workload.kind=StatefulSet). string "ephemeral"
envFromOverride Override the container envFrom entirely. When set, extraEnvFrom is ignored. Accepts raw Kubernetes envFrom entries (configMapRef, secretRef, prefix). list []
envOverride Override the container environment variables entirely. When set, system env vars (BACKEND_SECRET, DB credentials, etc.) are NOT added automatically. list []
externalDatabase External database connection. Used when postgresql.enabled is false. See docs/external-db.md for TLS setup and privilege requirements. When both postgresql.enabled and externalDatabase.host are false/empty, the chart renders no database env vars (BYO configuration via extraEnv or appConfig). object {"existingSecretRef":{"key":"password","name":""},"host":"","port":5432,"user":"postgres"}
externalDatabase.existingSecretRef Reference to an existing Secret containing the database password. object {"key":"password","name":""}
externalDatabase.existingSecretRef.key Key within the Secret that holds the password. string "password"
externalDatabase.existingSecretRef.name Name of the existing Secret. string ""
externalDatabase.host External database hostname. string ""
externalDatabase.port External database port. int 5432
externalDatabase.user External database user. string "postgres"
extraAppConfig Additional app-config files from existing ConfigMaps. list []
extraArgs Extra arguments appended after the system config flags. list []
extraContainers Additional sidecar containers. These are ADDED to system containers (e.g. Lightspeed Core sidecar), never replacing them. list []
extraDeploy Array of extra objects to deploy with the release (rendered through tpl). Each element is a complete Kubernetes manifest; Helm template expressions are supported. list []
extraEnv Extra environment variables appended after the system env vars. list []
extraEnvFrom Extra envFrom entries appended to the container. Accepts raw Kubernetes envFrom entries (configMapRef, secretRef, prefix). list []
extraInitContainers Additional init containers. These are ADDED after system init containers (install-dynamic-plugins), never replacing them. list []
extraVolumeMounts Additional volume mounts to add to the main container. These are ADDED to system-required mounts, never replacing them. list []
extraVolumes Additional volumes to add to the pod. These are ADDED to system-required volumes (dynamic-plugins-root, temp, npmcacache, etc.), never replacing them. list []
fullnameOverride Override the full resource name. string ""
global Global parameters shared with bitnami subcharts (postgresql, common). object {"defaultStorageClass":"","imagePullSecrets":[],"imageRegistry":""}
global.defaultStorageClass Global default StorageClass for PVCs. string ""
global.imagePullSecrets Global Docker registry secret names. list []
global.imageRegistry Global Docker image registry. Overrides per-image registries for all containers. string ""
host Custom hostname. Overrides openshift.clusterRouterBase for URL generation. string ""
hostAliases Host aliases for /etc/hosts entries. list []
httpRoute Gateway API HTTPRoute configuration. object {"annotations":{},"enabled":false,"hostnames":[],"labels":{},"parentRefs":[],"rules":[]}
httpRoute.labels Additional labels for the HTTPRoute resource. object {}
httpRoute.rules HTTPRoute rules. Each rule may set option port (backend service port). Defaults to service.port when omitted. list []
image Container image configuration. object {"digest":"","pullPolicy":"IfNotPresent","registry":"quay.io","repository":"rhdh-community/rhdh","tag":"next"}
image.digest Overrides the image tag with an image digest. string ""
imagePullSecrets Secrets for pulling images from private registries (merged with global.imagePullSecrets). list []
ingress Kubernetes Ingress configuration. object {"annotations":{},"className":"","enabled":false,"hosts":[{"host":"{{ .Values.host }}","paths":[{"path":"/","pathType":"Prefix"}]}],"tls":[]}
ingress.hosts Ingress hosts. Each path may set option port (backend service port). Defaults to service.port when omitted (e.g. use 4180 for an oauth2-proxy sidecar). list [{"host":"{{ .Values.host }}","paths":[{"path":"/","pathType":"Prefix"}]}]
intelligentAssistant Built-in Intelligent Assistant feature configuration. object {"config":{"profile":{"existingConfigMap":{"key":"","name":""}},"stack":{"existingConfigMap":{"key":"","name":""}}},"core":{"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"lightspeed-core/lightspeed-stack","tag":"0.7.1"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"enabled":true,"existingSecret":"","okp":{"affinity":{},"embeddingModel":"ibm-granite/granite-embedding-small-english-r2","enabled":false,"httpd":{"compressed":"true","encrypt":"false","serverName":"localhost"},"image":{"digest":"","pullPolicy":"IfNotPresent","registry":"registry.redhat.io","repository":"offline-knowledge-portal/rhokp-rhel9","tag":"1.3.0-1792010339"},"imagePullSecrets":[],"ingress":{"annotations":{},"className":"","enabled":true,"host":"","tls":{"enabled":false,"secretName":""}},"livenessProbe":{"initialDelaySeconds":30,"periodSeconds":30},"nodeSelector":{},"readinessProbe":{"initialDelaySeconds":10,"periodSeconds":10},"replicaCount":1,"resources":{"limits":{"cpu":"2","memory":"4Gi"},"requests":{"cpu":"200m","memory":"2Gi"}},"route":{"enabled":true,"tls":{"insecureEdgeTerminationPolicy":"Redirect","termination":"edge"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}},"service":{"type":"ClusterIP"},"solr":{"hostBind":"0.0.0.0","memory":"1g"},"tolerations":[],"topologySpreadConstraints":[]},"plugins":[{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend"}],"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}
intelligentAssistant.config Configuration files mounted into the sidecar. By default, the chart creates ConfigMaps from bundled source files. Set existingConfigMap to use a pre-existing ConfigMap instead. object {"profile":{"existingConfigMap":{"key":"","name":""}},"stack":{"existingConfigMap":{"key":"","name":""}}}
intelligentAssistant.config.profile Python profile with prompt templates (rhdh-profile.py). object {"existingConfigMap":{"key":"","name":""}}
intelligentAssistant.config.profile.existingConfigMap Use an existing ConfigMap instead of the bundled default. object Created from bundled rhdh-profile.py
intelligentAssistant.config.profile.existingConfigMap.key Key within the ConfigMap that holds the file content. Defaults to the bundled filename (rhdh-profile.py) if not set. string ""
intelligentAssistant.config.profile.existingConfigMap.name Name of the existing ConfigMap. string ""
intelligentAssistant.config.stack Lightspeed Core service configuration (lightspeed-stack.yaml). object {"existingConfigMap":{"key":"","name":""}}
intelligentAssistant.config.stack.existingConfigMap Use an existing ConfigMap instead of the bundled default. object Created from bundled lightspeed-stack.yaml
intelligentAssistant.config.stack.existingConfigMap.key Key within the ConfigMap that holds the file content. Defaults to the bundled filename (lightspeed-stack.yaml) if not set. string ""
intelligentAssistant.config.stack.existingConfigMap.name Name of the existing ConfigMap. string ""
intelligentAssistant.core Lightspeed Core sidecar container. object {"argsOverride":[],"commandOverride":[],"extraArgs":[],"extraEnv":[],"extraVolumeMounts":[],"image":{"digest":"","registry":"quay.io","repository":"lightspeed-core/lightspeed-stack","tag":"0.7.1"},"imagePullPolicy":"IfNotPresent","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}
intelligentAssistant.core.argsOverride Override the container's default args. Leave empty to use the chart defaults. list []
intelligentAssistant.core.commandOverride Override the container's default command. Leave empty to use the image entrypoint. list []
intelligentAssistant.core.extraArgs Extra arguments appended after the default arguments. Ignored when argsOverride is set. list []
intelligentAssistant.existingSecret Name of an existing Secret that supplies credentials and settings to the lightspeed-core container. Configure the provider itself in lightspeed-stack.yaml. If empty, no Secret is loaded. Expected keys (all optional; include only keys used by the configured provider): VLLM_URL, VLLM_API_KEY, VLLM_MAX_TOKENS, VLLM_TLS_VERIFY, OPENAI_API_KEY, VERTEX_AI_PROJECT, VERTEX_AI_LOCATION, GOOGLE_APPLICATION_CREDENTIALS, ENABLE_VALIDATION, VALIDATION_PROVIDER, VALIDATION_MODEL_NAME Set ENABLE_VALIDATION to question_validity to enable validation. GOOGLE_APPLICATION_CREDENTIALS must be a path to a credentials file mounted in the sidecar. See files/intelligent-assistant/secret.example.yaml for a reference template. string ""
intelligentAssistant.okp OKP (Offline Knowledge Portal) configuration. Deploys an OKP instance for RHDH documentation retrieval when explicitly enabled. The image is large and can significantly increase initial installation time. object {"affinity":{},"embeddingModel":"ibm-granite/granite-embedding-small-english-r2","enabled":false,"httpd":{"compressed":"true","encrypt":"false","serverName":"localhost"},"image":{"digest":"","pullPolicy":"IfNotPresent","registry":"registry.redhat.io","repository":"offline-knowledge-portal/rhokp-rhel9","tag":"1.3.0-1792010339"},"imagePullSecrets":[],"ingress":{"annotations":{},"className":"","enabled":true,"host":"","tls":{"enabled":false,"secretName":""}},"livenessProbe":{"initialDelaySeconds":30,"periodSeconds":30},"nodeSelector":{},"readinessProbe":{"initialDelaySeconds":10,"periodSeconds":10},"replicaCount":1,"resources":{"limits":{"cpu":"2","memory":"4Gi"},"requests":{"cpu":"200m","memory":"2Gi"}},"route":{"enabled":true,"tls":{"insecureEdgeTerminationPolicy":"Redirect","termination":"edge"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}},"service":{"type":"ClusterIP"},"solr":{"hostBind":"0.0.0.0","memory":"1g"},"tolerations":[],"topologySpreadConstraints":[]}
intelligentAssistant.okp.affinity Pod scheduling: affinity rules for the OKP pod. object {}
intelligentAssistant.okp.embeddingModel Sentence Transformers model ID used by Lightspeed Core for query embeddings. Must match the model used to index OKP content. string "ibm-granite/granite-embedding-small-english-r2"
intelligentAssistant.okp.enabled Enable OKP-backed RHDH documentation retrieval. Disabled by default on all platforms. bool false
intelligentAssistant.okp.imagePullSecrets Image pull secrets for the OKP container image. Required on vanilla Kubernetes to authenticate with registry.redhat.io. Not needed on OpenShift where the cluster-wide pull secret covers Red Hat registries. list []
intelligentAssistant.okp.livenessProbe Liveness probe configuration for the OKP container. object {"initialDelaySeconds":30,"periodSeconds":30}
intelligentAssistant.okp.nodeSelector Pod scheduling: node selector for the OKP pod. object {}
intelligentAssistant.okp.readinessProbe Readiness probe configuration for the OKP container. object {"initialDelaySeconds":10,"periodSeconds":10}
intelligentAssistant.okp.securityContext OKP container security context. readOnlyRootFilesystem is not set because Solr (Lucene) writes a lock file into its pre-built index directory at runtime. object {"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}
intelligentAssistant.okp.tolerations Pod scheduling: tolerations for the OKP pod. list []
intelligentAssistant.okp.topologySpreadConstraints Pod scheduling: topology spread constraints for the OKP pod. list []
intelligentAssistant.plugins Intelligent Assistant dynamic plugin packages. list [{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend"}]
intelligentAssistant.runtimeVolume Writable scratch volume for the sidecar (/tmp). object {"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}
intelligentAssistant.runtimeVolume.type Volume type: "emptyDir" or "persistentVolumeClaim". string "emptyDir"
lifecycleHooks Lifecycle hooks for the main RHDH container. Ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/ object {}
livenessProbe Liveness probe configuration. object {"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":1,"timeoutSeconds":4}
metrics Prometheus metrics configuration. object {"serviceMonitor":{"annotations":{},"enabled":false,"interval":"","labels":{},"path":"/metrics","port":"http-metrics"}}
nameOverride Override the chart name used in resource naming. string "developer-hub"
nodeSelector Node labels for pod assignment. object {}
openshift OpenShift-specific configuration. object {"clusterRouterBase":"apps.example.com","route":{"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","targetPort":"http-backend","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}}
openshift.clusterRouterBase Cluster router base domain used to auto-generate the hostname. string "apps.example.com"
openshift.route OpenShift Route configuration. object {"annotations":{},"enabled":true,"host":"{{ .Values.host }}","path":"/","targetPort":"http-backend","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}
orchestrator Orchestrator (Serverless workflows) configuration. object {"enabled":false,"plugins":[{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-orchestrator-backend"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-orchestrator"},{"enabled":true,"package":"ref://red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator"}],"serverlessLogicOperator":{"enabled":true},"serverlessOperator":{"enabled":true},"sonataflowPlatform":{"dataIndex":{"image":{"digest":"","registry":"","repository":"","tag":""}},"dbCreationJob":{"activeDeadlineSeconds":120,"backoffLimit":2,"image":{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"},"ttlSecondsAfterFinished":null},"eventing":{"broker":{"name":"","namespace":""}},"externalDB":{"existingSecret":"","host":"","name":"","port":""},"jobService":{"image":{"digest":"","registry":"","repository":"","tag":""}},"monitoring":{"enabled":true},"resources":{"limits":{"cpu":"500m","memory":"1Gi"},"requests":{"cpu":"250m","memory":"64Mi"}}}}
orchestrator.sonataflowPlatform.dataIndex SonataFlow Data Index service configuration. object {"image":{"digest":"","registry":"","repository":"","tag":""}}
orchestrator.sonataflowPlatform.dataIndex.image Override the Data Index container image. If empty, the operator default is used. object {"digest":"","registry":"","repository":"","tag":""}
orchestrator.sonataflowPlatform.dbCreationJob Database creation Job configuration. object {"activeDeadlineSeconds":120,"backoffLimit":2,"image":{"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"},"ttlSecondsAfterFinished":null}
orchestrator.sonataflowPlatform.dbCreationJob.image Container image for the create-db Job. object {"digest":"{{ .Values.postgresql.image.digest }}","registry":"{{ .Values.postgresql.image.registry }}","repository":"{{ .Values.postgresql.image.repository }}","tag":"{{ .Values.postgresql.image.tag }}"}
orchestrator.sonataflowPlatform.externalDB External database connection. Used when postgresql.enabled is false. object {"existingSecret":"","host":"","name":"","port":""}
orchestrator.sonataflowPlatform.externalDB.existingSecret Name of a Secret containing POSTGRES_HOST, POSTGRES_PORT, POSTGRES_USER, POSTGRES_PASSWORD keys. string ""
orchestrator.sonataflowPlatform.externalDB.host Database host (used in JDBC URLs). string ""
orchestrator.sonataflowPlatform.externalDB.name Database name to connect to for the CREATE DATABASE command. string ""
orchestrator.sonataflowPlatform.externalDB.port Database port (used in JDBC URLs). string ""
orchestrator.sonataflowPlatform.jobService SonataFlow Job Service configuration. object {"image":{"digest":"","registry":"","repository":"","tag":""}}
orchestrator.sonataflowPlatform.jobService.image Override the Job Service container image. If empty, the operator default is used. object {"digest":"","registry":"","repository":"","tag":""}
podAnnotations Annotations to add to the pod. object {}
podDisruptionBudget Pod Disruption Budget configuration. object {"create":false,"maxUnavailable":1,"minAvailable":""}
podLabels Labels to add to the pod. object {}
podSecurityContext Pod-level security context. object {}
postgresql Built-in PostgreSQL database (bitnami subchart). object {"auth":{"secretKeys":{"adminPasswordKey":"postgres-password","userPasswordKey":"password"}},"enabled":true,"image":{"digest":"","registry":"quay.io","repository":"fedora/postgresql-18","tag":"latest"},"postgresqlDataDir":"/var/lib/pgsql/data/userdata","primary":{"containerSecurityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"enabled":false},"extraEnvVars":[{"name":"POSTGRESQL_ADMIN_PASSWORD","valueFrom":{"secretKeyRef":{"key":"{{- include \"rhdh.postgresql.adminPasswordKey\" . }}","name":"{{- include \"rhdh.postgresql.secretName\" . }}"}}}],"networkPolicy":{"enabled":false},"persistence":{"enabled":true,"mountPath":"/var/lib/pgsql/data","size":"1Gi"},"podSecurityContext":{"enabled":false},"resources":{"limits":{"cpu":"250m","ephemeral-storage":"20Mi","memory":"1024Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}},"readReplicas":{"networkPolicy":{"enabled":false}},"serviceBindings":{"enabled":true}}
preInitContainers Init containers to run BEFORE the system init containers (e.g. inject auth credentials before install-dynamic-plugins runs). list []
priorityClassName Priority class name for pod scheduling. Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/ string ""
readinessProbe Readiness probe configuration. object {"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/readiness","port":"backend","scheme":"HTTP"},"periodSeconds":10,"successThreshold":2,"timeoutSeconds":4}
replicaCount Number of desired pods. int 1
resources Resource requests and limits for the main RHDH container. object {"limits":{"cpu":"1000m","ephemeral-storage":"5Gi","memory":"2.5Gi"},"requests":{"cpu":"250m","memory":"1Gi"}}
revisionHistoryLimit Number of old ReplicaSets to retain. int 10
service Service configuration. object {"annotations":{},"clusterIP":"","externalTrafficPolicy":"","extraPorts":[{"name":"http-metrics","port":9464,"targetPort":9464}],"ipFamilies":[],"ipFamilyPolicy":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePort":"","port":7007,"sessionAffinity":"","type":"ClusterIP"}
service.extraPorts Additional service ports. list [{"name":"http-metrics","port":9464,"targetPort":9464}]
service.ipFamilies IP families for dual-stack networking. list []
service.ipFamilyPolicy IP family policy for dual-stack networking. string ""
service.nodePort Node port for NodePort/LoadBalancer service types (range 30000-32767). string ""
serviceAccount ServiceAccount configuration. object {"annotations":{},"automount":true,"create":false,"labels":{},"name":""}
serviceAccount.labels Additional labels for the ServiceAccount. object {}
serviceAccount.name The name of the service account to use. If not set and create is true, a name is generated using the fullname template. string ""
startupProbe Startup probe configuration. Gives the application time to start before liveness/readiness probes kick in. object {"failureThreshold":3,"httpGet":{"path":"/.backstage/health/v1/liveness","port":"backend","scheme":"HTTP"},"initialDelaySeconds":30,"periodSeconds":20,"successThreshold":1,"timeoutSeconds":4}
strategy Deployment update strategy. object {}
terminationGracePeriodSeconds Duration in seconds the pod needs to terminate gracefully before being force killed. Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination string nil
test Test pod configuration for helm test. object {"enabled":true,"image":{"digest":"","pullPolicy":"IfNotPresent","registry":"quay.io","repository":"curl/curl","tag":"8.23.0"},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true}}
tolerations Tolerations for pod assignment. list []
topologySpreadConstraints Topology spread constraints for pod scheduling. list []
workload Kubernetes workload controller for Backstage pod. object {"kind":"Deployment","statefulSet":{"annotations":{},"extraVolumeClaimTemplates":[],"persistentVolumeClaimRetentionPolicy":{},"podManagementPolicy":"","serviceName":"","updateStrategy":{}}}
workload.kind Workload kind: Deployment (default) or StatefulSet. string "Deployment"
workload.statefulSet.annotations Annotations on the StatefulSet resource. object {}
workload.statefulSet.extraVolumeClaimTemplates Extra volumeClaimTemplates appended after the chart-managed dynamic-plugins-root claim (when type=statefulSetPVC). list []
workload.statefulSet.persistentVolumeClaimRetentionPolicy Optional PVC retention policy for the StatefulSet. object {}
workload.statefulSet.podManagementPolicy Pod management policy for the StatefulSet. string ""
workload.statefulSet.serviceName service name for the StatefulSet. Defaults to headless when empty. Service ({fullname}-headless) must match an existing service. string ""
workload.statefulSet.updateStrategy StatefulSet update strategy. object {}

Opinionated RHDH deployment

This chart defaults to an opinionated deployment of Red Hat Developer Hub that provides users with a usable instance out of the box.

Features enabled by the default chart configuration:

  1. Uses rhdh that pre-loads a lot of useful plugins and features
  2. Exposes a Route for easy access to the instance
  3. Enables OpenShift-compatible PostgreSQL database storage
  4. Built-in Intelligent Assistant feature (enabled by default)
  5. Dynamic plugins system with catalog index support

For additional instance features please consult the documentation for rhdh.

Additional features can be enabled by extending the default configuration at:

appConfig:
  # Inline app-config.yaml for the instance
extraEnv:
  # Additional environment variables (appended to system defaults)
extraVolumes:
  # Additional volumes (appended to system defaults)
extraVolumeMounts:
  # Additional volume mounts (appended to system defaults)
extraDeploy:
  # Additional Kubernetes resources deployed with the release

Features

This charts defaults to using the RHDH image that is OpenShift compatible:

quay.io/rhdh-community/rhdh:next

"Add, don't replace" pattern

System-required volumes, volume mounts, environment variables, init containers, and sidecar containers are hardcoded in the Backstage pod template (used by both Deployment and StatefulSet). User-provided extra* values are always appended after the system defaults:

  • extraVolumes — appended after dynamic-plugins-root, temp, npmcacache, extensions-catalog, etc.
  • extraVolumeMounts — appended after dynamic-plugins-root, extensions, temp mounts
  • extraEnv — appended after APP_CONFIG_backend_listen_port, BACKEND_SECRET, POSTGRES_* vars
  • extraInitContainers — appended after install-dynamic-plugins and Intelligent Assistant RAG init
  • extraContainers — appended after the Lightspeed Core sidecar

This means you never need to copy system defaults to add your own entries.

If you need full control, the corresponding *Override fields (envOverride, envFromOverride, commandOverride, argsOverride) replace the system defaults entirely — nothing is auto-injected when an override is set.

Workload kind (Deployment or StatefulSet)

By default, the chart creates a Kubernetes Deployment (workload.kind: Deployment). To use a StatefulSet instead:

# values.yaml
workload:
  kind: StatefulSet

Both kinds render the same Backstage pod (containers, volumes, probes, dynamic plugins, Intelligent Assistant, init containers). Only the workload controller changes; the pod definition is shared.

When to use StatefulSet

  • You need StatefulSet-specific settings (workload.statefulSet.updateStrategy, podManagementPolicy, extraVolumeClaimTemplates, or optional PVC retention policy).
  • You want parity with the RHDH Operator, which supports spec.deployment.kind: StatefulSet (operator documentation).

Most installs should keep the default Deployment (no app StatefulSet and no headless Service).

Values that behave the same for both kinds

replicaCount, autoscaling, probes, resources, dynamicPlugins, extraVolumes, podLabels, podAnnotations, and other pod-level settings apply regardless of workload.kind. When autoscaling.enabled is true, the HorizontalPodAutoscaler scales the selected kind (Deployment or StatefulSet).

Values that depend on the workload kind

Helm value Deployment StatefulSet
Update strategy strategy workload.statefulSet.updateStrategy
ReplicaSet revision history revisionHistoryLimit Not used
Controller annotations (not the pod) deploymentAnnotations workload.statefulSet.annotations
Shared controller annotations commonAnnotations commonAnnotations
PVC claim templates Not used workload.statefulSet.extraVolumeClaimTemplates
PVC retention policy Not used workload.statefulSet.persistentVolumeClaimRetentionPolicy

StatefulSet-only settings

When workload.kind is StatefulSet, the chart also renders a headless Service ({fullname}-headless, clusterIP: None). The StatefulSet serviceName points at that Service (stable pod network identity).

The existing ClusterIP Service (templates/service.yaml) is unchanged — OpenShift Routes, Ingress, and helm test still use it for application traffic.

Override workload.statefulSet.serviceName only if you create your own governing Service.

# values.yaml
workload:
  kind: StatefulSet
  statefulSet:
    serviceName: ""   # default: {fullname}-headless
    podManagementPolicy: OrderedReady   # or Parallel; omit when empty
    updateStrategy:
      type: RollingUpdate
    extraVolumeClaimTemplates: []
    persistentVolumeClaimRetentionPolicy: {}
    annotations: {}

Stable dynamic-plugins storage

To give each pod a StatefulSet-owned PVC for dynamic-plugins-root:

workload:
  kind: StatefulSet
dynamicPlugins:
  volume:
    type: statefulSetPVC
    statefulSetPVC:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 5Gi

The chart injects a volumeClaimTemplate named dynamic-plugins-root and mounts it on the pod. Kubernetes creates one PVC per pod named dynamic-plugins-root-{fullname}-{ordinal} (for example dynamic-plugins-root-my-rhdh-developer-hub-0). This requires workload.kind=StatefulSet.

To add additional StatefulSet-owned PVCs, use workload.statefulSet.extraVolumeClaimTemplates.

Changing workload.kind on an existing release

For a normal Helm-managed release, changing workload.kind and running helm upgrade replaces the rendered manifest: Helm removes the old workload kind (Deployment or StatefulSet) and creates the new one. Expect a brief cutover while pods are recreated. If you applied manifests outside Helm (for example GitOps that keeps both objects) or an old controller was left behind, delete the obsolete Deployment or StatefulSet so two controllers do not target the same selector.

Example install

helm upgrade -i my-rhdh redhat-developer/redhat-developer-hub \
  --set workload.kind=StatefulSet

OpenShift Routes

This chart offers an OpenShift Route resource enabled by default. In order to use the chart without it, please set openshift.route.enabled to false and switch to the Ingress resource via ingress values.

Routes can be further configured via the openshift.route field.

To manually provide the Backstage pod with the right context, please add the following value:

# values.yaml
openshift:
  clusterRouterBase: apps.example.com

Tip: you can use helm upgrade -i --set openshift.clusterRouterBase=apps.example.com ... instead of a value file

Custom hosts are also supported via the following shorthand:

# values.yaml
host: backstage.example.com

Note: The hostname is derived from host if set, otherwise from openshift.clusterRouterBase (as <release-name>-<chart-name>.<clusterRouterBase>). When both fields are set, host takes precedence. These are templating shorthands. For full manual control, configure the values under the openshift.route key directly.

Any custom modifications to how backstage is being exposed may require additional changes to the values.yaml:

# values.yaml
appConfig:
  app:
    baseUrl: 'https://{{- include "rhdh.hostname" . }}'
  backend:
    baseUrl: 'https://{{- include "rhdh.hostname" . }}'
    cors:
      origin: 'https://{{- include "rhdh.hostname" . }}'

Catalog Index Configuration

The chart supports automatic plugin discovery through a catalog index OCI image. This is configured via catalogIndex.image (with registry, repository, and tag fields) and lets you use a pre-defined set of dynamic plugins.

You can also configure additional catalog index images via catalogIndex.extraImages to make plugins from other sources discoverable in the Extensions UI. Each extra image contributes catalog entities only (no dynamic-plugins.default.yaml handling).

For detailed information on configuring the catalog index, including how to override the default image, use a private registry, or add extra catalog index images, see the Catalog Index Configuration documentation.

Extra Deployed Resources (extraDeploy)

Use extraDeploy to ship arbitrary Kubernetes resources alongside the chart release — NetworkPolicies, ConfigMaps, Secrets, Jobs, or any other kind. Each entry is rendered through tpl, so Helm template expressions are supported.

These resources are fully managed by Helm: they are created on install, updated on upgrade, and deleted on uninstall. Removing an entry from extraDeploy and running helm upgrade will delete the corresponding resource. This is in contrast to resources applied externally (e.g., via kubectl apply), which Helm does not track.

Entries can be objects (plain YAML) or strings (block scalars for multi-line template helpers like include).

Object form — template expressions work in individual string values:

extraDeploy:
  - apiVersion: v1
    kind: ConfigMap
    metadata:
      name: '{{ include "rhdh.fullname" . }}-my-config'
    data:
      key: value

String form — required when using helpers that expand into multiple YAML keys (e.g., rhdh.selectorLabels, rhdh.labels):

extraDeploy:
  - |
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: {{ include "rhdh.fullname" . }}-allow-http-egress
      labels:
        {{- include "rhdh.labels" . | nindent 8 }}
    spec:
      podSelector:
        matchLabels:
          {{- include "rhdh.selectorLabels" . | nindent 10 }}
      policyTypes:
        - Egress
      egress:
        - ports:
            - port: 80
              protocol: TCP

NetworkPolicies

This chart deploys a default-deny NetworkPolicy for the RHDH backend pod, blocking all ingress and egress traffic that is not explicitly allowed. When the built-in PostgreSQL is enabled (postgresql.enabled=true), the database pods also get their own default-deny policy with selective allow rules. When OKP is active, its pods receive a separate default-deny ingress and egress policy with rules allowing only the required HTTP ingress.

When orchestrator.enabled=true, the chart also creates NetworkPolicies for SonataFlow Data Index and Jobs Service pods (default-deny, then selective allow) and for other pods labeled app.kubernetes.io/managed-by: sonataflow-operator. These include RHDH ↔ SonataFlow access, scoped SonataFlow egress (DNS, HTTPS, Kubernetes API, PostgreSQL, and RHDH on port 7007), and (when built-in PostgreSQL is enabled) PostgreSQL ingress from SonataFlow-managed pods. The Orchestrator create-db Job uses rhdh.selectorLabels, so it is covered by the existing RHDH → PostgreSQL allow. These policies are label-scoped and do not use namespace-wide podSelector: {}.

The following traffic is allowed out of the box:

Direction Port Destination / Source Purpose
Egress 53, 5353 (UDP/TCP) Any DNS resolution
Egress 443 (TCP) Any HTTPS (Git forges, auth providers, external APIs)
Egress 6443 (TCP) Any Kubernetes API server — used by plugins that query cluster resources (Tekton, ArgoCD/GitOps, Topology, KServe model catalog, etc.). On some managed platforms the API server listens on 443 instead.
Egress 5432 (TCP) Built-in PostgreSQL pods (scoped) or any (external DB) Database access
Egress 6379 (TCP) Any Redis (BYO — no pod/namespace selector)
Egress 80 (TCP) Any destination LCORE access to an HTTP OKP Ingress (NP created only when OKP is enabled; disabled by default)
Egress 8080 (TCP) OKP pods LCORE access to the internal OKP Service fallback (NP created only when OKP is enabled; disabled by default)
Ingress 7007 (TCP) OpenShift router namespace or any namespace (non-OCP) User traffic via Route / Ingress
Ingress 8080 (TCP) RHDH pods and the OpenShift router namespace or any namespace (non-OCP) OKP queries and product-document citations via Route / Ingress
Ingress 9464 (TCP) openshift-monitoring, openshift-user-workload-monitoring, gmp-system, gke-gmp-system, monitoring Prometheus metrics scraping
Ingress any OpenShift router namespace → SonataFlow pods Orchestrator / SonataFlow Routes (NP created only when orchestrator.enabled=true)
Ingress any RHDH pods → SonataFlow pods Orchestrator backend to Data Index / workflows (NP created only when orchestrator.enabled=true)
Ingress any SonataFlow pods → SonataFlow pods (same or other namespaces) SonataFlow inter-pod ingress and egress (NP created only when orchestrator.enabled=true)
Ingress any knative-eventing, knative-serving, openshift-serverless-logic → SonataFlow pods Orchestrator infra namespaces (NP created only when orchestrator.enabled=true)
Ingress 8080 (TCP) openshift-monitoring, openshift-user-workload-monitoring, gmp-system, gke-gmp-system, monitoring → SonataFlow pods SonataFlow metrics scrape (NP created only when orchestrator.enabled=true and orchestrator.sonataflowPlatform.monitoring.enabled=true)
Ingress 7007 (TCP) SonataFlow pods → RHDH pods Workflows calling RHDH APIs (NP created only when orchestrator.enabled=true)
Egress any RHDH pods → SonataFlow pods Orchestrator backend to SonataFlow / Data Index (NP created only when orchestrator.enabled=true)
Egress 53, 5353 (UDP/TCP) SonataFlow pods → any SonataFlow DNS (NP created only when orchestrator.enabled=true)
Egress 443, 6443 (TCP) SonataFlow pods → any SonataFlow HTTPS and Kubernetes API (NP created only when orchestrator.enabled=true)
Egress 5432 (TCP) SonataFlow pods → built-in PostgreSQL (scoped) or any (external DB) SonataFlow database access (NP created only when orchestrator.enabled=true)
Egress 7007 (TCP) SonataFlow pods → RHDH pods Workflows calling RHDH APIs (NP created only when orchestrator.enabled=true)
Ingress 5432 (TCP) SonataFlow pods (same or other namespaces) → built-in PostgreSQL primary Orchestrator / SonataFlow database access (NP created only when orchestrator.enabled=true and postgresql.enabled=true)

OKP initiates no outbound connections: its HTTP server and Solr process run in the same pod and serve the documentation embedded in the image. Its default-deny policy therefore blocks all new egress connections. NetworkPolicy is stateful, so response traffic for allowed ingress connections remains permitted.

RHDH already permits HTTPS egress on port 443. When OKP uses HTTP instead, the chart permits RHDH egress on port 80 for a Kubernetes Ingress or restricts port 8080 egress to OKP pods for the internal Service fallback. No additional RHDH egress policy is created when OKP_SERVICE_URL uses HTTPS.

When Orchestrator is enabled (orchestrator.enabled=true), the chart first creates default-deny NetworkPolicies for the SonataFlow Data Index and Jobs Service pods, then selective allow policies for pods labeled app.kubernetes.io/managed-by: sonataflow-operator. These allow ingress from the Knative Eventing/Serving and OpenShift Serverless Logic namespaces, from the OpenShift router (any port), from other SonataFlow pods in the same or other namespaces (ingress and egress), from RHDH (any port), and (when orchestrator.sonataflowPlatform.monitoring.enabled=true) from known monitoring namespaces on port 8080. SonataFlow egress is scoped to DNS, HTTPS (443), the Kubernetes API (6443), PostgreSQL (5432), and RHDH on port 7007; additional destinations must be allowed explicitly. Separately, the RHDH backend pod (selected via rhdh.selectorLabels) is allowed to reach SonataFlow pods (any port), and SonataFlow pods are allowed to reach RHDH on port 7007. When the built-in PostgreSQL is enabled (postgresql.enabled=true), Postgres admits TCP/5432 from SonataFlow-managed pods in the same or other namespaces; the Orchestrator create-db Job uses rhdh.selectorLabels and is covered by the existing RHDH backend PostgreSQL allow.

Redis egress is intentionally unscoped. RHDH does not deploy Redis; users bring their own instance, which may live in the same namespace, a different namespace, or an external managed service. The rule therefore allows egress on port 6379 to any destination.

Bitnami subchart NetworkPolicies are disabled (postgresql.primary.networkPolicy.enabled=false, postgresql.readReplicas.networkPolicy.enabled=false) because this chart provides its own tighter policies for the built-in database pods.

Helm test NetworkPolicies (allow-test-connection and allow-test-connection-ingress) are Helm test hooks: they are created just before helm test runs and cleaned up automatically on success.

Adding your own NetworkPolicies. Kubernetes evaluates NetworkPolicies additively — if any policy allows a connection, the connection is permitted. You cannot tighten an existing allow rule by adding another NetworkPolicy; you can only broaden access. To add extra allow rules (for example, allowing HTTP egress to an internal auth provider), use extraDeploy or apply your own NetworkPolicy resources externally:

extraDeploy:
  - |
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: {{ include "rhdh.fullname" . }}-allow-http-egress
    spec:
      podSelector:
        matchLabels:
          {{- include "rhdh.selectorLabels" . | nindent 10 }}
      policyTypes:
        - Egress
      egress:
        - ports:
            - port: 80
              protocol: TCP

For more information on user workload monitoring on OpenShift, see Configuring user workload monitoring.

Intelligent Assistant

Use intelligentAssistant.enabled to enable or disable the built-in Intelligent Assistant feature.

When enabled, the chart adds the default Intelligent Assistant dynamic plugins (ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant and ref://red-hat-developer-hub-backstage-plugin-intelligent-assistant-backend), a Lightspeed Core sidecar listening on port 8080, chart-generated ConfigMaps, and a writable runtime volume. Override intelligentAssistant.plugins for disconnected environments. Plugin app-config uses the intelligent-assistant: namespace (not lightspeed:).

The bundled lightspeed-stack.yaml does not enable an LLM inference provider. Create a provider-enabled stack in a ConfigMap and reference it with intelligentAssistant.config.stack.existingConfigMap. Supply that provider's credentials and settings with intelligentAssistant.existingSecret; the chart does not create the Secret.

This is a breaking change from chart 1.x: rename lightspeed: to intelligentAssistant: in your values. Chart-generated ConfigMaps are named {fullname}-ia-{stack,profile} instead of {fullname}-lightspeed-*, so Helm replaces those objects on upgrade. The ia infix is used because Kubernetes names are limited to 63 characters.

Chart 2.1.0 removes intelligentAssistant.config.server and the separate Llama Stack config.yaml. Remove the server entry from existing values. Move custom Llama Stack settings into the lightspeed-stack.yaml supplied through intelligentAssistant.config.stack.existingConfigMap.

Use intelligentAssistant.runtimeVolume to change the writable /tmp runtime storage between emptyDir and an existing PVC reference. The chart mounts that volume at /tmp so both generated temporary files and /tmp/data remain writable.

When using the built-in Intelligent Assistant feature, do not also keep those plugin packages in dynamicPlugins.plugins. Existing installations that previously configured Lightspeed or Intelligent Assistant there should remove those entries if the built-in defaults are sufficient, or move their custom package definitions to intelligentAssistant.plugins; otherwise the rendered dynamic-plugins.yaml will contain duplicate plugin entries.

The Lightspeed Core sidecar loads intelligentAssistant.existingSecret as environment variables. If you update that Secret outside of Helm, Kubernetes does not guarantee that the Backstage Pod restarts automatically. Use a no-op helm upgrade or manually restart the Backstage workload (Deployment or StatefulSet) after changing the secret data.

RHDH documentation retrieval is disabled by default in Intelligent Assistant. To enable it, set intelligentAssistant.okp.enabled=true. This deploys the OKP workload and uses the OKP-enabled Lightspeed Stack configuration. The OKP container image is large, so enabling it can significantly increase the initial installation time while the image is downloaded. On vanilla Kubernetes, you must also configure the OKP Ingress and Red Hat registry credentials. See Intelligent Assistant and OKP integration for platform-specific configuration.

Vanilla Kubernetes compatibility mode

To deploy this chart on vanilla Kubernetes or any other non-OCP platform, apply the following changes. Note that further customizations might be required, depending on your exact Kubernetes setup:

# values.yaml
host: # Specify your own Ingress host
openshift:
  route:
    enabled: false  # OpenShift Routes do not exist on vanilla Kubernetes
ingress:
  enabled: true  # Use Kubernetes Ingress instead of OpenShift Route
podSecurityContext:  # Vanilla Kubernetes doesn't feature OpenShift default SCCs with dynamic UIDs, adjust accordingly to the deployed image
  fsGroup: 1001
postgresql:
  primary:
    podSecurityContext:
      enabled: true
      fsGroup: 26
  volumePermissions:
    enabled: true

Installing RHDH with Orchestrator on OpenShift

Orchestrator brings serverless workflows into Backstage, focusing on the journey for application migration to the cloud, onboarding developers, and user-made workflows of Backstage actions or external systems. Orchestrator is a flavor of RHDH, and can be installed alongside RHDH in the same namespace and in the following way:

  1. Have an admin install the orchestrator-infra Helm Chart, which will install the prerequisites required to deploy the Orchestrator-flavored RHDH. This process will include installing cluster-wide resources, so should be done with admin privileges:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add redhat-developer https://redhat-developer.github.io/rhdh-chart

helm install <release_name> redhat-developer/redhat-developer-hub-orchestrator-infra
  1. Manually approve the Install Plans created by the chart, and wait for the Openshift Serverless and Openshift Serverless Logic Operators to be deployed. To do so, follow the post-install notes given by the chart, or see them here
  2. Install the redhat-developer-hub chart with Helm, enabling orchestrator, like so:
helm install <release_name> redhat-developer/redhat-developer-hub --set orchestrator.enabled=true

Enabling Orchestrator also creates label-scoped NetworkPolicies for SonataFlow-managed pods (default-deny for Data Index and Jobs Service, then selective allows), for RHDH ↔ SonataFlow access, and (when built-in PostgreSQL is enabled) for SonataFlow access to Postgres on TCP/5432; they are not namespace-wide. See NetworkPolicies for details. Note that serverlessLogicOperator, and serverlessOperator are enabled by default. They can be disabled together or seperately by passing the following flags: --set orchestrator.serverlessLogicOperator.enabled=false --set orchestrator.serverlessOperator.enabled=false

Enablement of Notifications Plugin

Workflows running with Orchestrator may use the Notifications plugin. For this, you must enable the Notifications and Signals plugins. To do so, add the plugins listed below to the dynamicPlugins.plugins list in your values file. Do this before installing the Helm Chart, or upgrade the Helm release with the new values file.

dynamicPlugins:
  plugins:
    - enabled: true
      package: "./dynamic-plugins/dist/backstage-plugin-notifications"
    - enabled: true
      package: "./dynamic-plugins/dist/backstage-plugin-signals"
    - enabled: true
      package: "./dynamic-plugins/dist/backstage-plugin-notifications-backend-dynamic"
    - enabled: true
      package: "./dynamic-plugins/dist/backstage-plugin-signals-backend-dynamic"

Enabling these plugins will allow you to receive notifications from workflows running with Orchestrator.

Using Orchestrator while configuring an ExternalDB

To use orchestrator with an external DB, please follow the instructions in our documentation and populate the following values in the values.yaml:

orchestrator:
  sonataflowPlatform:
    externalDB:
      existingSecret: <cred-secret>
      name: ""
      host: ""
      port: ""

The values for host and port should match the ones configured in the credential secret.

Please note that externalDB.name is the name of the user-configured existing database, not the database that the orchestrator and sonataflow resources will use. A Job will run to create the 'sonataflow' database in the external database for the workflows to use.

Finally, install the Helm Chart (including setting up the external DB):

helm install <release_name> redhat-developer/redhat-developer-hub \
  --set orchestrator.enabled=true \
  --set orchestrator.sonataflowPlatform.externalDB.existingSecret=<cred-secret> \
  --set orchestrator.sonataflowPlatform.externalDB.name=example \
  --set orchestrator.sonataflowPlatform.externalDB.host=example \
  --set orchestrator.sonataflowPlatform.externalDB.port=example