CloudBrum
CloudBrum · Cloud decision-support platform
Google Cloud Containers

Google Kubernetes EngineLast reviewedReading time~12 minLevelBeginner to advanced

Google Cloud · Containers · Managed Kubernetes

Kubernetes from the company that started it. GKE runs the control plane and, in Autopilot mode, the nodes as well: you describe pods and Google finds the machines and bills for what the pods request. Standard mode hands you node pools and the work that comes with them. Pick the mode first, because it decides how you scale, how you’re billed and which settings you can still change. Then pick a release channel, so upgrades arrive on a schedule you chose instead of one you have to chase.

On this page (17 sections)

    Mind map: Google Kubernetes Engine at a glance

    Google Kubernetes Engine mind map Google Kubernetes Engine at a glance: Modes: Autopilot, Standard, Compute classes; Release channels: Rapid, Regular, Stable, Extended, Maintenance windows; Networking: VPC-native clusters, Dataplane V2, Gateway API; Identity: IAM, Workload Identity, Kubernetes RBAC; Storage: Persistent Disk CSI, Filestore, Cloud Storage FUSE; Fleet: Enterprise edition, Config Sync, Multi-cluster; Security: Private nodes, Binary Authorization, Security posture; Pricing: Cluster fee, Pod requests or VMs, Free credit. Google Kubernetes Engine at a glance Managed Kubernetes on Google Cloud: the main building blocks and decisions CloudBrum Cloud decision-support platform CloudBrum Autopilot Standard Compute classes Modes Rapid, Regular, Stable Extended Maintenance windows Release channels VPC-native clusters Dataplane V2 Gateway API Networking IAM Workload Identity Kubernetes RBAC Identity Persistent Disk CSI Filestore Cloud Storage FUSE Storage Enterprise edition Config Sync Multi-cluster Fleet Private nodes Binary Authorization Security posture Security Cluster fee Pod requests or VMs Free credit Pricing GKE17-point analysis CloudBrum· 17-point cloud service analysis cloudbrum.com
    CloudBrum GKE at a glance · 17-point analysis Modes Autopilot Standard Compute classes Release channels Rapid, Regular, Stable Extended Maintenance windows Networking VPC-native clusters Dataplane V2 Gateway API Identity IAM Workload Identity Kubernetes RBAC Storage Persistent Disk CSI Filestore Cloud Storage FUSE Fleet Enterprise edition Config Sync Multi-cluster Security Private nodes Binary Authorization Security posture Pricing Cluster fee Pod requests or VMs Free credit CloudBrum · cloudbrum.com

    Free to share. The downloaded image includes the CloudBrum link.

    Key features (summary)

    • Autopilot modeYou write pods with CPU and memory requests, and Google provisions, scales, patches and secures the nodes. Billing follows what your pods request, not the machines underneath, so empty capacity isn’t yours to pay for.
    • Standard modeYou create node pools, choose machine types, set autoscaling limits and decide how nodes upgrade. It gives the most control, including privileged workloads and unusual hardware, and it leaves the packing and the idle capacity to you.
    • Release channelsRapid, Regular and Stable trade speed for caution, and an Extended channel on Standard clusters keeps a minor version supported for longer. GKE upgrades the control plane and nodes inside the channel’s rules, and you pick the maintenance windows.
    • Workload Identity FederationPods call Google APIs as their own Kubernetes service account. You grant an IAM role directly to that identity, so there are no key files to create, mount or rotate. It’s always on in Autopilot.
    • VPC-native networkingPods and services get addresses from secondary ranges in your subnet, so they route like any other VPC address. Dataplane V2, built on Cilium, enforces network policy and adds logging.
    • Gateway APIGoogle Cloud load balancers are configured with the Kubernetes Gateway and HTTPRoute objects, with global or regional options, and Cloud Armor and managed certificates attach to them.
    • Private clusters and postureKeep nodes on private addresses, limit who can reach the control plane, scan workloads for vulnerabilities and watch configuration drift from a security posture dashboard.
    • FleetsThe Enterprise edition manages many clusters as a fleet, with shared policy, configuration sync from Git and multi-cluster services across projects.

    Basic concepts

    Autopilot
    A GKE mode where Google owns the nodes. Pods are billed by their requests, and some node-level settings (privileged containers, host access) are off limits.
    Standard
    A GKE mode where you manage node pools, machine types and upgrade strategy, and pay for the virtual machines.
    Zonal and regional cluster
    A zonal cluster has its control plane in one zone. A regional cluster spreads the control plane, and by default the nodes, over three zones, and has the higher availability target.
    Node pool
    A group of nodes in a Standard cluster that share a machine type and settings. Autoscaling and upgrades act on the pool.
    Compute class
    A named hardware profile that a pod asks for with a node selector, such as Balanced or Scale-Out. Autopilot uses them to choose the machine family.
    Release channel
    A subscription to Kubernetes versions: Rapid, Regular, Stable or, for Standard clusters, Extended. The channel decides which version you get and when.
    Maintenance window
    A recurring time slot when GKE may do disruptive upgrades. Exclusions block upgrades for a chosen period, such as a sales peak.
    VPC-native cluster
    A cluster that gets its pod and service ranges from alias IP ranges in a subnet, so no routes need to be created per node.
    Dataplane V2
    GKE’s networking layer built on Cilium. It enforces Kubernetes network policy and gives flow logging, and it’s the default on Autopilot.
    Workload Identity Federation for GKE
    Maps a Kubernetes service account to an identity inside a workload identity pool, PROJECT_ID.svc.id.goog, which IAM can grant roles to.
    Private cluster
    A cluster whose nodes have only internal addresses. The control plane can be reached privately, through authorised networks, or through a DNS-based endpoint.
    Gateway
    A Kubernetes API object that describes a load balancer. GKE turns a Gateway and its routes into a Google Cloud load balancer.
    Binary Authorization
    A deploy-time check that admits only images signed or attested by your pipeline.
    Fleet
    A logical group of clusters registered together so that policy, configuration and services can be managed as one.

    How to create & configure it

    Create an Autopilot cluster with gcloud

    1. Choose the project, region and modePick a project that belongs to a billing account, and a region such as asia-south1 (Mumbai) or asia-south2 (Delhi). Use Autopilot unless you know you need node-level control. Autopilot clusters are regional.
    2. Enable the servicesTurn on the Kubernetes Engine and Artifact Registry APIs. The first cluster in a project can take a few extra minutes while GKE sets itself up.
    3. Prepare the networkCreate a VPC subnet with two secondary ranges, one for pods and one for services, and with Private Google Access. Private nodes have no external address, so add Cloud Router and Cloud NAT if they need to reach the internet.
    4. Create the clusterRun gcloud container clusters create-auto with the network, the secondary ranges, private nodes, authorised networks for the control plane and a release channel.
    5. Set the maintenance scheduleAdd a recurring maintenance window outside business hours, and an exclusion for any freeze period.
    6. ConnectRun gcloud container clusters get-credentials. With --dns-endpoint you can reach the control plane from anywhere you’re allowed by IAM, without an authorised network entry.
    7. Grant access to the workloadGive the service account’s workload identity the IAM role it needs on the bucket. The principal is named after the project, namespace and service account, and no annotation is required.
    8. DeployApply the namespace, service account, deployment, service, gateway, route, autoscaler, disruption budget and network policy, and wait for the rollout. Autopilot may take a minute to add nodes for the first pods.
    9. Plan the upgradesCheck which versions your channel offers, set maintenance windows, and test a Regular or Stable upgrade on a staging cluster first.

    Tip: Autopilot accepts most workloads unchanged, but check the pods for privileged mode, host paths and daemonsets. If you do need them, the same page of the docs explains how to run Autopilot-style compute classes inside a Standard cluster. See the code references for the same cluster as Terraform.

    Common issues after configuration

    SymptomLikely causeWhat to check / fix
    kubectl fails with gke-gcloud-auth-plugin not foundRecent kubectl versions need the separate auth plugin that GKE shipsInstall the plugin (gcloud components install gke-gcloud-auth-plugin or your package manager) and set USE_GKE_GCLOUD_AUTH_PLUGIN only if an old client asks for it.
    kubectl times out against a private clusterYour address isn’t in the master authorised networks, or the private endpoint isn’t reachable from where you areAdd your CIDR with --master-authorized-networks, use a VM or VPN inside the VPC, or enable the DNS-based endpoint.
    Pods Pending for a minute or two in AutopilotAutopilot is creating a node for themThat’s normal for the first pods after a quiet period. For latency-sensitive workloads keep a few replicas running, or use a balloon deployment to hold spare capacity.
    Autopilot rejects the pod: violates Autopilot constraintsThe manifest asks for privileged mode, host networking, a hostPath or a node setting Autopilot doesn’t allowRemove the setting, or move the workload to a Standard cluster (or a Standard cluster with an Autopilot compute class).
    Pod requests were silently raisedAutopilot rounds requests up to its minimums and ratios, and sets limits equal to requests in some classesRead the pod’s applied resources with kubectl get pod -o yaml, set requests that already match, and check the bill for pods that request far more than they use.
    PERMISSION_DENIED from a Google API inside the podThe IAM binding names a different namespace or service account, or only a node’s service account has the roleCheck the principal string (project number, pool, namespace, service account), grant the role to it, and wait a minute for IAM to propagate.
    Workload Identity works for the app, but not for a sidecar or init containerA strict network policy blocks the metadata serverAllow egress to the GKE metadata server (169.254.169.252:988, and 169.254.169.254:80 on Dataplane V2).
    Gateway stays Programmed: FalseThe Gateway API isn’t enabled on the cluster, the proxy-only subnet is missing for a regional gateway, or a firewall rule blocks the health checksEnable the Gateway API channel, create the proxy-only subnet for regional classes, and allow Google’s health check ranges 130.211.0.0/22 and 35.191.0.0/16.
    ImagePullBackOff from Artifact RegistryThe node’s service account lacks the Artifact Registry Reader role, or private nodes can’t reach the registryGrant roles/artifactregistry.reader, and turn on Private Google Access on the subnet.
    An upgrade is blocked or stuckA Pod Disruption Budget allows no evictions, a maintenance exclusion is active, or surge capacity isn’t availableCheck kubectl get pdb -A, review the cluster’s maintenance exclusions, and raise surge or use blue-green node pool upgrades.
    The bill shows a cluster fee even though you expected a free clusterThe monthly free credit covers one Autopilot or zonal cluster per billing account, and further clusters pay the feeCount clusters per billing account, merge small ones and delete test clusters you aren’t using.

    Use cases: when and where to use it

    Good fit

    • Teams that want Kubernetes without managing nodes, which Autopilot allows
    • Microservices with changing load, where paying for requested pod resources avoids paying for idle nodes
    • Platform teams that run many clusters and want fleet-level policy
    • Workloads that use Google services such as Cloud Storage, Pub/Sub, BigQuery or Vertex AI through Workload Identity
    • GPU and TPU jobs for machine learning on Standard or Autopilot accelerator classes
    • Organisations moving from self-managed Kubernetes who want the version the community runs, quickly

    Consider something else

    • A single container with HTTP traffic → Cloud Run, which scales to zero and needs no cluster
    • Event-driven code → Cloud Run functions
    • One virtual machine with an application on it → Compute Engine
    • A team with nobody to own Kubernetes policy and upgrades → start with Cloud Run and move later
    • The same job on other clouds → compare Amazon EKS and Azure Kubernetes Service

    Pros: why consider it?

    Why teams choose it

    • Autopilot removes node management and ties cost to pod requests
    • Strong release channel model, with maintenance windows and exclusions
    • Workload Identity Federation needs no key files and no annotations
    • Dataplane V2 gives network policy and flow logs out of the box
    • Tight links to Cloud Load Balancing, Artifact Registry, IAM and Cloud Logging
    • A monthly free credit that covers the fee of one cluster

    Trade-offs to weigh

    • Autopilot restricts privileged, host-level and some daemonset workloads
    • Pod requests become a cost lever, so sloppy requests cost real money
    • The cluster management fee applies per cluster, so many small clusters add up
    • Some choices are permanent per cluster, such as the network setup and zone model
    • Fleet features sit in a separate, paid Enterprise edition
    • You still own workload design, policy and image supply chain

    Common threats, vulnerabilities & risks

    RiskSeverityWhy it mattersMitigation
    Control plane open to any addressHighA public endpoint with no network restriction is open to credential stuffing and unpatched flaws.Use private nodes, authorised networks or the DNS-based endpoint with IAM, and keep access to a few groups.
    Nodes running with the default service accountHighThe Compute Engine default account often carries broad project rights that every pod inherits.Use a dedicated minimal node service account, and Workload Identity Federation for pods.
    Service account keys mounted as secretsHighKeys don’t expire by default and can leak through images, logs or backups.Grant IAM roles to the Workload Identity principal instead, and block key creation with an organisation policy.
    Wide IAM and Kubernetes RBAC for developersMediumA broad cluster-admin or container.admin can change any workload.Use the Kubernetes Engine Developer or Viewer roles with namespace-level RBAC, and review bindings regularly.
    A channel that moves too quickly for productionMediumRapid channel versions arrive first, aren’t covered by the SLA and can hold unknown problems.Run production on Regular or Stable, and staging one channel ahead.
    Pod requests far above real use on AutopilotMediumYou pay for what you request, and unused requests are pure waste.Compare requests with usage in Cloud Monitoring, and right-size with Vertical Pod Autoscaler recommendations.
    Upgrades breaking removed Kubernetes APIsMediumManifests that use removed API versions stop applying after a minor upgrade.Check the deprecation insights in the console, lint manifests and test in staging.
    Images from unknown sourcesLow–MedA compromised or tampered image runs with your pod’s identity.Pull only from Artifact Registry, scan images, and enforce Binary Authorization in production.
    Cost drift from idle clusters and load balancersLow–MedTest clusters, forwarding rules and persistent disks keep billing quietly.Label by team, delete test clusters, share gateways and set a budget alert.

    Performance optimisation

    • Set requests from observed usage. Autopilot bills them and the scheduler uses them, so they decide both cost and placement.
    • Use the Horizontal Pod Autoscaler for replicas, and Vertical Pod Autoscaler in recommendation mode to find the right size.
    • Choose a compute class that fits: Balanced for general services, Scale-Out for cheap parallel work, accelerator classes for GPUs.
    • Spread replicas over zones with topology spread constraints, and use regional clusters for production.
    • Use NEGs through the Gateway API so the load balancer sends traffic straight to pods, not through a node hop.
    • Turn on image streaming and keep images small, since pod start-up time is dominated by the pull on a fresh node.
    • Keep a small buffer of spare capacity with a low-priority placeholder deployment if scale-up delay hurts your latency target.
    • Place stateful workloads and their Persistent Disks in the same zone, and use regional disks when a pod must survive a zone failure.

    Reduce monthly cost

    FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Google Kubernetes Engine.

    • Remember the cluster management fee of $0.10 per cluster-hour, and use the monthly free credit, which covers one Autopilot or zonal cluster per billing account.
    • On Autopilot, right-size requests. Unused requests are billed at the same rate as used ones.
    • On Standard, keep node utilisation high with the cluster autoscaler or node auto-provisioning, because you pay for idle VMs.
    • Compare modes by node utilisation: Autopilot usually wins for bursty or small workloads, and Standard for dense, steady ones. Measure before you move.
    • Use Spot pods or Spot VMs for fault-tolerant batch work.
    • Buy committed use discounts for the steady base of compute, and let spikes run at the normal rate.
    • Share gateways and load balancers between services, since each forwarding rule bills by the hour.
    • Watch inter-zone and egress traffic. Chatty services across zones and large downloads add to the bill.
    • Send only the logs you need to Cloud Logging, and exclude noisy namespaces from ingestion.
    • Label clusters and namespaces, export billing data to BigQuery and set budget alerts.

    The prices here are Google Cloud list prices as we read them in October 2026, mostly through secondary sources, and the Autopilot rates differ by region and compute class. Check the live pricing page before you plan around them (see Pricing).

    Security optimisation

    • Use private nodes, limit the control plane with authorised networks or the DNS-based endpoint, and keep the endpoint off the public internet where possible.
    • Give pods Workload Identity Federation instead of key files, and use a dedicated, minimal service account for nodes in Standard clusters.
    • Grant people IAM roles at project level and Kubernetes RBAC at namespace level, with groups instead of individual accounts.
    • Enable Shielded GKE Nodes (the default) and use Container-Optimized OS images, which GKE patches through upgrades.
    • Enforce Pod Security Standards, run containers as non-root and drop capabilities. Autopilot already blocks several risky settings.
    • Write network policies, beginning with default deny, and let Dataplane V2 enforce them.
    • Encrypt secrets with a Cloud KMS key (application-layer secrets encryption), and prefer Secret Manager for real secrets.
    • Turn on Binary Authorization to admit only attested images, and scan images in Artifact Registry.
    • Use the security posture dashboard and workload vulnerability scanning to catch misconfigurations and known flaws.
    • Keep Cloud Audit Logs for the Kubernetes API on, and alert on exec, role bindings and secret reads.

    Governance & compliance

    Guardrails

    • Labels on clusters and namespaces (owner, environment, cost centre) enforced by an organisation policy or a Terraform module
    • Organisation policies that block service account key creation and require private nodes and Shielded nodes
    • A shared Terraform module for clusters with private nodes, release channel, maintenance window and Workload Identity already set
    • An approved list of release channels per environment, so production never sits on Rapid

    Continuous checks (Security Command Center and Policy Controller)

    • “Master authorized networks disabled” finding in Security Command Center
    • “Workload Identity disabled” and “Legacy authorization enabled” findings
    • “Private cluster disabled” finding for the cluster
    • “Release channel disabled” finding
    • A Policy Controller constraint that rejects privileged pods and images from outside your registry

    Cloud Audit Logs record who created, changed or deleted clusters and what was done through the Kubernetes API, Security Command Center reports posture findings, Policy Controller (in the Enterprise edition, or open source Gatekeeper) enforces admission rules, and Compliance Manager and the Cloud compliance pages hold certificates. The shared duties are the standard managed-Kubernetes ones: Google runs and patches the control plane, and on Autopilot the nodes too, while you answer for workload permissions, network policy, images and how soon you adopt upgrades.

    Reduce carbon footprint

    • Right-size requests. Pods that ask for more than they use keep hardware running for nothing.
    • Let Autopilot or the autoscaler remove idle capacity, and delete test clusters.
    • Choose a Region with a low carbon share when data rules allow. Google publishes the carbon-free energy percentage per region.
    • Batch non-urgent jobs onto Spot capacity that would otherwise sit idle.
    • Share clusters across teams with namespaces instead of duplicating whole stacks.
    • Compress logs and keep traffic in-zone to reduce stored and moved data.
    • Cloud Carbon Footprint in the console estimates emissions per project and service. Check what it shows for GKE before you quote a figure.

    Pricing

    Purchase options

    Cluster management fee Per cluster-hour

    $0.10 per cluster per hour for both Autopilot and Standard, billed by the second. A monthly credit per billing account offsets the fee of one Autopilot or zonal cluster.

    Autopilot compute Per vCPU, GiB and storage, by the second

    You pay for the CPU, memory and ephemeral storage your pods request while they run. Rates depend on the region and the compute class.

    Standard compute Per VM

    You pay normal Compute Engine prices for the nodes in your pools, whether they’re busy or idle, plus their disks.

    Everything around it Varies

    Load balancers and forwarding rules, Cloud NAT, persistent disks, network egress, Cloud Logging, the Enterprise edition per vCPU and extended-support charges for old versions.

    What you actually pay for

    • The cluster management fee, less the monthly free credit where it applies
    • Pod requests (Autopilot) or node VMs (Standard)
    • Persistent disks, Filestore and snapshots
    • Load balancers, Cloud NAT and data leaving Google Cloud or crossing zones
    • Logging, monitoring, the Enterprise edition and extended support if you use them

    Rates vary by region and change over time, and some figures on this page come from secondary sources. See the official GKE pricing page and the Google Cloud Pricing Calculator for current numbers, and the page on Autopilot mode for how requests are billed.

    Important code references

    The orders-api service once more, this time on a regional, private Autopilot cluster in Mumbai. The gcloud tab prepares the network, creates the cluster, grants a bucket role directly to the pod’s identity and applies the manifest (service account, deployment, Gateway, route, autoscaler, disruption budget and network policy). Terraform builds the same cluster. The Python tab runs inside the pod and writes a receipt to Cloud Storage with the identity GKE hands it. The C# tab runs from a pipeline and lists pods that keep restarting or were killed for memory. Replace the project, project number, bucket and ranges with your own. A cluster bills from the moment it exists, so delete the test one when you’re done.

    # Placeholders: replace the project, project number, bucket and IP ranges with your own.
    PROJECT=my-orders-project
    PROJECT_NUMBER=123456789012
    REGION=asia-south1
    CLUSTER=orders-prod
    BUCKET=orders-receipts-example
    
    gcloud config set project $PROJECT
    gcloud services enable container.googleapis.com artifactregistry.googleapis.com compute.googleapis.com
    
    # The network: one subnet with secondary ranges for pods and services, and NAT for private nodes.
    gcloud compute networks create orders-net --subnet-mode=custom
    gcloud compute networks subnets create orders-nodes --network=orders-net --region=$REGION --range=10.10.0.0/20 \
      --secondary-range=pods=10.64.0.0/14,services=10.68.0.0/20 --enable-private-ip-google-access
    gcloud compute routers create orders-router --network=orders-net --region=$REGION
    gcloud compute routers nats create orders-nat --router=orders-router --region=$REGION --auto-allocate-nat-external-ips --nat-all-subnet-ip-ranges
    
    # The cluster: Autopilot, private nodes, the control plane limited to the office range, and the Regular release channel.
    gcloud container clusters create-auto $CLUSTER --region=$REGION \
      --network=orders-net --subnetwork=orders-nodes \
      --cluster-secondary-range-name=pods --services-secondary-range-name=services \
      --enable-private-nodes --enable-master-authorized-networks --master-authorized-networks=203.0.113.0/24 \
      --release-channel=regular --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE \
      --security-posture=standard --workload-vulnerability-scanning=standard
    
    # Upgrades only on Saturday nights (UTC), and a freeze around the end-of-quarter sale.
    gcloud container clusters update $CLUSTER --region=$REGION \
      --maintenance-window-start=2026-11-07T21:00:00Z --maintenance-window-end=2026-11-08T01:00:00Z \
      --maintenance-window-recurrence="FREQ=WEEKLY;BYDAY=SA"
    
    # Workload Identity Federation needs no service account: grant the role straight to the pod's principal.
    gcloud storage buckets add-iam-policy-binding gs://$BUCKET \
      --member="principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT.svc.id.goog/subject/ns/orders/sa/orders-api" \
      --role=roles/storage.objectCreator
    
    # Connect through the DNS-based endpoint, then deploy.
    gcloud container clusters get-credentials $CLUSTER --region=$REGION --dns-endpoint
    kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Namespace
    metadata:
      name: orders
      labels:
        pod-security.kubernetes.io/enforce: restricted
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: orders-api
      namespace: orders
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: orders-api
      namespace: orders
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: orders-api
      template:
        metadata:
          labels:
            app: orders-api
        spec:
          serviceAccountName: orders-api
          nodeSelector:
            cloud.google.com/compute-class: Balanced
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          containers:
            - name: api
              image: $REGION-docker.pkg.dev/$PROJECT/apps/orders-api:1.4.2
              ports:
                - containerPort: 8080
              env:
                - name: RECEIPT_BUCKET
                  value: $BUCKET
              resources:
                requests:
                  cpu: 250m
                  memory: 512Mi
                  ephemeral-storage: 1Gi
              readinessProbe:
                httpGet:
                  path: /healthz
                  port: 8080
              securityContext:
                allowPrivilegeEscalation: false
                readOnlyRootFilesystem: true
                capabilities:
                  drop: ["ALL"]
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: orders-api
      namespace: orders
    spec:
      selector:
        app: orders-api
      ports:
        - port: 80
          targetPort: 8080
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: orders-gw
      namespace: orders
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
        - name: http
          protocol: HTTP
          port: 80
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: orders-api
      namespace: orders
    spec:
      parentRefs:
        - name: orders-gw
      rules:
        - backendRefs:
            - name: orders-api
              port: 80
    ---
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: orders-api
      namespace: orders
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: orders-api
      minReplicas: 3
      maxReplicas: 12
      metrics:
        - type: Resource
          resource:
            name: cpu
            target:
              type: Utilization
              averageUtilization: 70
    ---
    apiVersion: policy/v1
    kind: PodDisruptionBudget
    metadata:
      name: orders-api
      namespace: orders
    spec:
      minAvailable: 2
      selector:
        matchLabels:
          app: orders-api
    ---
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: orders-api-from-load-balancer
      namespace: orders
    spec:
      podSelector:
        matchLabels:
          app: orders-api
      policyTypes: ["Ingress"]
      ingress:
        - from:
            - ipBlock:
                cidr: 130.211.0.0/22
            - ipBlock:
                cidr: 35.191.0.0/16
          ports:
            - port: 8080
    EOF
    kubectl -n orders rollout status deployment/orders-api
    
    # Later: which versions does the Regular channel offer for this cluster?
    gcloud container get-server-config --region=$REGION --format="yaml(channels)"
    # Placeholders: pass in your project, project number and the range that may reach the control plane.
    variable "project_id" {
      type = string
    }
    
    variable "project_number" {
      type = string
    }
    
    variable "office_cidr" {
      type    = string
      default = "203.0.113.0/24"
    }
    
    variable "region" {
      type    = string
      default = "asia-south1"
    }
    
    variable "receipt_bucket" {
      type    = string
      default = "orders-receipts-example"
    }
    
    resource "google_compute_network" "orders" {
      name                    = "orders-net"
      auto_create_subnetworks = false
    }
    
    resource "google_compute_subnetwork" "nodes" {
      name                     = "orders-nodes"
      region                   = var.region
      network                  = google_compute_network.orders.id
      ip_cidr_range            = "10.10.0.0/20"
      private_ip_google_access = true
    
      secondary_ip_range {
        range_name    = "pods"
        ip_cidr_range = "10.64.0.0/14"
      }
    
      secondary_ip_range {
        range_name    = "services"
        ip_cidr_range = "10.68.0.0/20"
      }
    }
    
    resource "google_compute_router" "orders" {
      name    = "orders-router"
      region  = var.region
      network = google_compute_network.orders.id
    }
    
    resource "google_compute_router_nat" "orders" {
      name                               = "orders-nat"
      router                             = google_compute_router.orders.name
      region                             = var.region
      nat_ip_allocate_option             = "AUTO_ONLY"
      source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
    }
    
    resource "google_container_cluster" "orders" {
      name                = "orders-prod"
      location            = var.region
      enable_autopilot    = true
      deletion_protection = true
    
      network    = google_compute_network.orders.id
      subnetwork = google_compute_subnetwork.nodes.id
    
      ip_allocation_policy {
        cluster_secondary_range_name  = "pods"
        services_secondary_range_name = "services"
      }
    
      private_cluster_config {
        enable_private_nodes    = true
        enable_private_endpoint = false
      }
    
      master_authorized_networks_config {
        cidr_blocks {
          cidr_block   = var.office_cidr
          display_name = "office"
        }
      }
    
      release_channel {
        channel = "REGULAR"
      }
    
      binary_authorization {
        evaluation_mode = "PROJECT_SINGLETON_POLICY_ENFORCE"
      }
    
      maintenance_policy {
        recurring_window {
          start_time = "2026-11-07T21:00:00Z"
          end_time   = "2026-11-08T01:00:00Z"
          recurrence = "FREQ=WEEKLY;BYDAY=SA"
        }
      }
    }
    
    # Workload Identity Federation: the role goes to the pod's principal, no service account and no key.
    resource "google_storage_bucket_iam_member" "orders_api" {
      bucket = var.receipt_bucket
      role   = "roles/storage.objectCreator"
      member = "principal://iam.googleapis.com/projects/${var.project_number}/locations/global/workloadIdentityPools/${var.project_id}.svc.id.goog/subject/ns/orders/sa/orders-api"
    }
    
    output "cluster_name" {
      value = google_container_cluster.orders.name
    }
    # Runs inside the orders-api pod. With Workload Identity Federation the metadata server hands the pod short-lived
    # credentials, and Application Default Credentials find them. There is no key file and nothing to mount.
    import json
    import os
    import time
    
    from google.api_core import retry
    from google.api_core.exceptions import PreconditionFailed
    from google.cloud import storage
    
    _client = storage.Client()    # picks the pod's identity up on its own
    _bucket = _client.bucket(os.environ["RECEIPT_BUCKET"])
    
    
    def write_receipt(order_id, total):
        blob = _bucket.blob("receipts/%s.json" % order_id)
        doc = json.dumps({"order": order_id, "total": total, "saved_at": int(time.time())})
        try:
            # if_generation_match=0 means "only if it doesn't exist yet", so a retry can't overwrite a receipt
            blob.upload_from_string(doc, content_type="application/json", if_generation_match=0,
                                    retry=retry.Retry(initial=0.5, maximum=8.0, timeout=30.0))
        except PreconditionFailed:
            return "gs://%s/%s (already there)" % (_bucket.name, blob.name)
        return "gs://%s/%s" % (_bucket.name, blob.name)
    
    
    if __name__ == "__main__":
        print(write_receipt("A-1042", 1249.50))
    // dotnet add package KubernetesClient
    // Lists pods that keep restarting or were killed for running out of memory, across all namespaces.
    // The kubeconfig written by "gcloud container clusters get-credentials" calls gke-gcloud-auth-plugin for the token.
    using k8s;
    using k8s.Models;
    
    var client = new Kubernetes(KubernetesClientConfiguration.BuildConfigFromConfigFile());
    V1PodList all = await client.CoreV1.ListPodForAllNamespacesAsync();
    
    var noisy = from pod in all.Items
                from cs in pod.Status.ContainerStatuses ?? new List<V1ContainerStatus>()
                let oom = cs.LastState?.Terminated?.Reason == "OOMKilled"
                where cs.RestartCount >= 3 || oom
                orderby cs.RestartCount descending
                select new { Ns = pod.Metadata.NamespaceProperty, Pod = pod.Metadata.Name, Container = cs.Name, cs.RestartCount, oom };
    
    int count = 0;
    foreach (var row in noisy)
    {
        count++;
        string hint = row.oom ? "  <- raise the memory request" : "";
        Console.WriteLine($"{row.Ns}/{row.Pod} [{row.Container}] restarts={row.RestartCount}{hint}");
    }
    
    Console.WriteLine(count == 0 ? "No pod has restarted three times or been OOM killed." : $"{count} container(s) need a look.");
    return count == 0 ? 0 : 1;

    Best videos to explore

    Short walkthrough videos for this service are being prepared. They will appear here and load only when you press play. Until then, follow CloudBrum on YouTube for new videos.

    Introduction to Google Kubernetes EngineVideo coming soon · Beginner
    GKE Autopilot versus StandardVideo coming soon · Intermediate
    Workload Identity Federation on GKEVideo coming soon · Intermediate
    GKE release channels and safe upgradesVideo coming soon · Advanced

    Interview questions

    BasicWhat is Google Kubernetes Engine?

    It’s Google Cloud’s managed Kubernetes service. Google runs the control plane, and you either manage the node pools yourself (Standard mode) or let Google manage the nodes and bill you for what your pods request (Autopilot mode). You deploy with the usual Kubernetes tools.

    BasicWhat is the difference between GKE Autopilot and Standard?

    In Autopilot, Google provisions and manages the nodes, and you pay for the CPU, memory and storage your pods request. Standard gives you control of node pools and machine types, and you pay for the VMs whether they’re full or empty. Autopilot restricts privileged and host-level workloads.

    BasicDoes GKE charge for the cluster itself?

    Yes. A management fee of $0.10 per cluster-hour applies to both modes, and a monthly free credit per billing account covers the fee for one Autopilot or zonal Standard cluster. Compute, storage, load balancers and traffic are billed on top.

    IntermediateHow does a pod call a Google API without a key file?

    With Workload Identity Federation for GKE. Every pod has an identity based on its project, namespace and service account, and you grant an IAM role directly to that principal, for example roles/storage.objectCreator on a bucket. The client libraries find the credentials through the metadata server, so nothing is mounted.

    IntermediateWhat are release channels and how would you use them?

    A channel subscribes the cluster to a stream of Kubernetes versions: Rapid, Regular, Stable, and Extended for Standard clusters. Production usually sits on Regular or Stable, staging one channel ahead, and maintenance windows and exclusions control when disruptive upgrades happen.

    IntermediateWhy do pods stay Pending for a while on Autopilot?

    Autopilot creates nodes in response to pods, so the first pods after a quiet period wait for a node to start. It is normal. If it hurts a latency target, keep a few replicas running or hold spare capacity with a low-priority placeholder deployment.

    AdvancedHow would you decide between Autopilot and Standard for a new platform?

    Start from the workloads: if they need privileged containers, unusual node settings or dense, steady packing, Standard fits. If they are mostly ordinary stateless services with variable load and you want little node work, Autopilot usually costs less and takes less effort. Measure node utilisation, because the break-even moves with it, and remember you can run Autopilot compute classes inside Standard clusters.

    AdvancedHow do you keep a private GKE cluster reachable for engineers and pipelines without exposing it?

    Use private nodes, then reach the control plane through the DNS-based endpoint with IAM controlling who may connect, or through authorised networks limited to known ranges, or from inside the VPC over VPN or Interconnect. Add Cloud NAT for node egress and Private Google Access for Google APIs.

    AdvancedA pod gets PERMISSION_DENIED from a Google API even after you granted the role. What do you check?

    Check the principal string: project number, pool name (PROJECT_ID.svc.id.goog), namespace and service account must match exactly. Check that the pod really uses that service account, that a network policy isn’t blocking the metadata server, and that the IAM binding has had a minute to propagate.

    AdvancedHow would you cut the bill of an Autopilot cluster by about a quarter?

    Compare requests with real usage and cut the gap, since you pay for requests. Move fault-tolerant work to Spot pods, use committed use discounts for the steady base, share Gateways instead of creating one per service, reduce log volume and delete test clusters. Check the compute class too, because Scale-Out is cheaper for work that tolerates it.

    Similar or alternative services on other clouds

    CapabilityAWSAzureGoogle Cloud
    ServiceAmazon EKSAzure Kubernetes Service (AKS)Google Kubernetes Engine (GKE)
    Cluster fee$0.10 per hour, $0.60 in extended supportFree tier; Standard about $0.10; Premium about $0.60$0.10 per hour, with a monthly free credit
    Mode where the provider runs nodesEKS Auto ModeAKS AutomaticAutopilot, the model GKE built first
    Pod access to cloud APIsEKS Pod Identity or IRSAEntra Workload IDWorkload Identity Federation, with no annotation needed
    Node scalingKarpenter, Cluster AutoscalerNode auto-provisioning, Cluster AutoscalerAutopilot, node auto-provisioning, Cluster Autoscaler
    Who signs inIAM roles through access entriesEntra ID with Azure RBACGoogle accounts and IAM with Kubernetes RBAC
    Load balancing from KubernetesAWS Load Balancer Controller, Auto ModeApp Routing, Application Gateway for ContainersGateway API and Ingress on Cloud Load Balancing
    How versions arriveYou choose a version, with a defined support windowPick an upgrade channel, optional Long-Term SupportRelease channels with maintenance windows and exclusions

    If you only need to run a stateless container, look at Cloud Run before you build a cluster. For event-driven code with no servers use Cloud Run functions. The data for a cluster's applications usually sits outside it, in Cloud SQL or Cloud Storage.

    Did you find this article helpful?

    Your answer helps us improve this page for the next reader.

    Sources and further reading

    CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.