Skip to content

Helm Install

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>
helm install dreadnode oci://registry.replicated.com/dreadnode/dreadnode \
--version <version> \
-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.

The chart’s small preset (default) totals roughly 4 vCPU and 8 Gi of requests across all components. Your cluster needs at least that much allocatable capacity, plus headroom for the ingress controller and system workloads.

Preset options: small (~50 users), medium (~50–200), large (200+). Set via global.resourcesPreset in your values overlay.

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.

The only required field is global.domain. Everything else has production-ready defaults.

global:
domain: dreadnode.example.com

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 below.

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

The chart’s full values surface is documented in the values reference. Most customers don’t need to touch anything beyond global.*.

Terminal window
helm install dreadnode oci://registry.replicated.com/dreadnode/dreadnode \
--version <version> \
-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.

1. Create a TLS Secret. The certificate must cover both <your-domain> and storage.<your-domain> — use a SAN list or wildcard.

Terminal window
kubectl -n <namespace> create secret tls dreadnode-tls \
--cert=/path/to/tls.crt \
--key=/path/to/tls.key

2. Set scheme and secret name in your values overlay:

global:
scheme: https
tls:
secretName: dreadnode-tls

3. Install (or upgrade) the chart. Every subchart ingress — API, frontend, MinIO — picks up the secret automatically against its respective hostname.

The global cascade covers the common case: one certificate for both hostnames. If your API and MinIO traffic terminate on different load balancers with different certificates, leave global.tls.secretName empty and set per-subchart values:

  • dreadnode-api.ingress.tls
  • dreadnode-frontend.ingress.tls
  • dreadnode-base.minio.apiIngress.tls

Subchart-local values always override the global cascade.

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/health
# {"status":"ok"}

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

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

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

Open http(s)://<your-domain>/ and create an account. The first user to sign up is automatically enrolled in the default organization. Additional users need an invitation.

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> \
-f values.yaml

Database migrations run automatically on API pod startup. Migrations are forward-only (Alembic), so helm rollback is disabled. 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
NS=<namespace>
helm uninstall dreadnode -n "$NS"
# Delete persistent data
kubectl -n "$NS" delete pvc \
data-dreadnode-postgresql-0 \
data-dreadnode-clickhouse-0 \
data-dreadnode-minio-0
# Delete keep-annotated secrets
kubectl -n "$NS" delete secret \
dreadnode-postgresql \
dreadnode-clickhouse \
dreadnode-minio \
dreadnode-api-encryption

Then run helm install again as if starting fresh.