Skip to main content
Version: 3.1

Install single-node on Kubernetes

The single-node chart installs MaestroHub, TimescaleDB and Prometheus with one helm install. This page is for the platform team that runs the cluster. What the installation looks like once it runs is on Single-node on Kubernetes.

The chart's version is MaestroHub's version: chart 3.1.0 installs MaestroHub 3.1.0.

What the cluster needs​

Needed
Kubernetes1.28 or later, any distribution (versions)
HelmHelm 4, or Helm 3.16 or later, in a release that supports your Kubernetes version (versions)
Nodesone node, Linux, amd64 or arm64
CPU and memoryabout 1 CPU and 3.5 GiB requested; up to 2 CPU and 9 GiB at the limits
Storagea default StorageClass with ReadWriteOnce volumes: 300 GiB for TimescaleDB (the historian), 5 GiB for MaestroHub, 8 GiB for Prometheus
ImagesDocker Hub, quay.io and registry.k8s.io, or your own registry with the offline bundle

300 GiB is the size recommended for a plant's history. A smaller volume works for a trial: --set historian.volumeSize=50Gi.

Kubernetes and Helm versions​

Kubernetes 1.28 or later. Every chart is checked against the Kubernetes 1.28 API before release, and installed and upgraded on Kubernetes 1.37. It does not check the cluster's version itself, so on an older cluster it may install and then fail in ways that are hard to trace: check first.

Helm 4 (recommended), or Helm 3.16 or later. The chart is tested with Helm 3.16 and Helm 4.3. Use a Helm release that supports your cluster's Kubernetes version: each Helm release supports the Kubernetes version it was built with and the three before it, and makes no promise for newer ones.

Your clusterHelm 4Helm 3
1.34 to 1.374.33.22
1.33 to 1.364.23.21
1.32 to 1.354.13.20
1.31 to 1.344.03.19
1.28 to 1.31none3.16, 3.17, 3.18

Check what you have:

helm version --short           # e.g. v4.3.1+gc0d08d0
kubectl version # "Server Version" is the cluster's
  • Helm 3.9 or older cannot read the chart. It stops with error calling index: index of untyped nil. Upgrade Helm.
  • Helm 3.10 to 3.15 render the chart, but are not tested with it. Use 3.16 or later.
  • Helm 3 receives security fixes only until 10 February 2027 (the Helm project's end of life for Helm 3). Plan the move to Helm 4.

The same versions apply to an upgrade, and to the offline bundle: use a Helm from the table on the machine you install from.

Check for clashes first​

The chart installs into one namespace and touches nothing outside it, with one exception: the node metrics. Check these before you install:

  • Port 9100 on the nodes. The chart's node-exporter uses host port 9100 on every node, as kube-prometheus-stack, Rancher Monitoring and most monitoring agents do. If one already runs there, the install stops before deploying anything and names it. Then reuse yours: --set prometheus.bundled.infrastructure.nodeExporter.enabled=false --set prometheus.bundled.infrastructure.nodeExporter.scrapeExisting=true.
  • Pod Security. That node-exporter needs the privileged level in its namespace (host network, read-only host paths). With a stricter level, turn it off as above.
  • The namespace. Use a namespace of its own. Two releases in one namespace work, but share nothing; never point two at one external PostgreSQL server, whose databases (<module>_db) they would share.
  • Ingress host names and Service ports. The Service is ClusterIP by default; with service.type=NodePort or LoadBalancer, check that its ports are free.
  • NetworkPolicy. Off by default. With networkPolicy.enabled=true (the production values), the cluster's CNI must enforce NetworkPolicy (Calico, Cilium and most managed CNIs do; kind's default does not).

Get the chart​

The chart is published on Docker Hub, next to MaestroHub's image, as an OCI chart: oci://registry-1.docker.io/maestrohub/context-platform-single-node (on Docker Hub). Helm reads it directly; there is no helm repo add. Use the version you install, the MaestroHub version (3.1.0 below).

Look at it before you install:

helm show chart  oci://registry-1.docker.io/maestrohub/context-platform-single-node --version 3.1.0
helm show readme oci://registry-1.docker.io/maestrohub/context-platform-single-node --version 3.1.0
helm show values oci://registry-1.docker.io/maestrohub/context-platform-single-node --version 3.1.0 > default-values.yaml

Or download it, to keep it with your own values or to review it:

helm pull oci://registry-1.docker.io/maestrohub/context-platform-single-node --version 3.1.0          # context-platform-single-node-3.1.0.tgz
helm pull oci://registry-1.docker.io/maestrohub/context-platform-single-node --version 3.1.0 --untar # a folder

Docker Hub limits anonymous pulls per IP address. If you hit the limit, log Helm in with any Docker Hub account (helm registry login registry-1.docker.io), and give the cluster a pull secret for the images (global.imagePullSecrets).

Install​

From Docker Hub:

helm install maestrohub oci://registry-1.docker.io/maestrohub/context-platform-single-node \
--version 3.1.0 -n maestrohub --create-namespace --wait --timeout 15m

Or from the chart you downloaded, the same way: helm install maestrohub ./context-platform-single-node-3.1.0.tgz -n maestrohub --create-namespace --wait --timeout 15m.

Then open MaestroHub and create the first administrator:

kubectl -n maestrohub port-forward svc/maestrohub-context-platform-single-node 8080:8080
# http://localhost:8080

Check the installation at any time with helm test maestrohub -n maestrohub --logs.

For production, start from the production values: they keep secrets in a Secret you create, turn NetworkPolicy on and expose MaestroHub through an Ingress.

helm pull oci://registry-1.docker.io/maestrohub/context-platform-single-node --version 3.1.0 --untar
less context-platform-single-node/values-production.yaml # what it changes, and why
helm install maestrohub ./context-platform-single-node -n maestrohub --create-namespace \
-f context-platform-single-node/values-production.yaml \
--set secrets.existingSecret=maestrohub-secrets --set ingress.host=maestrohub.example.com

Every setting is described in the chart's README: helm show readme oci://registry-1.docker.io/maestrohub/context-platform-single-node --version 3.1.0.

Check the signature​

The chart, like the image, is signed by MaestroHub's release workflow. With Cosign:

cosign verify \
--certificate-identity-regexp '^https://github\.com/maestrohub-labs/maestrohub/\.github/workflows/release\.yml@refs/tags/' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
docker.io/maestrohub/context-platform-single-node:3.1.0

Install without internet access​

Download the offline Helm bundle for your architecture from the MaestroHub Portal: MaestroHub_ContextPlatform_Helm_<version>_<amd64|arm64>.zip. It carries the chart and every image the chart uses.

  1. Check it, on the machine you downloaded it to, before you carry it into your network. Unzip it, then in its folder:

    cosign verify-blob checksums.txt --bundle checksums.txt.sigstore.json \
    --certificate-identity-regexp '^https://github\.com/maestrohub-labs/maestrohub/\.github/workflows/release\.yml@refs/tags/' \
    --certificate-oidc-issuer 'https://token.actions.githubusercontent.com'
    sha256sum -c checksums.txt

    The first command must say Verified OK: the file list was signed by MaestroHub's release workflow. The second must say OK on every line: every file is the one that was signed. Cosign needs internet access for this, which is why you check on the download machine.

  2. Push the images to your registry, from a machine with Docker that reaches it:

    docker login registry.example.com
    ./push-images.sh registry.example.com

    Add --chart to push the chart too, as oci://registry.example.com/context-platform-single-node, for Argo CD or Flux (log Helm in first: helm registry login registry.example.com).

  3. Set your registry (and a pull secret, if it needs one) in values-airgap.yaml, then install from the bundle:

    helm install maestrohub ./context-platform-single-node-3.1.0.tgz \
    -n maestrohub --create-namespace -f values-airgap.yaml --wait --timeout 15m

Some registries need more:

  • Harbor keeps every image in a project. Give the project with the registry, ./push-images.sh harbor.example.com/maestrohub, and the same global.imageRegistry: harbor.example.com/maestrohub.
  • Amazon ECR does not create a repository on push. Create one for each name ./push-images.sh <registry> --dry-run lists, first.
  • One registry for both architectures: the amd64 and arm64 bundles push the same names and tags, so the second push replaces the first. Give each architecture its own path, e.g. registry.example.com/maestrohub-arm64, in both push-images.sh and global.imageRegistry.

The bundle's README.md has the details, including how to push the images without Docker. For an upgrade, download the new version's bundle from the Portal and push its images the same way.

Upgrade​

helm upgrade maestrohub oci://registry-1.docker.io/maestrohub/context-platform-single-node   --version <new version> -n maestrohub --reset-then-reuse-values --timeout 60m

--reset-then-reuse-values takes the new chart's defaults and keeps the values you set. Before anything changes, the chart checks your data with the new version. If the new version converts stored data, the chart checks that PostgreSQL's volume has room for a snapshot, stops MaestroHub, takes a snapshot of the PostgreSQL databases onto that volume, converts the data and starts the new version, all in this one command. MaestroHub is stopped for as long as the snapshot and the conversion take: give --timeout more for large databases.

With your own PostgreSQL server, the upgrade first stops with nothing changed and asks for your snapshot; its log gives the steps. The steps for each release are in Upgrades; where the snapshot is, how to restore it and how to go back to the previous version are in the chart README, section Upgrading.

Do not add --atomic (or --rollback-on-failure with Helm 4) to an upgrade.

Uninstall​

helm uninstall maestrohub -n maestrohub

This keeps your data on purpose:

  • the volumes: MaestroHub's (maestrohub-context-platform-single-node-data) and TimescaleDB's (data-maestrohub-context-platform-single-node-postgresql-0). Installing again under the same release name in the same namespace uses them again, with your data;
  • the Secret maestrohub-context-platform-single-node-secrets: the database password and the encryption keys the chart generated. Installing again reuses it, and your data can only be read with it, so keep it as long as you keep the volumes;
  • the last run of the upgrade check and of the database setup, and the upgrade check's ServiceAccount, Role and NetworkPolicies (Helm never deletes these).

To remove everything, data included:

kubectl delete namespace maestrohub

When something does not start​

What you seeWhy, and what to do
helm install stops: another node-exporter already holds host port 9100See Check for clashes first. Nothing was deployed.
A volume stays PendingNo default StorageClass, or it cannot create a volume of that size. kubectl get storageclass; set persistence.storageClass, postgres.bundled.storage.storageClass and prometheus.bundled.storage.storageClass.
The MaestroHub pod is Running but never ReadyIt shows why on its address: usually Upgrade needed, after an upgrade that skipped the chart's check (see Upgrade). kubectl logs says the same.
helm upgrade fails: pre-upgrade hooks failed … upgrade-gateThat is the upgrade check refusing, with nothing changed. Its log says why and what to run: kubectl -n maestrohub logs job/maestrohub-context-platform-single-node-upgrade-gate.
A connector cannot reach a device or a serverWith NetworkPolicy on and outbound traffic locked (networkPolicy.allowExternalEgress=false), add the address to networkPolicy.extraEgress: the chart README, section NetworkPolicy, has a worked example.