Install CloudGrange — Helm on your own Kubernetes
If you already run Kubernetes, install CloudGrange with Helm from the chart published with every release. No VM is created and no installer script runs. Your cluster provides the ingress controller, storage, a load balancer and TLS; see the prerequisites.
This is the same chart the appliance, the Windows-orchestrated installer and the native Linux installer all deploy — those paths simply install K3s first and then run this chart for you.
CloudGrange is in preview, not GA. The commands on this page always download the chart of the latest release. See current product and release status.
Compare installation modes
| Mode | What you provide | What CloudGrange installs |
|---|---|---|
| Appliance (VHDX) | A Hyper-V host | A prepared Linux VM, K3s and the chart, all pre-baked |
| Windows-orchestrated | A Windows/Hyper-V host | Creates the Linux VM, installs K3s, deploys the chart |
| Native Linux | An Ubuntu/Debian server | Installs K3s on it, deploys the chart |
| Helm (this page) | Any Kubernetes cluster | The chart only |
Prerequisites
The full list, with sizes, Pod Security, RBAC, egress and air-gap details, is on BYO Kubernetes prerequisites. In short:
A conformant Kubernetes cluster. CloudGrange tests on Kubernetes 1.36 (K3s
v1.36.4+k3s1).kubectland Helm, both pointed at the cluster, pluscurlandsha256sumto download and verify the chart. Helm 3.x and Helm 4.x both work (tested: v3.22.0 and v4.3.0). Avoid Helm v4.2.1: a Helm bug (helm/helm#32214) makeshelm install --waithang until its timeout.An ingress controller. The chart does not install one. You tell it which class to use. See Ingress controller below.
A LoadBalancer implementation (a cloud load balancer or MetalLB) for the relay's
LoadBalancerService on TCP 8443, or setrelay.service.type=NodePort.A default StorageClass for
ReadWriteOncevolumes, about 29.4 GiB in total. Check that you have one:kubectl get storageclassExactly one class should be marked
(default). On microk8s, enable one withmicrok8s enable hostpath-storage.A namespace that allows Pod Security level
privileged, because the log shipper reads node logs throughhostPath.cluster-admin for the identity running
helm install. On the defaults the chart creates nothing outside the release namespace; turning on the log shipper (observability.promtail.enabled=true) adds a ClusterRole and a ClusterRoleBinding.Outbound HTTPS from your nodes to
ghcr.io,docker.ioandquay.io, or an air-gapped image mirror.
Step 1 — install cert-manager
cert-manager must be a separate Helm release, installed first. It ships CustomResourceDefinitions that the CloudGrange chart's own templates reference, and Helm validates every object in a release before applying any of it — so a single combined install fails with no matches for kind "Certificate". This is cert-manager's own documented pattern, not a CloudGrange quirk.
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--version v1.21.2 \
--namespace cert-manager --create-namespace \
--set crds.enabled=true \
--wait --timeout 5m
Skip this step if cert-manager is already running in your cluster, or if you bring your own certificate (see TLS). The CloudGrange installers use cert-manager v1.21.2.
Step 2 — install CloudGrange
Create the namespace and allow the privileged Pod Security level, which the log shipper needs:
kubectl create namespace cloudgrange
kubectl label namespace cloudgrange pod-security.kubernetes.io/enforce=privileged
Download the chart of the latest release and verify it:
curl -fsSLO https://github.com/CloudGrange/cloudgrange-deployment-installer/releases/latest/download/cloudgrange-chart.tgz
curl -fsSLO https://github.com/CloudGrange/cloudgrange-deployment-installer/releases/latest/download/cloudgrange-chart.tgz.sha256
sha256sum --check cloudgrange-chart.tgz.sha256
helm show chart ./cloudgrange-chart.tgz | grep '^version:'
Expect cloudgrange-chart.tgz: OK. The last command shows the release version. The chart pins every first-party image to that version, so no image tag is needed on the command line.
Then install it:
helm install cloudgrange ./cloudgrange-chart.tgz \
--namespace cloudgrange \
--set global.hostname=cloudgrange.example.com \
--set global.ingress.className=nginx \
--set global.ingress.annotations=null \
--timeout 10m --wait
The same install as a values file is on BYO Kubernetes prerequisites.
Set global.hostname to the DNS name or IP address you will browse to. If it is an IP address the chart omits the Ingress host rule automatically, because Kubernetes rejects an IP in that field.
Ingress controller
The chart defaults to traefik, because the bundled K3s installs ship Traefik. On any other cluster you must set the class to match your controller, or nothing will claim the Ingress and the portal will be unreachable with no error to explain it.
| Your controller | Flags |
|---|---|
| Traefik (K3s default) | (default — nothing to set) |
| ingress-nginx | --set global.ingress.className=nginx --set global.ingress.annotations=null |
| microk8s built-in | --set global.ingress.className=public --set global.ingress.annotations=null |
| AKS Application Gateway | --set global.ingress.className=azure-application-gateway --set global.ingress.annotations=null |
| AWS ALB | --set global.ingress.className=alb --set global.ingress.annotations=null |
| Let a default IngressClass claim it | --set global.ingress.className="" --set global.ingress.annotations=null |
global.ingress.annotations=null clears the Traefik-specific annotations the default carries. Add your own controller's annotations the same way:
--set global.ingress.annotations."nginx\.ingress\.kubernetes\.io/proxy-body-size"=0
Check which classes your cluster offers:
kubectl get ingressclass
Step 3 — verify
kubectl get pods -n cloudgrange
kubectl get ingress,svc -n cloudgrange
Every pod should reach 1/1 Running, except cloudgrange-secrets-bootstrap-*, which is a one-shot Job and correctly ends as 0/1 Completed. The Ingress should show your class and an address, and the cloudgrange-relay Service should have an external address.
Then browse to https://<global.hostname>/ and complete the first-run setup wizard.
Secrets
You do not supply any credentials. A Helm pre-install hook Job generates the Postgres, Keycloak admin, Keycloak API client, Grafana, relay enrollment and realm administrator secrets directly through the Kubernetes API, and only if they do not already exist — so helm upgrade never rotates a live database's password out from under it.
To read the first-login realm administrator password:
kubectl get secret cloudgrange-secrets -n cloudgrange -o jsonpath='{.data.realm-admin-password}' | base64 -d; echo
Upgrading
Platform updates are applied in the portal, under Platform → Updates, on every deployment method, including your own cluster. See Updates.
The in-cluster updater is namespace-scoped, so there is exactly one case it hands back to you: a chart version that adds, changes or removes a cluster-scoped object. It detects that before it changes anything and tells you the command to run. See In-app Platform updates on your cluster.
To upgrade from the command line instead, download and verify the new release's chart as in Step 2, then:
helm upgrade cloudgrange ./cloudgrange-chart.tgz \
--namespace cloudgrange --reset-then-reuse-values --timeout 10m --wait
--reset-then-reuse-values, never--reuse-values.--reuse-valueskeeps the previous release's values verbatim and so drops every default the new chart introduces — which is exactly how the in-app updates to2609.0.0-preview.18and.19broke (nil pointer evaluating interface {}.registry, from anairgapvalues key the older release did not have).--reset-then-reuse-values(Helm 3.14 and later) resets to the new chart's defaults and re-applies only the values you supplied; it is the flag the in-cluster updater itself uses. Re-passing your full values file with-fis equally correct.
If you ever set global.image.tag yourself, remove it (--set global.image.tag=) so the new chart's pinned version applies. Never use the latest tag. With pullPolicy: IfNotPresent, an upgrade that does not change the tag renders an identical pod spec, so Kubernetes restarts nothing and keeps the cached images.
You maintain the Kubernetes cluster itself. CloudGrange does not upgrade it. See Support boundary.
Uninstalling
helm uninstall cloudgrange -n cloudgrange
PersistentVolumeClaims deliberately survive an uninstall — that is Kubernetes' own default and it protects your database from a mistyped command. Reinstalling reattaches the existing data. To destroy the data as well:
kubectl delete pvc -n cloudgrange -l app.kubernetes.io/part-of=cloudgrange
kubectl delete pvc -n cloudgrange data-cloudgrange-postgres-0
After the control plane is running
- Install the CloudGrange Relay — one per site, if you are not using the relay bundled in this chart.
- Install the CloudGrange Agent — on every Hyper-V host you want to manage.
Values reference
| Value | Default | Purpose |
|---|---|---|
global.hostname |
cloudgrange.local |
DNS name or IP you browse to; used for the Ingress rule and the TLS SAN |
global.ingress.className |
traefik |
IngressClass to bind to; must match your controller |
global.ingress.annotations |
Traefik entrypoint | Controller-specific Ingress annotations |
global.image.registry |
ghcr.io/cloudgrange |
Image registry |
global.image.tag |
The release version | Image tag for the first-party services. Pin it to the chart version, never latest |
global.image.pullPolicy |
IfNotPresent |
Image pull policy |
certManager.installOperator |
true |
Render the namespaced self-signed Issuer and the Certificate. Set false to bring your own cloudgrange-tls Secret |
certManager.issuerRef.name / .kind |
"" / ClusterIssuer |
Use an issuer you already run (ACME, internal CA) instead of the self-signed one |
postgres.persistence.storageClass |
"" (cluster default) |
StorageClass for the database volume |
postgres.persistence.size |
10Gi |
Database volume size |
relay.service.type |
LoadBalancer |
How the relay is published on TCP 8443 |
metallb.enabled, metallb.addressPool |
false, [] |
Render a MetalLB pool for the relay (MetalLB installed separately) |
foundation.managed |
false |
Set by CloudGrange's installers only. Shows the Foundation update card. Leave it false on your own cluster |
The full per-path requirements are on BYO Kubernetes prerequisites.
The full set lives in the chart's own values.yaml:
helm show values ./cloudgrange-chart.tgz