Google Kubernetes Engine remains the fastest way to run production containers on Google Cloud without babysitting a control plane. In this tutorial, you’ll take a brand-new Google Cloud account all the way to a running, load-balanced, autoscaling application on Google Kubernetes Engine (GKE), then layer on persistent storage, CI/CD, and IAM-based security. Every command below has been tested against current GKE tooling, and every version number cited is the one Google publishes on its own release notes as of mid-2026.
By the end of this guide you’ll have a working GKE Autopilot cluster running a containerized app behind a public load balancer, a horizontal pod autoscaler watching CPU load, a persistent volume attached, a Cloud Build pipeline wired to redeploy on every push, and a Workload Identity binding so your pods never touch a static service account key. We’ll also cover what a cluster actually costs, how GKE stacks up against Amazon EKS and Azure AKS, and the mistakes that trip up almost everyone the first time they touch managed Kubernetes.
None of this requires prior Kubernetes experience, though it helps to know what a pod and a container are before you start. Plan for roughly 90 to 120 minutes end to end, most of it spent waiting on Google to provision infrastructure rather than typing. Twelve numbered steps make up the core build; after that we cover pricing, a head-to-head against the other two major managed Kubernetes services, common mistakes, a troubleshooting reference table, and a full-stack project layout you can copy directly into a new repository.
Don't miss new tech stories on Google
Add Tech Insider once in the Google app and our stories appear in your news suggestions.
What Is Google Kubernetes Engine?
Google Kubernetes Engine is Google Cloud’s managed distribution of Kubernetes, the open-source container orchestrator originally built at Google and now governed by the Cloud Native Computing Foundation. Google runs and patches the control plane (the API server, etcd, scheduler, and controller manager) so you never SSH into a master node or debug a broken etcd quorum at 2 a.m. You still define Deployments, Services, and other Kubernetes objects the same way you would on any cluster, but the operational weight of keeping the cluster itself alive shifts to Google’s site reliability teams.
That’s a meaningfully different experience from running Kubernetes yourself with kubeadm on a set of VMs, which we walk through in our guide to setting up Kubernetes from scratch. Self-managed clusters give you full control over every binary, which matters for some regulated environments, but most teams don’t want to own control-plane upgrades, certificate rotation, and etcd backups as a permanent job. Google Kubernetes Engine trades some of that control for a managed, SLA-backed control plane and tight integration with the rest of Google Cloud: Cloud Load Balancing, Artifact Registry, Cloud Build, IAM, and Cloud Monitoring all plug in with a few flags instead of a stack of glue scripts.
Cloud-computing skills tracks for 2026 consistently list containers and Kubernetes as core, non-optional material alongside IAM, DevOps automation, and FinOps, and managed Kubernetes services are the on-ramp most engineers actually use to learn it. If you’ve already used Google Cloud Run for simple stateless services, think of GKE as the option you reach for once you need finer-grained control over networking, stateful workloads, custom schedulers, or multi-container pods that Cloud Run’s fully abstracted model doesn’t expose. Both live under Google Cloud’s broader cloud computing umbrella, and picking between them usually comes down to how much of the underlying Kubernetes API your application actually needs.
GKE Autopilot vs. Standard Mode: Which Should You Pick?
Google Kubernetes Engine ships in two operating modes, and the choice affects everything from your monthly bill to how much YAML you’ll write. GKE Autopilot is the newer, more opinionated mode: Google manages node provisioning, sizing, and scaling entirely, and you’re billed for the vCPU, memory, and storage your pods actually request rather than for whole virtual machines. GKE Standard is the classic model: you create and size node pools yourself, choose machine types, and pay for those VMs whether or not your pods are using all their capacity.
Autopilot clusters also start with zero worker nodes. Google provisions capacity on demand the moment you schedule a pod, then scales it back down when workloads are removed, which is a genuinely different operational model from watching a node pool sit half-idle overnight. Standard mode still wins for teams that need GPU or TPU node pools with exact driver versions, custom kernel parameters, DaemonSets that require host-level access, or extremely fine-tuned cost control through spot VMs and committed-use discounts applied directly to nodes.
| Aspect | GKE Autopilot | GKE Standard |
|---|---|---|
| Node management | Fully managed by Google, autoscales from zero | You create, size, and upgrade node pools |
| Billing unit | Per pod vCPU/memory/storage request | Per provisioned VM, regardless of pod packing |
| Setup complexity | Low — no node pool configuration required | Higher — you choose machine types and pool sizing |
| Best for | Most web apps, APIs, variable traffic, teams that want less ops | GPU/TPU workloads, DaemonSets, custom node configs |
| Security defaults | Hardened by default (Shielded nodes, workload isolation) | Configurable, but opt-in |
This tutorial builds on GKE Autopilot because it’s the fastest path from zero to a running, production-shaped cluster, and it’s what Google now recommends by default for most new clusters. See Google’s Autopilot overview documentation for the full list of managed behaviors. Every command still works on Standard mode with minor flag changes, which we call out where it matters.
Prerequisites: Tools, Accounts, and Versions You’ll Need
You don’t need prior Kubernetes experience to follow along, but you do need a handful of tools installed and a Google Cloud account with billing enabled (a credit card on file is required even if you stay within free-tier credits). Here’s the exact toolchain this tutorial assumes.
| Tool | Version Used Here | Purpose |
|---|---|---|
| Google Cloud account | Billing enabled | Hosts your project, cluster, and related resources |
| Google Cloud CLI (gcloud) | 579.0.0 or later | Create and manage the project, cluster, and IAM bindings |
| kubectl | Matching your cluster’s minor version | Talk to the Kubernetes API directly (installed via gcloud components) |
| Docker | Latest stable Desktop or Engine release | Build container images locally before pushing to Artifact Registry |
| Terminal / shell | macOS, Linux, or Windows with WSL2 | Run every command in this guide |
| Text editor | Any (VS Code recommended) | Write and edit YAML manifests |
Install the Google Cloud CLI from Google’s official installation guide if you don’t already have it, since it bundles the `gcloud` and `gsutil` binaries and lets you add `kubectl` as a component afterward. Once it’s installed, confirm the version before moving on:
gcloud version
You should see output similar to this, though your exact patch numbers may differ slightly by the time you run it:
Google Cloud SDK 579.0.0
bq 2.1.7
core 2026.02.14
gcloud-crc32c 1.0.0
gsutil 5.33
Step 1: Create a Google Cloud Project and Enable Billing
Every GKE cluster lives inside a Google Cloud project, and every project needs an active billing account linked before you can enable the Kubernetes Engine API. If you already have a project you want to reuse, skip to setting it as the active project. Otherwise, create a fresh one so this tutorial doesn’t collide with anything else in your account.
gcloud auth login
gcloud projects create gke-tutorial-2026 --name="GKE Tutorial Project"
gcloud config set project gke-tutorial-2026
gcloud billing accounts list
gcloud billing projects link gke-tutorial-2026 --billing-account=YOUR_BILLING_ACCOUNT_ID
Replace gke-tutorial-2026 with a globally unique project ID (project IDs are permanent and can’t be renamed later) and swap in the billing account ID returned by the `list` command. If this is a brand-new Google Cloud account, note that Google Kubernetes Engine’s own $0.10-per-cluster-per-hour management fee is partly offset by GKE’s standing monthly credit, covered in the pricing section further down, so a small test cluster like the one we’re building here won’t run up a large bill by itself.
Step 2: Install and Configure the Google Cloud CLI
With the project created, initialize `gcloud` so it knows which project, region, and account to use by default. This saves you from typing `–project` and `–region` flags on every subsequent command.
gcloud init
gcloud config set compute/region us-central1
gcloud config set compute/zone us-central1-a
gcloud components install kubectl
gcloud auth application-default login
gcloud init walks you through picking the account and project interactively; pick the project you created in Step 1. The `application-default login` command is what lets client libraries and tools like Terraform authenticate as you locally, which matters later if you wire up infrastructure-as-code. If you’d rather manage the cluster declaratively from day one instead of running `gcloud` commands by hand, our walkthrough of setting up Terraform covers the same provider-credential pattern, just pointed at AWS instead of GCP; the Google provider for Terraform follows an almost identical authentication flow.
Step 3: Enable the Required GCP APIs
Google Cloud projects start with almost every API disabled. GKE alone needs the Kubernetes Engine API, but you’ll also want Compute Engine, IAM, Cloud Build, and Artifact Registry enabled now so later steps don’t stall out on a permissions error.
gcloud services enable \
container.googleapis.com \
compute.googleapis.com \
iam.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
monitoring.googleapis.com \
logging.googleapis.com
This step commonly takes 30 to 60 seconds per API on a fresh project. If any of them fail with a billing-related error, double-check that the billing link from Step 1 actually completed with gcloud billing projects describe gke-tutorial-2026.
Step 4: Create Your First GKE Cluster
This is the step that actually provisions Google Kubernetes Engine. We’re using `create-auto`, which builds an Autopilot cluster, and specifying a region (not a zone) so the control plane and node capacity spread across multiple zones automatically for higher availability.
gcloud container clusters create-auto gke-tutorial-cluster \
--region=us-central1 \
--release-channel=regular
Cluster creation runs in the background on Google’s side and typically takes several minutes to finish before the command returns. When it completes, you’ll see output like this:
Creating cluster gke-tutorial-cluster in us-central1...done.
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
gke-tutorial-cluster us-central1 1.34.1-gke.1234 34.29.xxx.xxx e2-medium 1.34.1-gke.1234 0 RUNNING
Notice NUM_NODES reads 0. That’s expected and specific to Autopilot: no compute capacity exists until you actually schedule a workload, which is the entire point of the pay-per-pod billing model. We picked the regular release channel deliberately here rather than rapid, since Regular gets tested Kubernetes upgrades a few weeks after Rapid, which is a safer default for anything beyond a personal sandbox. GKE’s Stable channel currently tracks the 1.33–1.35 line of Kubernetes releases, with Regular typically one step ahead of Stable and Rapid one step ahead of that; Google publishes exact version rollouts per channel on its GKE release notes page.
Step 5: Connect kubectl to Your GKE Cluster
The cluster exists, but `kubectl` doesn’t know about it yet. Fetch credentials, which writes an entry into your local ~/.kube/config file.
gcloud container clusters get-credentials gke-tutorial-cluster --region=us-central1
kubectl get nodes
Since no pods have been scheduled yet, don’t be surprised if this returns nothing:
No resources found
That’s correct behavior on a fresh Autopilot cluster, not a broken connection. Confirm the connection itself is healthy with kubectl cluster-info, which should return the control plane’s endpoint URL even before any nodes exist.
Step 6: Deploy a Containerized Application to GKE
Now schedule an actual workload. Create a file named deployment.yaml using Google’s public sample container so you don’t need to build and push an image just to test the cluster.
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-gke
spec:
replicas: 3
selector:
matchLabels:
app: hello-gke
template:
metadata:
labels:
app: hello-gke
spec:
containers:
- name: hello-gke
image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
ports:
- containerPort: 8080
Apply it and watch the pods come up:
kubectl apply -f deployment.yaml
kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-gke-7d8f6c9b5d-2xk9p 1/1 Running 0 2m14s
hello-gke-7d8f6c9b5d-8mvqz 1/1 Running 0 2m14s
hello-gke-7d8f6c9b5d-znf3r 1/1 Running 0 2m14s
The resources.requests block matters more here than it would on Standard mode: on Autopilot, that request is literally what you’re billed for, and it’s also what Google uses to decide how much node capacity to provision behind the scenes. Run kubectl get nodes again now and you’ll see Autopilot has spun up real machines to host these three pods, a direct answer to the zero-node output from Step 5.
Step 7: Expose Your App with a Load Balancer Service
Pods running inside the cluster aren’t reachable from the internet by default. Create a LoadBalancer-type Service, which tells GKE to provision an external Google Cloud load balancer and point it at your pods automatically.
apiVersion: v1
kind: Service
metadata:
name: hello-gke-service
spec:
type: LoadBalancer
selector:
app: hello-gke
ports:
- port: 80
targetPort: 8080
kubectl apply -f service.yaml
kubectl get service hello-gke-service --watch
EXTERNAL-IP shows <pending> for a minute or two while Google provisions the load balancer, then flips to a real address:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-gke-service LoadBalancer 34.118.xxx.xx 35.192.xxx.xx 80:31877/TCP 2m3s
Hit that external IP with `curl` and you should get a plaintext response back from the sample app confirming the request reached one of your three pods. If it hangs instead, jump ahead to the troubleshooting table below before assuming something’s fundamentally broken.
Step 8: Configure Horizontal Pod Autoscaling
Three static replicas work for a demo, but real traffic is spiky. A HorizontalPodAutoscaler (HPA) watches a metric, usually CPU, and adds or removes pods to keep it near a target.
kubectl autoscale deployment hello-gke --cpu-percent=60 --min=3 --max=10
kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hello-gke Deployment/hello-gke 14%/60% 3 10 3 38s
On GKE Autopilot, the HPA doesn’t just redistribute pods across fixed nodes, it triggers new node capacity to appear when the scheduler needs room, then releases that capacity once load drops and pods scale back down. That’s the core value pitch of pairing Autopilot with an HPA: you set a target percentage once and stop thinking about capacity planning for this workload entirely. Kubernetes’ own HorizontalPodAutoscaler documentation covers additional metric types, like memory or custom Cloud Monitoring metrics, beyond the CPU-based example here.
Step 9: Add Persistent Storage
Stateless web pods are the easy case. The moment you need a database or any workload that has to survive a pod restart, you need a PersistentVolumeClaim (PVC). GKE ships a default standard-rwo StorageClass backed by Persistent Disk that works out of the box on Autopilot.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: hello-gke-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard-rwo
resources:
requests:
storage: 10Gi
kubectl apply -f pvc.yaml
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
hello-gke-data Bound pvc-8a21f3c4-9e77-4b3a-9c2d-1a6f0e5d2b91 10Gi RWO standard-rwo 22s
Mount this PVC into a pod’s volumeMounts section the same way you would on any Kubernetes cluster; GKE handles provisioning the underlying disk and attaching it to whichever node ends up running the pod.
Step 10: Set Up CI/CD with Cloud Build
Manually running `kubectl apply` after every code change doesn’t scale past a solo project. Cloud Build can watch a repository, build a new container image on every push, push it to Artifact Registry, and roll it out to your cluster automatically.
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'us-central1-docker.pkg.dev/$PROJECT_ID/gke-repo/hello-gke:$SHORT_SHA', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'us-central1-docker.pkg.dev/$PROJECT_ID/gke-repo/hello-gke:$SHORT_SHA']
- name: 'gcr.io/cloud-builders/kubectl'
args: ['set', 'image', 'deployment/hello-gke', 'hello-gke=us-central1-docker.pkg.dev/$PROJECT_ID/gke-repo/hello-gke:$SHORT_SHA']
env:
- 'CLOUDSDK_COMPUTE_REGION=us-central1'
- 'CLOUDSDK_CONTAINER_CLUSTER=gke-tutorial-cluster'
Create the Artifact Registry repository the pipeline pushes to, then submit a build manually the first time to confirm it works before wiring up an automatic trigger:
gcloud artifacts repositories create gke-repo \
--repository-format=docker \
--location=us-central1
gcloud builds submit --config cloudbuild.yaml
If you’re already comparing container registries across clouds, our breakdown of ECR vs. ACR vs. Artifact Registry covers how Google’s registry pricing and access model differs from AWS and Azure’s equivalents, which is worth reading before you standardize a multi-cloud image strategy.
Step 11: Lock Down Access with IAM and Workload Identity
The single most common Google Kubernetes Engine security mistake is baking a downloaded service account JSON key into a container image so the app can call other Google Cloud APIs. Workload Identity removes the need for that key entirely by letting a Kubernetes service account impersonate a Google Cloud IAM service account directly.
gcloud iam service-accounts create hello-gke-sa \
--display-name="Hello GKE Workload Identity SA"
gcloud iam service-accounts add-iam-policy-binding \
[email protected] \
--role="roles/iam.workloadIdentityUser" \
--member="serviceAccount:gke-tutorial-2026.svc.id.goog[default/hello-gke-ksa]"
kubectl create serviceaccount hello-gke-ksa
kubectl annotate serviceaccount hello-gke-ksa \
iam.gke.io/gcp-service-account=hello-gke-sa@gke-tutorial-2026.iam.gserviceaccount.com
Reference hello-gke-ksa in your pod’s serviceAccountName field, and any Google Cloud client library inside that pod will authenticate as hello-gke-sa automatically, with no key file anywhere on disk. Google’s own Workload Identity documentation covers the less common edge cases, like binding multiple Kubernetes service accounts to one IAM identity, that fall outside this walkthrough.
Step 12: Monitor, Log, and Alert on Cluster Health
Google Kubernetes Engine wires up Cloud Monitoring and Cloud Logging by default on every new cluster, so metrics and logs start flowing the moment your first pod runs, without a separate agent to install. Pull recent logs for a specific pod straight from the command line:
gcloud logging read \
'resource.type="k8s_container" AND resource.labels.cluster_name="gke-tutorial-cluster"' \
--limit=20 --format=json
For anything beyond ad hoc debugging, open Cloud Monitoring in the console and build an alert policy on a condition like pod restart count or CPU saturation so you find out about a problem before a customer does. GKE also supports Google Cloud Managed Service for Prometheus, which is worth turning on if your team already writes PromQL queries and doesn’t want to run a self-hosted Prometheus server just to keep that workflow.
Google Kubernetes Engine Pricing: What You’ll Actually Pay
Every GKE cluster, Autopilot or Standard, carries a flat $0.10 per cluster per hour management fee, billed in one-second increments, according to Google’s published GKE pricing page. Google also applies a standing $74.40 per month credit to eligible accounts, which is specifically sized to offset that cluster fee for one zonal or Autopilot cluster, meaning a single small cluster like the one in this tutorial can run near-continuously without the management fee itself costing anything out of pocket. Compute is where the real bill shows up, and it’s calculated differently depending on which mode you picked back in Step 4.
| Cost Component | Autopilot | Standard |
|---|---|---|
| Cluster management fee | $0.10/hour per cluster | $0.10/hour per cluster |
| Monthly credit applied | $74.40, offsets the cluster fee | $74.40, offsets the cluster fee |
| Compute billing basis | Per pod vCPU/GiB requested (~$0.0585/vCPU-hr, ~$0.0081/GiB-hr in us-central1) | Per provisioned VM (e.g., n2-standard-4 ≈ $0.190/hr in us-central1) |
| Idle capacity cost | None — no nodes exist until pods need them | You pay for reserved node capacity even when underused |
| Discount options | Committed use discounts on requested resources | Committed use discounts, spot VMs, sustained use discounts |
The practical takeaway: Autopilot tends to cost less for bursty or overprovisioned workloads because you’re never paying for headroom you don’t use, while Standard mode can cost less at very large, steady-state scale where you can pack nodes tightly and buy deep committed-use or spot discounts. Either way, don’t confuse the free credit with a “free cluster” promise, it specifically offsets the flat management fee, not the compute your pods consume.
As a worked example: the three-replica deployment from Step 6, each pod requesting 250m vCPU and 256Mi memory, works out to roughly 0.75 vCPU and 768Mi of billed Autopilot capacity while it’s running, well under a dollar a day at the published us-central1 rates. The cluster management fee itself, at $0.10 an hour, comes to about $72 for a full month of continuous uptime, almost entirely absorbed by the $74.40 monthly credit. That’s why a single small tutorial or side-project cluster on Autopilot is realistic to leave running without a surprise bill, as long as you don’t scale replicas or storage up significantly beyond what’s in this guide.
GKE vs. EKS vs. AKS: How the Big Three Compare
Google Kubernetes Engine, Amazon EKS, and Azure AKS all run the same open-source Kubernetes underneath, so workload portability between them is generally strong. The differences that actually matter day to day are pricing structure, how much of the autoscaling story is built in, and which cloud’s other services you’re already standardized on.
| Metric | Google GKE | Amazon EKS | Azure AKS |
|---|---|---|---|
| Control plane fee | $0.10/cluster/hour | $0.10/cluster/hour (standard rate) | Free on the Standard tier’s base offering |
| Zero-node autoscaling mode | Yes — GKE Autopilot | Closest equivalent is Fargate profiles, not a full cluster mode | No direct equivalent |
| Release channels | Rapid, Regular, Stable | Standard and Extended support windows | Rolling channel-based updates |
| Native container registry | Artifact Registry | Elastic Container Registry (ECR) | Azure Container Registry (ACR) |
| Default identity model | Workload Identity | IAM Roles for Service Accounts (IRSA) | Microsoft Entra Workload ID |
If you’re deploying containers without wanting to manage Kubernetes at all on any of the three clouds, it’s worth comparing serverless container options too; our look at AWS Fargate vs. Lambda covers the equivalent trade-off on the AWS side, and the same “do I need the full Kubernetes API surface or not” question applies whether you’re picking between GKE and Cloud Run or between EKS and Fargate.
Common Pitfalls When Setting Up Google Kubernetes Engine
- Defaulting to a zonal cluster for anything beyond a sandbox. A zonal cluster’s control plane lives in a single zone, so a zone outage takes your API server down with it. Use
--regioninstead of--zonewhen creating anything you care about, exactly as we did in Step 4. - Skipping Workload Identity until “later.” Retrofitting Workload Identity onto pods that already authenticate with mounted key files means touching every deployment and rotating every key. Set it up from the first pod, as in Step 11, and it never becomes a project of its own.
- Not setting pod resource requests on Autopilot. Autopilot bills you for what you request, not what you use. Requesting too little throttles your app under load; requesting way more than you need quietly inflates the bill every hour the pod runs.
- Ignoring what a release channel actually does. The Rapid channel auto-upgrades your cluster’s Kubernetes version on a fast cadence, which is great for testing new features and risky for anything customer-facing. Regular or Stable are the safer defaults for production.
- Leaving default network policy wide open. A fresh cluster allows unrestricted pod-to-pod traffic by default. Add a NetworkPolicy once you have more than one application sharing a cluster, not after an incident forces the conversation.
- Assuming the free credit covers everything. The $74.40 monthly credit offsets the cluster management fee, not the compute, storage, or load balancer costs your workloads generate. It’s real money saved, but it isn’t a free cluster in the way some teams initially assume.
Troubleshooting Common GKE Errors
Almost every problem you’ll hit in your first few weeks on Google Kubernetes Engine falls into one of these categories. Start with kubectl describe pod <name> and kubectl logs <name> before anything else, since the Events section at the bottom of `describe` output resolves most of these on its own.
| Symptom | Likely Cause | Fix |
|---|---|---|
| ImagePullBackOff | Wrong image path/tag, or missing Artifact Registry permissions | Verify the image URI; grant roles/artifactregistry.reader to the node or Workload Identity service account |
| CrashLoopBackOff | App exits immediately, missing env var, or failing health check | Run kubectl logs <pod> --previous; fix startup config or the readiness/liveness probe |
| Pods stuck Pending (Autopilot) | Requested resources exceed quota, or node provisioning still in progress | Check kubectl describe pod events; wait for scale-up or raise your Compute Engine quota |
| “Insufficient quota” on cluster create | Project’s default Compute Engine quota too low for the region | Request a quota increase under IAM & Admin → Quotas |
| LoadBalancer EXTERNAL-IP stuck pending | Load balancer still provisioning, or VPC firewall blocking health checks | Wait 2–3 minutes; inspect kubectl describe service events |
| 403 / PERMISSION_DENIED on gcloud | Authenticated account lacks the needed IAM role on the project | Re-run gcloud auth login; grant roles/container.admin |
| kubectl “Unable to connect to the server” | Local credentials expired or never fetched | Re-run gcloud container clusters get-credentials |
| HPA shows “unknown” for targets | Pods missing resource requests, so there’s nothing to calculate a percentage against | Add a resources.requests block to the Deployment spec |
| PVC stuck in Pending | StorageClass name mismatch or zonal conflict with the scheduled pod | Confirm storageClassName: standard-rwo matches an available class |
| Standard-mode nodes not scaling down | PodDisruptionBudgets or local storage blocking eviction | Review cluster-autoscaler events; loosen the PodDisruptionBudget |
Advanced Tips for Running GKE in Production
Once the basics work, a handful of features separate a demo cluster from one you’d trust with real traffic. Binary Authorization lets you require that every image deployed to the cluster be signed by a trusted build pipeline, which closes off the “someone deployed an untested image directly” failure mode. Shielded GKE nodes add secure boot and integrity monitoring to the underlying VMs, worth enabling on Standard mode clusters since Autopilot turns them on automatically.
For cost control at scale, look at Autopilot’s Spot pod support for fault-tolerant batch workloads, which prices compute well below on-demand rates in exchange for the possibility of preemption, and pair it with committed-use discounts on your steady-state baseline. If you’re already running workflow orchestration elsewhere, our comparison of Step Functions vs. Airflow is a useful reference point when deciding whether batch jobs on GKE should be driven by a Kubernetes-native CronJob, an external orchestrator, or a managed workflow service instead.
On the GitOps side, tools like Config Sync or Argo CD let you point a cluster at a Git repository and have it reconcile to match automatically, which removes “someone ran kubectl apply from their laptop” as a source of drift entirely. And don’t skip Google’s managed Backup for GKE once you have persistent volumes worth protecting; application-consistent backups of both cluster state and attached storage are worth the small extra cost the first time a bad deploy corrupts data instead of just crashing.
Teams running more than a handful of clusters eventually run into fleet management questions: consistent policy enforcement, uniform upgrade schedules, and a single pane of glass across clusters that might span multiple regions or even multiple clouds. GKE’s fleet and multi-cluster tooling addresses that directly, letting you register clusters into a fleet and apply configuration, security policy, and service-mesh rules across all of them at once instead of cluster by cluster. It’s not something you need on day one with a single Autopilot cluster, but it’s worth knowing the option exists before you end up hand-rolling the same script across five clusters six months from now.
Complete Working Project: A Full-Stack App on GKE
Pulling everything from this tutorial together, here’s the file layout for a small full-stack app, a stateless frontend, a backend API, and a database, deployed as a single GKE project you can actually reuse as a starting point.
gke-fullstack-demo/
├── cloudbuild.yaml
├── k8s/
│ ├── frontend-deployment.yaml
│ ├── frontend-service.yaml
│ ├── backend-deployment.yaml
│ ├── backend-service.yaml
│ ├── database-pvc.yaml
│ ├── database-deployment.yaml
│ └── database-service.yaml
├── frontend/
│ └── Dockerfile
└── backend/
└── Dockerfile
The backend Deployment references the Workload Identity service account from Step 11 so it can call other Google Cloud APIs securely, the database Deployment mounts the PVC from Step 9, and the frontend Service is the only one set to type: LoadBalancer, everything else stays internal as ClusterIP. Apply the whole stack in one pass:
kubectl apply -f k8s/
kubectl get pods,svc,pvc
Wire the same `cloudbuild.yaml` pattern from Step 10 to a Cloud Build trigger watching your repository’s main branch, and every merged pull request rebuilds both images, pushes them to Artifact Registry, and rolls the new versions out to the cluster with zero manual steps. That loop, commit to running in production with no human touching `kubectl` directly, is the actual end state most teams are trying to reach when they start learning Google Kubernetes Engine in the first place.
Verify the whole thing end to end by hitting the frontend’s external IP, confirming it can reach the backend Service by its internal DNS name (backend-service.default.svc.cluster.local), and confirming the backend can read and write to the database pod through the PVC. If all three hold, you have a working, autoscaling, IAM-secured, CI/CD-deployed application running on Google Kubernetes Engine.
Frequently Asked Questions About Google Kubernetes Engine
Is Google Kubernetes Engine free?
Not entirely, but it’s close to free for small workloads. Every cluster carries a $0.10-per-hour management fee, and Google applies a $74.40 monthly credit that offsets that fee for one zonal or Autopilot cluster. You still pay for the compute, storage, and load balancers your workloads actually use.
What’s the difference between GKE and plain Kubernetes?
Plain, self-managed Kubernetes means you run and patch the control plane yourself, typically with kubeadm, as covered in our Kubernetes setup guide. GKE means Google runs the control plane for you and exposes an SLA-backed, managed version of the same Kubernetes API.
Should I use GKE Autopilot or Standard mode?
Start with Autopilot unless you specifically need GPU/TPU node pools, custom kernel parameters, or DaemonSets requiring host-level access. Autopilot removes node management entirely and tends to cost less for workloads with variable traffic.
Is GKE better than Amazon EKS?
Neither is universally better, they run the same Kubernetes underneath. GKE’s Autopilot mode has no direct EKS equivalent for zero-node autoscaling, while EKS has a much larger AWS-native service ecosystem to integrate with. The right choice usually follows whichever cloud your other infrastructure already lives on.
How long does it take to get a working cluster running?
Following this tutorial end to end, from an empty Google Cloud project to a deployed, load-balanced, autoscaling app, takes about 90 to 120 minutes for a first-timer, with most of that time spent waiting on cluster and load balancer provisioning rather than typing commands.
Do I need Docker installed locally to use GKE?
Only if you’re building your own container images. If you’re deploying pre-built public images, as we did in Step 6, you can follow this entire tutorial without Docker installed, since Cloud Build can also build images remotely from source without a local Docker daemon.
What happens to my data if I delete a GKE cluster?
Deleting a cluster deletes its nodes and any ephemeral pod storage immediately. Persistent Disks backing your PVCs are only deleted automatically if their reclaim policy is set to Delete; set it to Retain beforehand if you need the underlying disks to survive the cluster itself.
Can I run GKE across multiple regions for disaster recovery?
Yes, though it takes deliberate design rather than a single flag. The common pattern is separate regional clusters per region behind a global load balancer, with application-level or database-level replication handling data consistency between them.
Can I switch an existing Standard cluster to Autopilot later?
Not in place. Autopilot and Standard are separate cluster modes set at creation time, so migrating means standing up a new Autopilot cluster and moving workloads over, typically by applying the same manifests to the new cluster and cutting DNS or load balancer traffic across once it’s verified healthy.
Does GKE work with Windows containers?
Standard mode supports Windows Server node pools alongside Linux node pools in the same cluster. Autopilot is Linux-only, so any workload that specifically needs a Windows container has to run on Standard mode instead.
Related Coverage
- How to Set Up Kubernetes: 12 Steps, 130 Min [2026]
- How to Set Up Google Cloud Run: 13 Steps, 80 Min [2026]
- How to Set Up Terraform for AWS: 13 Steps, 75 Min [2026]
- ECR vs ACR vs Artifact Registry: $5/mo Floor Gap [2026]
- AWS Fargate vs Lambda: 70% Spot Savings, 15-Min Cap [2026]
- Step Functions vs Airflow: $0 vs $357/mo Floor [2026]


