Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cc5ad91
Creating workload templates
OpinionatedHeron Sep 14, 2026
b4f757b
Bumping chart version
OpinionatedHeron Sep 14, 2026
01474e0
Enabling opt-in statefulset
OpinionatedHeron Sep 17, 2026
a82ae7b
Syncing with ustream & updating Readme
OpinionatedHeron Sep 17, 2026
d658633
Adding headless service
OpinionatedHeron Sep 17, 2026
8077df1
Adding ci values for stateful set & updating ReadMe
OpinionatedHeron Sep 17, 2026
50dcb58
Making fixes based on testing and review
OpinionatedHeron Sep 17, 2026
09b7e6f
Ci test fixes
OpinionatedHeron Sep 17, 2026
cf7a07f
Removing workload
OpinionatedHeron Sep 18, 2026
443b27d
Fixing appVersion
OpinionatedHeron Sep 18, 2026
01a5a2f
Fixing values formatting
OpinionatedHeron Sep 20, 2026
5b2798d
Adding volumeClaimTemplates
OpinionatedHeron Sep 21, 2026
3816a16
Small formatting fixes
OpinionatedHeron Sep 21, 2026
dfadd66
Truncating long name - qodo bug fix
OpinionatedHeron Sep 21, 2026
1fd5322
Merge remote-tracking branch 'upstream' into stateful
OpinionatedHeron Sep 21, 2026
ff59fa3
Removing unused helpers
OpinionatedHeron Sep 21, 2026
2dfee61
Updating to .Values.workload.kind
OpinionatedHeron Sep 21, 2026
6881ba0
Fixing values.yaml & adding statefulSetPVC
OpinionatedHeron Sep 21, 2026
b0d9f58
Updating _backstage-pod-template to mount statefulSetPVC
OpinionatedHeron Sep 21, 2026
49967bd
Fixing merge conflicts with upstream
OpinionatedHeron Sep 21, 2026
a52049a
Updating statefulset.yaml
OpinionatedHeron Sep 21, 2026
3341e03
Updating values schema and README
OpinionatedHeron Sep 21, 2026
7fd570a
Updating ci to include plugins VCT
OpinionatedHeron Sep 21, 2026
f61240f
Making fixes after review
OpinionatedHeron Sep 21, 2026
4bb2dc5
Fixing comments
OpinionatedHeron Sep 21, 2026
80d8489
Merge upstream/main into stateful
OpinionatedHeron Sep 21, 2026
9d9363f
Applying suggestions
OpinionatedHeron Sep 22, 2026
c0f57fa
Merge branch 'main' into stateful
OpinionatedHeron Sep 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion charts/rhdh/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: v2
name: redhat-developer-hub
type: application
version: 3.0.0
version: 3.1.0
appVersion: 2.1.0
annotations:
artifacthub.io/category: integration-delivery
Expand Down
116 changes: 108 additions & 8 deletions charts/rhdh/README.md

Large diffs are not rendered by default.

94 changes: 91 additions & 3 deletions charts/rhdh/README.md.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ helm install my-rhdh redhat-developer/redhat-developer-hub --version {{ template

This chart bootstraps a [Red Hat Developer Hub](https://developers.redhat.com/rhdh) deployment on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.

Unlike the legacy `backstage` chart, this chart owns all Kubernetes templates directly (Deployment, Service, ConfigMap, etc.) without depending on an upstream Backstage subchart. It uses an **"add, don't replace"** pattern: system-required volumes, volume mounts, environment variables, and init containers are hardcoded in the Deployment template, while user-provided values (`extraVolumes`, `extraVolumeMounts`, `extraEnv`, `extraInitContainers`, `extraContainers`) are always appended — never replacing the defaults.
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

Expand Down Expand Up @@ -195,7 +195,7 @@ 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 Deployment template. User-provided `extra*` values are always **appended** after the system defaults:
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
Expand All @@ -207,6 +207,94 @@ 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:

```yaml
# 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](https://github.com/redhat-developer/rhdh-operator), which supports `spec.deployment.kind: StatefulSet` ([operator documentation](https://github.com/redhat-developer/rhdh-operator/blob/main/docs/configuration.md#deployment-kind)).

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.
```yaml
# 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`:

```yaml
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-redhat-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**

```console
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.
Expand Down Expand Up @@ -303,7 +391,7 @@ Use `intelligentAssistant.runtimeVolume` to change the writable `/tmp` runtime s

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 deployment after changing the secret data.
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](../../docs/intelligent-assistant.md) for platform-specific configuration.

Expand Down
16 changes: 16 additions & 0 deletions charts/rhdh/ci/with-statefulset-values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# CI: render/install with workload.kind=StatefulSet (expects headless Service + StatefulSet + plugins VCT).
dynamicPlugins:
includes: []
volume:
type: statefulSetPVC
workload:
kind: StatefulSet
intelligentAssistant:
plugins: []
okp:
route:
enabled: false
ingress:
enabled: false
orchestrator:
plugins: []
Loading
Loading