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:
backendUrlis a gRPC dial target,host:port, no scheme. For an agent in the same cluster as the backend, use the in-cluster Service (kubebolt-agent-ingest.kubebolt.svc.cluster.local:9090) without TLS.- The
kubebolt-ingest-tokenSecret must exist in the agent’s namespace, with the token under thetokenkey (issue it in Administration → Agents & Ingest → Agent Tokens). agent.promRead.urlis the base endpoint — the agent appends/api/v1/query_rangeitself.scrape.enabled=falsedisables the bundledvmagentsidecar so it does not scrape in parallel. It does not disable the DaemonSet’s kubelet collectors, which still complement GMP with KubeBolt’s canonical metrics.- The default matchers use explicit metric names rather than a regex on
__name__, because GMP rejects{__name__=~"…"}selectors. Keep any override as an explicit name list. - Do not set
agent.deferNodeStress=trueon GMP. GMP managed collection does not scrape node-exporter, so the agent’s own collector is the only source ofnode_load1/5/15and the pressure series. Deferring it empties the Load average panel. (That flag is the right call on Azure, not here.)
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.