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).

  • kubectl and Helm, both pointed at the cluster, plus curl and sha256sum to 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) makes helm install --wait hang 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 LoadBalancer Service on TCP 8443, or set relay.service.type=NodePort.

  • A default StorageClass for ReadWriteOnce volumes, about 29.4 GiB in total. Check that you have one:

    kubectl get storageclass
    

    Exactly one class should be marked (default). On microk8s, enable one with microk8s enable hostpath-storage.

  • A namespace that allows Pod Security level privileged, because the log shipper reads node logs through hostPath.

  • 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.io and quay.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-values keeps the previous release's values verbatim and so drops every default the new chart introduces — which is exactly how the in-app updates to 2609.0.0-preview.18 and .19 broke (nil pointer evaluating interface {}.registry, from an airgap values 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 -f is 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

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