Skip to main content

GKE Kubernetes provisioner backend

Provision Nora agents into Google Kubernetes Engine using Nora’s generic Kubernetes adapter and Admin cluster registry.
GKE uses the same Kubernetes adapter as every Kubernetes provider. Nora stores provider, namespace, exposure, and load-balancer settings on the Admin cluster row; docker-compose.kubernetes.yml only mounts kubeconfig files into the control-plane containers.

Step-by-step setup

1. Prerequisites

  • GCP project with the Kubernetes Engine API enabled.
  • gcloud CLI installed and gcloud auth login completed.
  • An existing GKE cluster (or create one — GCP Console → Kubernetes Engine → Clusters → Create).
  • kubectl installed on the host that runs Nora.
Use the cluster details page in Google Cloud Console to confirm the GKE cluster name, location type, and region or zone before creating the kubeconfig.
GKE cluster details

Google Cloud Console — Kubernetes Engine cluster details

2. Create the kubeconfig

Use --zone <zone> instead of --region <region> for zonal clusters. You can copy the exact command from the cluster’s Connect dialog.
GKE Connect dialog

Google Cloud Console — Cluster → Connect dialog (get-credentials command)

3. Verify access from the host

4. Configure Nora

Set the generic Kubernetes mount variable in .env:
For two or more GKE clusters, put each kubeconfig under NORA_KUBECONFIGS_DIR and use Admin paths such as /kubeconfigs/gke-us-central1 and /kubeconfigs/gke-us-east1. Confirm region / VPC alignment in the Console’s Networking tab before exposing services to the public internet.
GKE networking review

Google Cloud Console — create cluster review with Networking complete

5. Start the stack

This smoke-mode command is for the local nginx config (NGINX_CONFIG_FILE=nginx.conf, usually NGINX_HTTP_PORT=8080). If your .env already points to the public TLS config (NGINX_CONFIG_FILE=nginx.public.conf), include the tracked infra/docker-compose.public-tls.yml layer as shown in Promote to production; otherwise nginx will not mount /etc/letsencrypt and Cloudflare can return 521 because the origin web server is down.

6. Register this cluster in Admin

Open Admin -> Kubernetes, click Add cluster, and use these values: Do not put ./.secrets/gke-kubeconfig in the Admin Kubeconfig path when Nora runs in Docker Compose. That is the host-side path; the containers see files from NORA_KUBECONFIGS_DIR under /kubeconfigs.

7. Deploy a test agent

Open the dashboard at http://127.0.0.1:8080, sign in, and create an agent with the GKE cluster label you registered.
Deploy wizard backend
picker

Nora deploy wizard — Backend dropdown showing Kubernetes on GKE

Deploy wizard Kubernetes
selected

Nora deploy wizard — Kubernetes on GKE selected

Agent detail K8s

Agent detail — status running with the GKE LoadBalancer address

GKE Service options

The default GKE LoadBalancer Service path works without annotations. To request GKE’s external passthrough Network Load Balancer with RBS on supported cluster versions, set: Set the Admin Load balancer class field to networking.gke.io/l4-regional-external. For clusters that use the annotation path instead of loadBalancerClass:
Leave Service annotations JSON empty unless your cluster policy requires provider-specific Service annotations.

Verification

For real e2e, enable the Kubernetes matrix cell:
Agent logs K8s

Logs tab — worker-provisioner output during a successful GKE deploy

Automated smoke

Once your GKE kubeconfig is in place, run the shared lifecycle smoke:
This script is operator-run only — it provisions real workloads against a live GKE cluster and is not part of CI. Set KEEP_ENV=true to leave the stack running after the script finishes.

Promote to production

Once the smoke is green, switch from the dev-mode stack to the prod-mode stack. The only changes vs the testing setup are nginx (public config + TLS) and Compose mode (infra/docker-compose.public-tls.yml for prod Dockerfiles, TLS mounts, public ports, and restart policies).

1. Tighten the LoadBalancer source ranges

Replace the smoke-time <nora-control-plane-egress-cidr> placeholder with your production control plane’s egress CIDR. Combine with cloud.google.com/load-balancer-type: Internal annotations if you’re keeping agents on a private subnet.

2. Switch nginx to public + TLS

In .env:
Provision Let’s Encrypt certs once:

3. Stop the smoke-mode stack

4. Start the prod-mode stack

5. Confirm

Deploy a real agent from the UI and confirm it reaches running and the GKE LoadBalancer assigns an external IP.

See also

  • Kind — local Kubernetes for development
  • K3s — self-hosted production K8s
  • AKS — Azure Kubernetes Service
  • EKS — Amazon EKS