KubeBolt docs
GitHub

Google GKE Guide

Deploy KubeBolt on Google Kubernetes Engine, including Autopilot and Google Managed Prometheus.

Quick install

The chart works out of the box on GKE — it creates a ServiceAccount and a ClusterRole granting KubeBolt read access to the cluster plus the write verbs its actions use (exec, port-forward, scale, restart, edit, delete).

helm install kubebolt oci://ghcr.io/clm-cloud-solutions/kubebolt/helm/kubebolt \
  --namespace kubebolt --create-namespace --wait

kubectl -n kubebolt get secret kubebolt-admin-password \
  -o jsonpath='{.data.password}' | base64 -d ; echo

kubectl -n kubebolt port-forward svc/kubebolt 3000:80

Open http://localhost:3000 and log in as admin with the printed password (other ways to get it: Quick Start).

GKE ships Metrics Server, so live CPU and memory bars work immediately.

Authentication

KubeBolt itself needs no GCP permissions — it talks to the Kubernetes API and nothing else. Workload Identity matters only when the ServiceAccount also has to reach a Google Cloud service, which for KubeBolt means one case: reading Google Managed Prometheus with the agent, below.

Ingress with GCE

helm install kubebolt \
  oci://ghcr.io/clm-cloud-solutions/kubebolt/helm/kubebolt \
  --namespace kubebolt --create-namespace \
  --set ingress.enabled=true \
  --set ingress.className=gce \
  --set ingress.hosts[0].host=kubebolt.example.com \
  --set ingress.hosts[0].paths[0].path=/ \
  --set ingress.hosts[0].paths[0].pathType=Prefix

For an internal load balancer, use the gce-internal class instead (--set ingress.className=gce-internal). The backslash escaping in annotation keys passed with --set is for Helm’s parser, not YAML — a values file with -f avoids it entirely.

On clusters where an Ingress controller is not an option, the chart can front the API with the Gateway API instead — --set gatewayAPI.enabled=true, mutually exclusive with ingress.

GKE Autopilot

The kubebolt chart needs no privileged containers, so it installs on Autopilot clusters as is. Autopilot may raise the chart’s small default requests to meet its minimums — that is expected.

helm install kubebolt \
  oci://ghcr.io/clm-cloud-solutions/kubebolt/helm/kubebolt \
  --namespace kubebolt --create-namespace

Google Managed Prometheus

If your metrics already live in GMP, you do not need a second scrape pipeline. Deploy the optional agent in promread mode and it queries GMP’s Prometheus-compatible API directly, authenticating with GCP IAM through Workload Identity — no service-account key file.

1. Find the endpoint

GMP’s query endpoint is global per project; the location/global segment is fixed and there is no region to pass:

PROJECT_ID=$(gcloud config get-value project)
GMP_ENDPOINT="https://monitoring.googleapis.com/v1/projects/${PROJECT_ID}/location/global/prometheus"

TOKEN=$(gcloud auth print-access-token)
curl -s -H "Authorization: Bearer $TOKEN" \
  "${GMP_ENDPOINT}/api/v1/query?query=count(up)"

A status: success response means the endpoint and the bearer-auth path work.

2. Create the Google service account and bind it

PROJECT_ID=$(gcloud config get-value project)
GSA=kubebolt-promread
NAMESPACE=kubebolt
KSA=kubebolt-agent   # the chart's default; override with serviceAccount.name

gcloud iam service-accounts create $GSA \
  --display-name="KubeBolt agent — reads from Google Managed Prometheus"

# monitoring.viewer is read-only: no ingest, no admin.
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${GSA}@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/monitoring.viewer" \
  --condition=None

# The Kubernetes ServiceAccount does not exist yet — helm creates it in
# step 3. GKE resolves this binding lazily when it appears.
gcloud iam service-accounts add-iam-policy-binding \
  ${GSA}@${PROJECT_ID}.iam.gserviceaccount.com \
  --role="roles/iam.workloadIdentityUser" \
  --member="serviceAccount:${PROJECT_ID}.svc.id.goog[${NAMESPACE}/${KSA}]"

Workload Identity has to be on at both layers. Enabling it at the cluster scope (--workload-pool) is not enough — every node pool running the agent also needs --workload-metadata=GKE_METADATA. Missing the cluster layer shows up as unable to fetch token; missing the node-pool layer is nastier: the pod silently inherits the node’s default Compute Engine service account and you get 403 PERMISSION_DENIED on monitoring.timeSeries.list even though the binding above is correct.

3. Install the agent in promread mode

helm upgrade --install kubebolt-agent \
  oci://ghcr.io/clm-cloud-solutions/kubebolt/helm/kubebolt-agent \
  -n kubebolt --create-namespace \
  --set backendUrl=<your-kubebolt-host>:443 --set tls.enabled=true \
  --set cluster.name=<your-cluster-name> \
  --set auth.mode=ingest-token \
  --set auth.ingestToken.existingSecret=kubebolt-ingest-token \
  --set scrape.enabled=false \
  --set agent.promRead.enabled=true \
  --set agent.promRead.url="${GMP_ENDPOINT}" \
  --set agent.promRead.auth.mode=gcpIam \
  --set serviceAccount.annotations."iam\.gke\.io/gcp-service-account"="${GSA}@${PROJECT_ID}.iam.gserviceaccount.com"

Notes that catch people out:

The Add cluster wizard generates this command for you — see Connecting clusters and Metrics.

Troubleshooting

API pod in CrashLoopBackOff. Check kubectl -n kubebolt logs -l app.kubernetes.io/component=api. The usual cause is a missing ClusterRoleBinding — verify with kubectl get clusterrolebinding | grep kubebolt.

Binary Authorization blocks the images. Add an exemption for ghcr.io/clm-cloud-solutions/kubebolt/*, or attest the images under your own policy.

403 on some resources. Expected, and handled: KubeBolt degrades gracefully. Restricted resources are dimmed in the sidebar behind a “Limited access” banner. See RBAC & Permissions.