Deploying Cluster Mode
deploy/helm/hyve is a single Helm chart deploying both components of Cluster Mode — the controller and the API — together.
Install
The chart isn’t published to a Helm repository — install it from a hyve checkout. The image is published to ghcr.io/cbridges1/hyve with every release.
Get the chart and apply the CRDs
git clone https://github.com/cbridges1/hyve.git && cd hyvekubectl apply -f deploy/helm/hyve/crds/Install the chart
helm upgrade --install hyve deploy/helm/hyve \ --namespace hyve-system --create-namespace \ --set image.repository=ghcr.io/cbridges1/hyve \ --set image.tag=<version> \ --set api.publicBaseURL=https://hyve.example.com \ --set api.multiTenant.enabled=truehyve-api generates and stores its own session-signing key on first start — there’s no Secret to create.
Expose hyve-api
The chart creates a plain ClusterIP Service (hyve-api, port 80) and no Ingress. Expose it however your cluster already does — an Ingress, a LoadBalancer Service, a tunnel (e.g. Pangolin or Cloudflare), or kubectl port-forward for a quick look. Terminate TLS in front of it and set api.publicBaseURL to that HTTPS address. The same address serves the web console — and hyve-agent, which tunnels back over a WebSocket at /agent/tunnel, so whatever fronts hyve-api must allow WebSocket upgrades; no other port needs exposing.
Create the first superadmin
Accounts live in hyve-api’s own datastore, so this runs inside the API pod:
kubectl -n hyve-system exec deploy/hyve-api -- \ hyve cluster-config api create-user admin --role superadmin --namespace hyve-systemPass --password for scripting; omit it to be prompted. Or skip this step entirely by setting api.bootstrapAdmin.username and api.bootstrapAdmin.passwordSecret.name (an existing Secret with a password key) at install time — or api.bootstrapAdmin.usernameKey instead of username to read the username from that same Secret.
Log in
hyve context login --api-url https://hyve.example.comKey values
| Value | Purpose |
|---|---|
image.repository / image.tag | The hyve image — ghcr.io/cbridges1/hyve and a release tag |
namespace | The control-plane namespace both components run in (default hyve-system) |
api.publicBaseURL | The HTTPS address callers reach hyve-api on — required for host-cluster and hyve-agent kubeconfigs |
api.multiTenant.enabled | Lets one install serve many organizations (a ClusterRole instead of a namespaced Role). With api.db.driver: postgres, hyve-controller also reconciles every organization on the home cluster (it reads them from the same database, and restarts itself to pick up new ones) |
controller.agent.controlPlaneURL | hyve-api’s public HTTPS address (usually api.publicBaseURL) — where a newly installed hyve-agent bootstraps and tunnels to. Unset disables hyve-agent installs |
api.db.driver | sqlite (default, one API replica, stored on a PVC) or postgres — required for more than one replica or for moving organizations onto reconciling clusters |
api.requireReconcilingCluster | Refuse to let any tenant organization live on the home cluster |
api.bootstrapAdmin.username (or .usernameKey) / .passwordSecret | Create the first superadmin on startup, only while none exists — replaces the manual create-user step. Not an API endpoint; the password (and, with usernameKey, the username) is read from a mounted Secret |
api.smtp.host / .port / .username / .fromAddress / .passwordSecret | Seed outbound email (password resets) on first start; settings saved later in the console always win |
api.service.type / api.service.nodePort | ClusterIP by default; NodePort only where node ports are reachable |
api.accessRoles.clusterScoped | See the warning below — leave at its default |
Running multiple tenants on one cluster
Multiple hyve installs (each its own controller + API pair) can safely share one cluster, isolated by namespace — every hyve.io CRD is namespaced, and (with clusterScoped: false, the default) each install’s roles are scoped to its own namespace only:
kubectl create namespace tenant-ahelm install hyve-tenant-a deploy/helm/hyve \ --namespace tenant-a \ --set namespace=tenant-a \ --set image.repository=ghcr.io/cbridges1/hyve --set image.tag=<version>A second tenant is the identical pattern with a different namespace — no shared config beyond a common image. For most setups, one install serving several organizations (api.multiTenant.enabled=true) is simpler than one install per tenant.