Skip to content

Installation

The core installs into Kubernetes from a single signed Helm umbrella chart. This page covers a general install; for a production-shaped AWS walkthrough see Deploy to EKS.

  • Kubernetes 1.26+ with kubectl and Helm 3 pointed at it.
  • cluster-admin for the first install — the bundled ClickHouse operator installs CRDs and a ClusterRole/Binding.
  • A StorageClass for ClickHouse’s PVC (a cluster default, or set clickhouse.persistence.storageClass).
  • Network egress to ghcr.io/ultrvlt for images and the chart — or a private mirror for air-gapped installs.

Every release is cosign-signed with an offline-verifiable key. Verify before you install:

Terminal window
export ULTRVLT_VERSION=0.1.25 # use the latest release
curl -fsSLO https://raw.githubusercontent.com/ultrvlt/ultrvlt/main/deploy/cosign/cosign.pub
cosign verify --key cosign.pub --insecure-ignore-tlog=true \
ghcr.io/ultrvlt/charts/ultrvlt:$ULTRVLT_VERSION

See Verifying signed artifacts for images, SBOMs, and build provenance.

The core boots without a license — it runs UI-locked but still ingests, a safe default. To unlock the UI, mount your signed .lic from a Secret:

Terminal window
kubectl create namespace ultrvlt
kubectl -n ultrvlt create secret generic ultrvlt-license \
--from-file=valid.lic=./customer.lic

The chart’s queryApi.license.existingSecret points at this Secret. (You can also inline the license with queryApi.license.content.)

The portal ships with auth.mode=local and is fail-closed: the install errors if no admin credential is provided. Prefer a pre-computed argon2id hash so no plaintext is stored at rest:

Terminal window
# Provide ONE of: a plaintext password (hashed at boot) or an argon2id PHC hash.
export ADMIN_HASH='$argon2id$v=19$m=65536,t=3,p=2$...'

If you run more than one query-api replica, also set a stable session-signing secret so replicas accept each other’s sessions:

Terminal window
export SESSION_SECRET=$(openssl rand -hex 32)

See Configuration → Authentication for OIDC single sign-on.

Terminal window
helm install ultrvlt oci://ghcr.io/ultrvlt/charts/ultrvlt \
--version "$ULTRVLT_VERSION" \
-n ultrvlt --create-namespace \
--set queryApi.license.existingSecret=ultrvlt-license \
--set-string queryApi.auth.admin.passwordHash="$ADMIN_HASH" \
--set queryApi.auth.admin.hashed=true \
--set queryApi.auth.sessionSecret="$SESSION_SECRET"

The schema-init Job runs automatically on install and each upgrade.

Enable the ingress (or port-forward for a quick look). Production installs should serve the portal over HTTPS — the session cookie is Secure, so login won’t stick over plain HTTP:

Terminal window
helm upgrade ultrvlt oci://ghcr.io/ultrvlt/charts/ultrvlt --version "$ULTRVLT_VERSION" \
-n ultrvlt --reuse-values \
--set portalUi.ingress.enabled=true \
--set portalUi.ingress.host=ultrvlt.example.com
Terminal window
# license is valid/unlocked:
kubectl -n ultrvlt exec deploy/ultrvlt-query-api -- \
wget -qO- localhost:8080/api/v1/license
# clickhouse reachable:
kubectl -n ultrvlt exec deploy/ultrvlt-query-api -- \
wget -qO- localhost:8080/api/v1/ping

With no data source the pages are empty until telemetry arrives. Enable one or more:

Terminal window
# eBPF sensor (validate the node kernel first — see Deploy to EKS):
--set sensor.enabled=true --set sensor.siteId=prod --set sensor.clusterId=prod
# pod-log collection (OpenTelemetry Collector DaemonSet):
--set logCollector.enabled=true
# Kubernetes object state for the Infrastructure pages:
--set clusterState.enabled=true

Any OpenTelemetry SDK or Collector can also send OTLP to the gateway on :4317.

The chart is offline-first. Mirror the signed images to your registry, vendor the subchart, and point registry at your mirror:

Terminal window
helm pull oci://ghcr.io/ultrvlt/charts/ultrvlt --version "$ULTRVLT_VERSION"
# mirror ghcr.io/ultrvlt/* images to your registry, then:
helm install ultrvlt ./ultrvlt-$ULTRVLT_VERSION.tgz -n ultrvlt --create-namespace \
--set registry=registry.internal.example.com/ultrvlt \
--set imagePullSecrets[0].name=my-mirror-pull-secret

Nothing in the core reaches the public internet unless you enable connected mode.