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 | |
|---|---|
| Kubernetes | 1.28 or later, any distribution (versions) |
| Helm | Helm 4, or Helm 3.16 or later, in a release that supports your Kubernetes version (versions) |
| Nodes | one node, Linux, amd64 or arm64 |
| CPU and memory | about 1 CPU and 3.5 GiB requested; up to 2 CPU and 9 GiB at the limits |
| Storage | a default StorageClass with ReadWriteOnce volumes: 300 GiB for TimescaleDB (the historian), 5 GiB for MaestroHub, 8 GiB for Prometheus |
| Images | Docker 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 cluster | Helm 4 | Helm 3 |
|---|---|---|
| 1.34 to 1.37 | 4.3 | 3.22 |
| 1.33 to 1.36 | 4.2 | 3.21 |
| 1.32 to 1.35 | 4.1 | 3.20 |
| 1.31 to 1.34 | 4.0 | 3.19 |
| 1.28 to 1.31 | none | 3.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
privilegedlevel 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
ClusterIPby default; withservice.type=NodePortorLoadBalancer, 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.
-
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.txtThe first command must say
Verified OK: the file list was signed by MaestroHub's release workflow. The second must sayOKon 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. -
Push the images to your registry, from a machine with Docker that reaches it:
docker login registry.example.com
./push-images.sh registry.example.comAdd
--chartto push the chart too, asoci://registry.example.com/context-platform-single-node, for Argo CD or Flux (log Helm in first:helm registry login registry.example.com). -
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 sameglobal.imageRegistry: harbor.example.com/maestrohub. - Amazon ECR does not create a repository on push. Create one for each
name
./push-images.sh <registry> --dry-runlists, 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 bothpush-images.shandglobal.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 see | Why, and what to do |
|---|---|
helm install stops: another node-exporter already holds host port 9100 | See Check for clashes first. Nothing was deployed. |
A volume stays Pending | No 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 Ready | It 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-gate | That 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 server | With NetworkPolicy on and outbound traffic locked (networkPolicy.allowExternalEgress=false), add the address to networkPolicy.extraEgress: the chart README, section NetworkPolicy, has a worked example. |