Skip to content

Install with Helm

Install Dreadnode on an existing Kubernetes cluster using the Helm CLI.

Terminal window
helm registry login registry.replicated.com \
--username <your-email> \
--password <license-id>
export NAMESPACE=dreadnode
helm install dreadnode oci://registry.replicated.com/dreadnode/dreadnode \
--version <version> \
--namespace "$NAMESPACE" \
--create-namespace \
-f values.yaml

That’s the full install. The rest of this page covers what goes into values.yaml, what your cluster needs before you run the command, and how to verify the install afterward.

Your cluster needs four things.

Kubernetes 1.28 or later. The chart gates this in kubeVersionhelm install will refuse to run on older clusters.

A StorageClass with dynamic provisioning. PostgreSQL, ClickHouse, and MinIO each claim a PersistentVolume at install time. No StorageClass means those PVCs stay Pending forever.

An ingress controller. The chart emits standard networking.k8s.io/v1 Ingress resources and does not install a controller. Traefik is tested and recommended — install it separately before deploying Dreadnode. Other controllers (ingress-nginx, Contour, ALB) work in principle but are untested; you may need controller-specific annotations via global.ingress.annotations.

DNS records pointing at your ingress controller for two hostnames:

  • <your-domain> — serves the frontend at / and the API at /api
  • storage.<your-domain> — serves the MinIO S3 API

MinIO needs its own subdomain because S3 SDKs sign requests against host+path. Path-prefix routing breaks signature validation.

With bundled data stores and OpenSandbox enabled, the default small preset requests roughly 1.6 vCPU and 4.8 Gi across its always-on workloads. Provision 4 vCPU and 8 Gi as a practical floor so the platform has room alongside the ingress controller and Kubernetes system workloads.

Preset options: small (~50 users), medium (~50–200), large (200+). Set via global.resourcesPreset in your values overlay. See Configuration — Resource sizing for the per-preset numbers.

Your license file from Dreadnode contains the license ID. Use it to authenticate with the Replicated registry:

Terminal window
helm registry login registry.replicated.com \
--username <your-email> \
--password <license-id>

Image pulls are proxied through proxy.enterprise.dreadnode.io using credentials bound to your license. No manual imagePullSecrets wiring is needed.

global.domain is the only required field. Enable the bundled LiteLLM proxy in the same overlay if this install should serve dn/* models:

global:
domain: dreadnode.example.com
dreadnode-litellm:
enabled: true
dreadnode-api:
config:
litellm:
enabled: true

The model list starts empty. Save a provider credential, then add a model from Admin → Model Deployments after installation. See First model deployment.

To start with HTTPS (recommended if you have certificate material ready):

global:
domain: dreadnode.example.com
scheme: https
tls:
secretName: dreadnode-tls

Create the TLS Secret before running helm install — see TLS certificates.

global:
# Ingress class if your controller isn't the cluster default
ingress:
className: traefik
# Scale resources for larger deployments
resourcesPreset: medium # small (default) | medium | large

Inspect the chart’s full values surface with helm show values oci://registry.replicated.com/dreadnode/dreadnode --version <version>. Most base install and networking choices live under global.*; the focused Configure pages show the subchart values for data stores, sandboxes, authentication, and scaling.

Terminal window
export NAMESPACE=dreadnode
helm install dreadnode oci://registry.replicated.com/dreadnode/dreadnode \
--version <version> \
--namespace "$NAMESPACE" \
--create-namespace \
-f values.yaml

For releases on the Stable channel, the URL is oci://registry.replicated.com/dreadnode/dreadnode. Beta and Unstable releases include the channel: oci://registry.replicated.com/dreadnode/beta/dreadnode.

The chart defaults to HTTP so the first install can complete before certificate material exists. Production installs should enable TLS. Follow TLS certificates to prepare a certificate, create the Secret, configure the values overlay, and verify the certificate selected by your ingress controller.

Every subchart Ingress — API, frontend, and MinIO — picks up global.tls.secretName automatically against its respective hostname. If your API and MinIO traffic terminate on different load balancers with different certificates, see Per-ingress TLS.

Terminal window
kubectl -n "$NAMESPACE" get pods -l app.kubernetes.io/instance=dreadnode -w

All pods should reach Ready within a few minutes. If any stay Pending, check for missing StorageClass or insufficient resources. If pods crash-loop, check logs:

Terminal window
kubectl -n "$NAMESPACE" logs deploy/dreadnode-api
Terminal window
curl http://dreadnode.example.com/api/v1/health
# {"status":"ok"}

If DNS isn’t configured yet, port-forward the ingress controller — not individual pods:

Terminal window
kubectl port-forward -n traefik svc/traefik 8080:80

Add an /etc/hosts entry mapping your domain and storage.<domain> to 127.0.0.1, then open http://<your-domain>:8080/ in a browser.

File and package transfers fail on this port: presigned storage URLs point at http://storage.<domain>/ without a port. To smoke-test uploads and downloads too, forward port 80 instead (binding it requires root) and open http://<your-domain>/:

Terminal window
sudo kubectl port-forward -n traefik svc/traefik 80:80

Pods running is not a finished install. Continue with the post-install steps, which are the same on both install paths:

  1. First admin account — sign in and claim platform ownership
  2. First model deployment — every model picker stays empty until you add one
  3. Connect clients — point the TUI, CLI, and SDK at your deployment

Your Hub starts empty. See Loading Hub content to populate it with capabilities, task environments, and task sets from another platform.

The chart generates random passwords for the bundled data stores. Retrieve them if you need direct database access:

Terminal window
# PostgreSQL
kubectl -n "$NAMESPACE" get secret dreadnode-postgresql \
-o jsonpath='{.data.password}' | base64 -d
# ClickHouse
kubectl -n "$NAMESPACE" get secret dreadnode-clickhouse \
-o jsonpath='{.data.admin-password}' | base64 -d
# MinIO
kubectl -n "$NAMESPACE" get secret dreadnode-minio \
-o jsonpath='{.data.rootPassword}' | base64 -d

These secrets are annotated with helm.sh/resource-policy: keep — they survive helm uninstall so reinstalls reuse the same credentials. The Fernet encryption key (dreadnode-api-encryption) is also kept; without it, encrypted user secrets in Postgres are unrecoverable.

Terminal window
helm upgrade dreadnode oci://registry.replicated.com/dreadnode/dreadnode \
--version <new-version> \
--namespace "$NAMESPACE" \
-f values.yaml

Review the release notes before changing <new-version>. Migrations are forward-only, so helm rollback is disabled — see Upgrades for release notifications, what runs during an upgrade, and recovery. If an upgrade produces an unrecoverable state, the supported path is a clean reinstall — see Reinstall from scratch.

helm uninstall removes workloads but leaves PVCs and keep-annotated Secrets behind. For a true clean slate:

Terminal window
helm uninstall dreadnode -n "$NAMESPACE"
# Delete persistent data
kubectl -n "$NAMESPACE" delete pvc \
data-dreadnode-postgresql-0 \
data-dreadnode-clickhouse-0 \
data-dreadnode-minio-0
# Delete keep-annotated secrets
kubectl -n "$NAMESPACE" delete secret \
dreadnode-postgresql \
dreadnode-clickhouse \
dreadnode-minio \
dreadnode-api-encryption

Then run helm install again as if starting fresh.