# Open-sourced helm chart for run:AI

> Source: <https://github.com/logicalclocks/run-ai-helm>
> Published: 2026-10-15 12:11:30+00:00

Installs NVIDIA Run:ai (control plane and cluster) and the KAI Scheduler it schedules with

The chart wraps the published upstream charts and adds the glue between them: release profiles, validation, the Secrets the upstream charts expect to exist, and the cluster registration step.

| Subchart | Upstream chart | Version | Repository | 
|---|---|---|---|
| `controlplane` | `control-plane` | 3.0.20 | `https://helm.ngc.nvidia.com/nvidia/runai-oss` | 
| `cluster` | `runai-cluster` (bundles`kai-resource-management` v0.18.3 and`kai-scheduler` v0.18.3) | 3.0.20 | `https://helm.ngc.nvidia.com/nvidia/runai-oss` | 
| `kai` | `kai-scheduler` | v0.18.3 | `oci://ghcr.io/kai-scheduler/kai-scheduler` | 
| `monitoring` | `kube-prometheus-stack` | 76.2.0 | `https://prometheus-community.github.io/helm-charts` | 
| `gpu` | `gpu-operator` ,`fake-gpu-operator` | v26.7.1, 0.0.62 | `https://helm.ngc.nvidia.com/nvidia` ,`oci://ghcr.io/run-ai/fake-gpu-operator` | 
| `runailib` | library chart with the shared helpers |  |  | 

The chart is installed once per namespace. Each release enables its components with a profile file:

| Order | Release | Namespace | Profile | Installs | 
|---|---|---|---|---|
| 1 | `runai-prerequisites` | any ( `runai-prerequisites` ) | `values.prerequisites.yaml` | Prometheus Operator, NVIDIA GPU Operator (or the fake GPU operator with `values.dev.yaml` ) | 
| 2 | `runai-backend` | `runai-backend` | `values.control-plane.yaml` | Run:ai control plane: backend services, UI, Keycloak, PostgreSQL, Thanos, NATS | 
| 3 | `runai-cluster` | `runai` | `values.cluster.yaml` | Run:ai cluster: operator, admission, agent, KAI Scheduler | 
|  | `kai-scheduler` | `kai-scheduler` | `values.kai-scheduler.yaml` | KAI Scheduler alone, for clusters without Run:ai | 

The control plane and the cluster cannot share a release. The cluster's pre-install hooks call
the control-plane API with a cluster UUID and a bootstrap token, and the control plane issues
both only once it is running. `scripts/register_cluster.sh` registers the cluster and writes them
to a values file for release 3.

KAI Scheduler comes with release 3: `runai-cluster` depends on `kai-resource-management`, which
depends on `kai-scheduler`. The Run:ai operator writes KAI's `Config` and the
`kai-resource-management` node-pool controller writes one `SchedulingShard` per node pool. The
standalone `kai-scheduler` profile is for clusters that run KAI without Run:ai,
and the chart refuses to render it together with the cluster profile.

- Kubernetes >= 1.30, Helm 3.x or 4.x, `kubectl` ,`curl` ,`jq` .
- An ingress controller. The control plane creates an `Ingress` with class`nginx` by default
(`global.ingress.ingressClass` ,`nginx` or`haproxy` ). OpenShift uses Routes.
- A DNS name for the control plane (`global.domain` ) that resolves to the ingress controller, both
from where`scripts/install.sh` runs and from inside the cluster.
- A TLS certificate for `global.domain` : PEM in`controlplane.tls` , a cert-manager issuer in`controlplane.tls.certManager` , or a`kubernetes.io/tls` Secret`runai-backend-tls` created in
namespace`runai-backend` before the install.
- A default StorageClass for the PostgreSQL, Thanos (100Gi) and NATS volumes.
- A Prometheus Operator and an NVIDIA GPU stack (DCGM exporter). Release 1 installs both; skip it
with `--skip-prerequisites` when the cluster already has them.

From a git checkout:

```
./helm_dependencies.sh
scripts/install.sh --domain runai.example.com -f my-values.yaml
```

`my-values.yaml` is passed to every release. A minimal one with a certificate for the domain:

```
controlplane:
  tls:
    certificate: |
      -----BEGIN CERTIFICATE-----
      ...
    key: |
      -----BEGIN PRIVATE KEY-----
      ...
```

When the certificate is signed by a private CA, also set the CA so the cluster components trust it:

```
global:
  customCA:
    enabled: true
  _runai:
    customCA:
      certificate: |
        -----BEGIN CERTIFICATE-----
        ...
```

and pass `--cacert ca.pem` to `scripts/install.sh` for the registration calls.

`scripts/install.sh --help` lists the options: `--skip-prerequisites`, `--skip-control-plane`,
`--skip-cluster`, `--dev` (fake GPUs), `--cluster-name`, `--admin-user`, `--cacert`,
`--insecure`, `--timeout`.

The UI is at `https://<global.domain>`. The admin user is `test@run.ai`
(`controlplane.control-plane.tenantsManager.config.adminUsername`) and its password is generated:

```
kubectl get secret runai-backend-gen-tenants-manager -n runai-backend \
  -o jsonpath='{.data.ADMIN_PASSWORD}' | base64 -d
helm upgrade --install runai-prerequisites . -n runai-prerequisites --create-namespace \
  -f values.prerequisites.yaml --wait

helm upgrade --install runai-backend . -n runai-backend --create-namespace \
  -f values.control-plane.yaml -f my-values.yaml --set global.domain=runai.example.com \
  --wait --wait-for-jobs --timeout 20m

scripts/register_cluster.sh --domain runai.example.com --output cluster-registration.yaml

helm upgrade --install runai-cluster . -n runai --create-namespace \
  -f values.cluster.yaml -f my-values.yaml -f cluster-registration.yaml \
  --wait --wait-for-jobs --timeout 20m
```

`cluster-registration.yaml` holds a bootstrap token. The control plane mints a new one on every
call, so regenerate the file before each install or upgrade of `runai-cluster`.

```
scripts/install.sh --domain runai.example.com --dev -f my-values.yaml
kubectl label node <node> run.ai/simulated-gpu-node-pool=default
```

`values.dev.yaml` replaces the NVIDIA GPU Operator with the fake GPU operator, which reports
8 Tesla-A10 GPUs on each labelled node.

```
helm upgrade --install kai-scheduler . -n kai-scheduler --create-namespace \
  -f values.kai-scheduler.yaml --wait
```

KAI creates the queues `default-parent-queue` and `default-queue` on first install. Pods opt in
with `schedulerName: kai-scheduler` and the label `kai.scheduler/queue: default-queue`.

Layer `values.openshift.yaml` on every release. Upstream detects OpenShift with `lookup`, which
returns nothing under `helm template`, so the file states it: it sets
`global.config.kubernetesDistribution: openshift` (Routes and SCCs in the control plane) and
forces OpenShift mode in `runai-cluster`, `kai-resource-management` and `kai-scheduler`. Leave
`global._runai.monitoring` off: the Run:ai operator uses `openshift-monitoring`.

ArgoCD renders with `helm template`, so:

- Set `global._runai.mode: install` (or`upgrade` ):`lookup` returns nothing, and the chart then
renders the`runai-reservation` Namespace unconditionally.
- Create one Application per release, synced in the order of the table above.
- The cluster Application needs the registration values. Run `scripts/register_cluster.sh` and
store its output in a Secret-backed values source, since it holds a bootstrap token.

The Run:ai cluster takes its routing settings through `clusterConfig`, a merge patch into its
`RunaiConfig`. To use HAProxy instead of nginx:

```
cluster:
  runai-cluster:
    clusterConfig:
      global:
        ingress:
          ingressClass: haproxy
```

NVIDIA also publishes the commercial Run:ai line (2.x) as `control-plane` and `runai-cluster` in
`https://helm.ngc.nvidia.com/nvidia/runai`, which needs an NGC API key. Those charts take the
same install values (`controlPlane.url`, `controlPlane.clientSecret`, `cluster.uid`,
`cluster.url`, `clusterConfig`). Their `runai-cluster` 2.26.50 schedules with the proprietary
`runai-engine` (v3.41.19, from `nvcr.io/artifactory`) instead of KAI Scheduler. This chart wraps the
open-source 3.x line from `nvidia/runai-oss`.

Each subchart passes its upstream chart's values one level down, for example
`controlplane.control-plane.keycloakx`, `cluster.runai-cluster.kai-resource-management` or
`monitoring.kube-prometheus-stack.grafana`. The upstream charts also read these globals:

| Key | Read by | Purpose | 
|---|---|---|
| `global.domain` | control plane | FQDN of the control plane | 
| `global.ingress.ingressClass` | control plane | `nginx` (default) or`haproxy` | 
| `global.config.kubernetesDistribution` | control plane | `kubernetes` or`openshift` | 
| `global.image.registry` | control plane, cluster | Registry for Run:ai images (default `nvcr.io/nvidia/runai-oss` ) | 
| `global.customCA.enabled` | control plane, cluster | Trust the CA in Secret `runai-ca-cert` | 
| `global.imagePullSecrets` | control plane, KAI | Pull secrets as `[{name: ...}]` | 
| `global.additionalImagePullSecrets` | cluster | Pull secrets as a list of names | 

| Key | Type | Default | Description | 
|---|---|---|---|
| cluster | object | `{}` | Cluster subchart: the upstream values under cluster.runai-cluster, including the registration values and KAI under cluster.runai-cluster.kai-resource-management.kai-scheduler. See charts/cluster/values.yaml. | 
| controlplane | object | `{}` | Control-plane subchart: TLS for global.domain, and the upstream values under controlplane.control-plane. See charts/controlplane/values.yaml. | 
| global._runai.cluster.enabled | bool | `false` | Run:ai cluster, including KAI Scheduler. Release namespace must be runai. Needs a running control plane and the values scripts/register_cluster.sh writes. | 
| global._runai.controlPlane.enabled | bool | `false` | Run:ai control plane. Release namespace must be runai-backend. | 
| global._runai.customCA.certificate | string | `""` | PEM CA bundle rendered into the runai-ca-cert Secret of the release namespace when global.customCA.enabled is true. Leave empty to create runai-ca-cert yourself. | 
| global._runai.gpu.enabled | bool | `false` | NVIDIA GPU Operator, or the fake GPU operator (gpu.fake-gpu-operator.enabled). | 
| global._runai.kaiScheduler.enabled | bool | `false` | Standalone KAI Scheduler, without Run:ai. Upstream documents namespace kai-scheduler. Never together with cluster, which bundles KAI. | 
| global._runai.mode | string | `"auto"` | "auto" lets templates call lookup. Set "install" or "upgrade" when rendering with `helm template` (ArgoCD), where lookup returns nothing. | 
| global._runai.monitoring.enabled | bool | `false` | kube-prometheus-stack. The Run:ai cluster requires a Prometheus Operator. | 
| global._runai.registry.password | string | `""` | Registry password or token. | 
| global._runai.registry.server | string | `""` | Registry host for the control-plane pull secret runai-reg-creds. Nothing is rendered unless server, username and password are all set. The images on nvcr.io/nvidia/runai-oss are public. | 
| global._runai.registry.username | string | `""` | Registry user. | 
| global.customCA.enabled | bool | `false` | Trust the CA in Secret runai-ca-cert (key runai-ca.pem). Needed when the control-plane certificate is not signed by a public CA. | 
| global.domain | string | `""` | FQDN the control plane is served on. Required by the controlPlane component. | 
| global.imagePullSecrets | list | `[]` | Pull secrets for control-plane and KAI pods, as [{name: }]. The Run:ai cluster reads global.additionalImagePullSecrets (a list of names) instead. | 
| gpu | object | `{}` | GPU subchart: gpu.gpu-operator and gpu.fake-gpu-operator, each with an enabled switch. | 
| kai | object | `{}` | Standalone KAI subchart: the upstream values under kai.kai-scheduler. | 
| monitoring | object | `{}` | Monitoring subchart: the upstream values under monitoring.kube-prometheus-stack. |
