GCP Compute

GCP Compute: Compute Engine, Cloud Run, GKE and Cloud Functions

Quick take: Compute Engine is your VM when you need control. Cloud Run is your fastest path from a container to an HTTPS URL. GKE is Kubernetes when you genuinely need Kubernetes. Cloud Functions is for event-driven snippets. App Engine is the original opinionated PaaS. Pick the abstraction that matches how much infrastructure you actually want to own — not the one your team happens to know.

A retail company ran every workload on Compute Engine because that is what the team knew. They baked custom OS images, hand-rolled startup scripts for trivial APIs, wrote their own autoscaling glue, and spent one engineer-week a month patching kernels and rotating images. The bill was high and, worse, the toil was high — most of the team’s time went into keeping VMs alive rather than shipping features. When they finally moved their stateless APIs to Cloud Run, deployment time dropped from hours to under two minutes, the VMs-to-patch count fell to zero for those services, and the monthly compute spend for that tier dropped by roughly 60% because the services now scaled to zero overnight. The machine-learning training jobs, though, stayed on Compute Engine — they needed specific GPUs, custom NVIDIA drivers, and 200 GB of local SSD scratch space that no serverless product offers. That single migration is the whole lesson of this article in miniature: GCP gives you compute at five very different abstraction levels, and the art is matching each workload to the right rung of the ladder.

This article is the map of that ladder. We treat Compute Engine, Cloud Run, GKE, Cloud Functions and App Engine not as five competing products but as five points on one axis — control on one end, abstraction on the other — where moving toward abstraction trades knobs for the elimination of toil. You will learn what each service actually is, how each one scales (and whether it scales to zero), what drives the bill, the machine families and types behind Compute Engine and GKE, how Spot and preemptible VMs cut cost by up to 91%, how managed instance groups (MIGs) and autoscaling turn raw VMs into a self-healing fleet, and — the payoff — a decision matrix you can run a workload through in thirty seconds. Every operation gets real gcloud and, where it applies, Terraform. The comparisons, machine specs and pricing drivers are all laid out as scannable tables — read the prose once, then keep the tables open when you size your next service.

By the end you will stop defaulting. When a new workload lands on your desk you will know whether it wants a VM you fully own, a container that scales to zero behind an HTTPS URL, a Kubernetes cluster because you have Kubernetes-shaped problems, a function that fires on an event, or a PaaS that just runs your app. Knowing which — and being able to defend it with cost numbers and operational trade-offs — is what separates an architect from someone who runs everything on the one service they already know.

What problem this solves

Every cloud platform offers compute at multiple abstraction levels, but the cost of choosing wrong is rarely visible until months later. Choose too much control (everything on Compute Engine) and you pay in toil: OS patching, image management, autoscaling glue, hardening, and the salaries of the people doing all of it. Choose too much abstraction for a workload that doesn’t fit (a long-running stateful process forced onto Cloud Functions) and you pay in workarounds, timeouts and architecture contortions. Choose Kubernetes when you have three services and no platform team and you pay in operational complexity that buys you nothing. The pain is real and it compounds.

What breaks without a clear mental model: teams standardise on the wrong default. A startup adopts GKE because a senior engineer used it elsewhere, then spends six months learning Kubernetes operations instead of building product. An enterprise mandates Compute Engine for “consistency” and ends up with hundreds of barely-utilised VMs running stateless web apps that should cost a tenth as much on Cloud Run. A developer reaches for Cloud Functions for a 20-minute batch job and fights the timeout ceiling forever. None of these are wrong tools — they are right tools pointed at the wrong workloads.

Who hits this: essentially every team on GCP. It bites hardest on teams migrating from on-premises (who reach for VMs out of habit), teams over-rotated on one technology (Kubernetes shops who orchestrate everything including a static website), and cost-sensitive teams who never realised that an idle Cloud Run service costs literally nothing. The fix is not a single “best” service — it is a framework for matching the workload’s real requirements (statefulness, runtime length, scaling profile, control needs, team capability) to the rung of the ladder that fits.

To frame the whole field before the deep dive, here is the entire GCP compute spectrum at a glance — the five services, what each one fundamentally is, and the one-line reason you’d reach for it:

Service What it fundamentally is Abstraction level Scales to zero? Reach for it when…
Compute Engine Raw virtual machines on Google’s infrastructure Lowest (you own the OS) No (VMs are always-on unless you stop them) You need OS control, GPUs, specific licenses, or long-lived stateful processes
Google Kubernetes Engine (GKE) Managed Kubernetes — container orchestration Low-to-medium (you own the cluster, Google owns the control plane) Pods can; nodes can scale to zero (Autopilot/node-auto-provisioning) You have Kubernetes-shaped problems: many services, complex scheduling, the K8s ecosystem
App Engine Opinionated platform-as-a-service for web apps Medium-high Standard: yes; Flexible: no (min 1 VM) You want a managed runtime for a web app and accept the platform’s opinions
Cloud Run Serverless containers behind an HTTPS endpoint High Yes (default) Stateless HTTP services or jobs in a container, fast deploys, pay-per-use
Cloud Functions Functions-as-a-service — event-driven snippets Highest Yes (default) Short event handlers: a Pub/Sub message, a Storage upload, an HTTP webhook

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You should be comfortable with cloud fundamentals: what a virtual machine is, what a container is (and ideally have built a Docker image), and the difference between a stateless and a stateful workload. Familiarity with running gcloud in Cloud Shell or a configured local SDK helps, as does a basic grasp of HTTP, autoscaling concepts, and what “serverless” means (no servers to manage yourself — Google still runs servers). You do not need Kubernetes expertise; this article explains where GKE fits without requiring you to already know it.

This article sits at the foundation of the GCP compute track and is upstream of nearly everything you’ll build. Once you’ve chosen a compute service here, the deeper single-service articles take over. For the serverless-container path, Cloud Run Explained: Serverless Containers That Scale to Zero (and Back) Without Kubernetes goes far deeper on concurrency, cold starts and revisions. For Kubernetes, GKE Autopilot vs Standard vs Enterprise: Choose Your Kubernetes Mode and GKE Autopilot vs Standard: Which Google Kubernetes Engine Mode Should You Actually Use? drill into cluster modes. The decision itself is also covered, from a slightly different angle, in GCP Cloud Run vs GKE vs Compute Engine: Choose the Right Compute. Underpinning all compute choices are regions and zones — GCP Regions and Zones Explained: What They Really Mean for Availability and Latency — and identity, where every workload runs as something via GCP IAM and Service Accounts: Roles, Bindings and Least Privilege. If you’re coming from another cloud, the translation maps make this faster: GCP for AWS Engineers and GCP for Azure Engineers.

A quick map of who typically owns each compute service in a real org, so you know whose problem each service becomes:

Service Who operates it day-to-day What they own What Google owns
Compute Engine Platform / infra / SRE team OS, patching, images, scaling glue, security hardening Hypervisor, hardware, network, live migration
GKE Standard Platform team + app teams Node pools, K8s objects, upgrades (with help), add-ons Control plane, node auto-repair, managed upgrades
GKE Autopilot App teams (mostly) Workloads (pods, services), resource requests Nodes, scaling, node security, control plane
App Engine App teams Code, app.yaml, scaling config Runtime, OS, scaling, patching, the entire platform
Cloud Run App teams Container image, service config, concurrency Everything below the container
Cloud Functions App teams / developers Function code + dependencies Build, runtime, scaling, everything else

Core concepts

Five mental models make every later decision in this article obvious.

The control-vs-abstraction axis is the master variable. Picture a horizontal line. On the far left sits Compute Engine, where you own everything from the OS up — maximum control, maximum responsibility. On the far right sits Cloud Functions, where you hand Google a snippet and it handles everything else — maximum abstraction, almost no control. Every GCP compute service is a point on that line, and moving rightward systematically trades knobs for the elimination of toil. There is no “best” position, only the one that matches a given workload: an ML training job with custom drivers belongs on the left, a webhook handler on the far right, most stateless web services in the Cloud Run zone right of centre. The biggest mistake teams make is anchoring at one position (usually the far left, out of habit) and dragging every workload to it.

Statefulness and runtime length route the decision more than anything else. Two questions answer most placements. Does the workload hold state on the instance (in-memory session, local disk, a long-lived connection)? If yes, lean toward VMs, GKE StatefulSets or App Engine Flexible — the serverless options assume disposable, interchangeable instances. How long does one unit of work run? A 50-millisecond request fits anywhere; a 9-minute job fits Cloud Run jobs or Cloud Functions (2nd gen); a 6-hour batch job needs Compute Engine, a GKE Job, or a long-running Cloud Run job — never Cloud Functions. Answer these two and the candidate set usually narrows to two services.

Scale-to-zero is the cost game-changer, and only some services play it. A service that scales to zero costs nothing when idle — compute drops to zero (you may still pay for storage or a reserved minimum). Cloud Run, Cloud Functions, App Engine Standard and GKE pods (with the right setup) can scale to zero. Compute Engine VMs and App Engine Flexible cannot — a running VM bills whether it serves one request or a million until you stop it. For spiky, low-average or dev/test workloads, scale-to-zero is the difference between a ₹200/month bill and a ₹6,000/month one. The catch is the cold start: the first request to a scaled-to-zero service pays the start-up latency while an instance spins up.

Serverless does not mean “no servers” — it means “not your servers, and you pay only for use.” Google still runs the servers under Cloud Run and Cloud Functions; you just never see, patch or scale them. The defining properties: you deploy units of work (a container, a function) not machines; the platform scales them automatically including to zero; and you are billed for consumption (requests, CPU-seconds, GB-seconds, invocations) not allocated capacity. This is why serverless is cheap for spiky workloads and can be more expensive than a VM at steady high utilisation — at constant high load, a committed VM beats per-request pricing.

Managed instance groups turn raw VMs into a platform feature. A single VM is a pet — it has a name, it can die, and nothing brings it back. A managed instance group (MIG) built from an instance template is a herd: it maintains a target number of identical VMs, recreates any that fail a health check (autohealing), scales the count on metrics (autoscaling), and rolls out new templates gradually. With a MIG plus a load balancer, Compute Engine gains much of what makes serverless attractive — self-healing and autoscaling — while keeping full OS control. It’s why “Compute Engine” in practice usually means “a MIG,” not a lone VM.

The spectrum, side by side

Before the deep sections, pin down every service against the dimensions that decide placement. This is the mental model in one table; the rest of the article is the detail behind each cell:

Dimension Compute Engine GKE App Engine Cloud Run Cloud Functions
Unit you deploy A VM (or a MIG of VMs) Containers (pods) on a cluster App code + app.yaml A container image A function (code + deps)
You manage the OS? Yes Standard: yes (nodes); Autopilot: no No No No
Scales to zero? No Pods yes; nodes can Standard yes / Flexible no Yes Yes
Max request/job duration Unlimited (it’s a VM) Unlimited Standard ~10 min req; Flexible ~60 min 60 min (request) / longer for jobs 9 min (1st gen) / 60 min (2nd gen)
GPUs / custom hardware Yes (full menu) Yes (GPU node pools) No Yes (limited GPU support) No
State on instance Yes (persistent disk) Yes (StatefulSets, PVs) Flexible only No (stateless) No (stateless)
Cold starts None (always on) None (pods running) Standard: yes / Flexible: no Yes (mitigate with min-instances) Yes
Primary billing unit vCPU+RAM per second Nodes (VMs) + cluster fee Instance-hours / instance-class Requests + CPU/mem time Invocations + CPU/mem time
Operational burden Highest High (Standard) / Medium (Autopilot) Low Very low Lowest
Best fit Full control, GPU, legacy, stateful K8s ecosystem, many services Managed web apps Stateless HTTP / containerised jobs Event-driven glue

The control-versus-abstraction spectrum in depth

The single most useful thing you can internalise is where each service sits and what the move between them costs you. Think of it as a dial you turn from “I own everything” to “I own almost nothing.” Turning it toward abstraction is mostly a one-way win — you shed toil — until you hit a workload requirement the higher abstraction can’t satisfy (a GPU, a 6-hour run, OS-level access, a kernel module), at which point you must turn the dial back. The skill is turning it as far toward abstraction as the workload allows, and no further.

Here is the dial, position by position, with the concrete thing you gain and the concrete thing you give up at each step:

Position (most → least control) You gain by moving here (toward abstraction) You give up The wall you hit that forces you back
Compute Engine (bare VM) — (this is the control anchor) (nothing more controllable in this list)
Compute Engine + MIG Autohealing, autoscaling, rolling updates Per-instance pets; still patch the OS
GKE Standard Container orchestration, scheduling, the K8s ecosystem Cluster + node operations; a steep learning curve Need raw OS/kernel access or non-container workloads
GKE Autopilot Node management gone; pay per pod resource Node-level customisation (DaemonSets limited, no privileged tweaks) Need specific node shapes/customisation Standard allows
App Engine Flexible Managed VMs running your container/runtime Kubernetes flexibility; min 1 instance (no scale-to-zero) Need orchestration of many interdependent services
App Engine Standard Fully managed runtime, scale-to-zero, fast scaling Runtime/library constraints; sandbox limits Need a custom binary, a long job, or an unsupported runtime
Cloud Run Any container, scale-to-zero, HTTPS in minutes, per-use billing Long-lived state; background work outside a request (mitigated by jobs) Need persistent local state or a process that must always run
Cloud Functions Deploy a snippet, zero infra, event triggers built in Everything but the function; tight time/size limits Need anything longer/larger than a small handler

A few practical truths about navigating this dial:

Compute Engine deep dive: machine families, types, and the VM model

Compute Engine is raw infrastructure-as-a-service: you rent virtual machines on Google’s hardware, choose the OS, and own everything from there up. Its superpower is flexibility — any OS, any software, GPUs, TPUs, local SSDs, custom machine shapes — and its cost is toil: you patch, image, scale and secure. This section is for the workloads where the other services genuinely can’t help.

Machine families and types

A Compute Engine VM’s shape is its machine type, and machine types are grouped into families optimised for different workload profiles. Picking the right family is the first sizing decision and the one most people get wrong by defaulting to a general-purpose type for a memory-bound or compute-bound job. The families, what they’re for, and when to reach for each:

Family Series (examples) Optimised for vCPU:memory profile Reach for it when…
General purpose E2, N2, N2D, N4, C4 Balanced price/performance for most workloads ~4 GB per vCPU (varies) Web/app servers, microservices, small-medium databases
Cost-optimised E2 Lowest cost, day-to-day workloads Flexible, capped performance Dev/test, low-traffic services, batch where cost matters
Compute optimised C3, C4, H3 Highest per-core performance Lower memory per vCPU Gaming servers, HPC, CPU-bound batch, ad serving
Memory optimised M1, M2, M3, M4 Very high memory per core Up to ~30 GB+ per vCPU Large in-memory databases, SAP HANA, big analytics
Accelerator (GPU/TPU) A2, A3, A4 (GPU), G2 Attached GPUs/accelerators High memory + GPU ML training/inference, rendering, scientific compute
Scale-out (Arm) T2A, C4A Price/performance on Arm Balanced Scale-out, cloud-native, Arm-compatible workloads

Within a family you choose a machine type that fixes the vCPU and memory, named <series>-<type>-<vcpus> (for example e2-standard-4 = E2 family, standard type, 4 vCPUs). The type sub-categories control the memory-to-vCPU ratio:

Type keyword Memory per vCPU (typical) Example Use for
micro / small / medium Shared-core, fractional e2-micro, e2-small Tiny services, free-tier-eligible workloads
standard ~4 GB n2-standard-8 (8 vCPU, 32 GB) Balanced general workloads
highmem ~8 GB n2-highmem-8 (8 vCPU, 64 GB) Memory-bound: caches, in-memory DBs
highcpu ~1 GB n2-highcpu-16 (16 vCPU, 16 GB) CPU-bound: batch, encoding, compute
custom You choose custom-6-20480 (6 vCPU, 20 GB) Right-size to exact need, avoid waste

The custom machine type is an underused cost lever: if your workload needs 6 vCPUs and 20 GB, you don’t have to round up to a predefined n2-standard-8 (8 vCPU, 32 GB) and pay for unused capacity — you specify exactly --custom-cpu=6 --custom-memory=20GB. For oddly-shaped workloads this routinely saves 15–30%.

Creating and managing a VM

A minimal VM with gcloud:

# Create a general-purpose E2 VM with a Debian image
gcloud compute instances create web-vm-01 \
  --project=my-project \
  --zone=asia-south1-a \
  --machine-type=e2-standard-4 \
  --image-family=debian-12 \
  --image-project=debian-cloud \
  --boot-disk-size=30GB \
  --boot-disk-type=pd-balanced \
  --tags=http-server

The equivalent in Terraform, which is how you should manage anything beyond a throwaway:

resource "google_compute_instance" "web_vm" {
  name         = "web-vm-01"
  project      = "my-project"
  zone         = "asia-south1-a"
  machine_type = "e2-standard-4"
  tags         = ["http-server"]

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-12"
      size  = 30
      type  = "pd-balanced"
    }
  }

  network_interface {
    network = "default"
    access_config {} # ephemeral external IP
  }
}

The boot-disk type is itself a sizing decision — it sets the IOPS and throughput ceiling and a chunk of the cost:

Disk type Performance profile Cost Use for
pd-standard HDD-backed, low IOPS Cheapest Cold/archival, sequential throughput, dev
pd-balanced SSD, balanced IOPS/cost Moderate Most workloads (good default)
pd-ssd SSD, high IOPS Higher Databases, latency-sensitive I/O
pd-extreme / hyperdisk Highest, configurable IOPS Highest Demanding databases, provisioned IOPS
Local SSD Physically attached NVMe, ephemeral Per-disk Scratch space, caches (data lost on stop)

Spot VMs and preemptible VMs: cutting compute cost by up to 91%

A regular Compute Engine VM runs until you stop it, at the standard price. A Spot VM runs on Google’s spare capacity at a steep discount — historically 60–91% off the on-demand price — with one catch: Google can preempt (reclaim) it at any time, with about 30 seconds’ notice, when it needs the capacity back. For the right workloads this is the single biggest cost lever in Compute Engine.

Spot VMs are the current model; preemptible VMs are the older, legacy version with a hard 24-hour maximum lifetime. New workloads should use Spot. The eviction model and what tolerates it:

Property Spot VM Preemptible VM (legacy) Regular (on-demand)
Discount vs on-demand ~60–91% ~60–91% 0% (baseline)
Maximum lifetime No fixed limit (until preempted) 24 hours hard cap Unlimited
Preemption notice ~30 seconds ~30 seconds Never preempted
Can be preempted? Yes, anytime Yes, anytime + forced at 24h No
Best for Fault-tolerant, restartable, batch Same (legacy) Stateful, always-on, latency-critical

The decision of whether a workload can run on Spot comes down to one question: can it survive being killed with 30 seconds’ notice and restarted? If yes, take the discount. If no, don’t.

Workload Spot-safe? Why
Batch data processing (checkpointed) Yes Restart from last checkpoint; minutes lost, not hours
CI/CD build runners Yes A killed build just re-runs
Stateless web tier behind a load balancer (with on-demand baseline) Partly Mix Spot + on-demand; LB drains evicted nodes
ML training with checkpointing Yes Resume from checkpoint; huge savings on long runs
Rendering / encoding farms Yes Per-frame/per-segment work re-queues
Production database No State loss / availability hit unacceptable
Latency-critical user-facing single instance No A 30-second eviction is a user-visible outage

Creating a Spot VM is one flag:

# Spot VM — same as a normal VM plus the provisioning model and termination action
gcloud compute instances create batch-worker-01 \
  --zone=asia-south1-a \
  --machine-type=n2-standard-8 \
  --provisioning-model=SPOT \
  --instance-termination-action=DELETE \
  --image-family=debian-12 --image-project=debian-cloud

To handle the 30-second notice gracefully, your VM should listen for the preemption signal (delivered via the metadata server) and checkpoint or drain. The most powerful pattern is Spot VMs inside a MIG: the group keeps requesting capacity, so preempted instances are automatically recreated when capacity returns, giving you a fleet that’s mostly Spot-priced and self-replenishing.

Managed instance groups and autoscaling: production VMs without the pets

A lone VM is a liability — it can fail and nothing recovers it. A managed instance group (MIG) turns Compute Engine into a production-grade, self-healing, autoscaling platform. You define an instance template (machine type, image, disks, startup script, tags) and the MIG maintains a target number of identical VMs from it, recreating any that die and scaling the count to demand.

The features a MIG layers on raw VMs are exactly what makes serverless attractive — minus the OS abstraction:

MIG feature What it does Why it matters
Instance template Immutable blueprint for every VM in the group Identical, reproducible instances; version your fleet
Autohealing Recreates VMs that fail an application health check Self-healing — a hung app gets replaced automatically
Autoscaling Adds/removes VMs based on CPU, LB utilisation, or custom metrics Match capacity to load; pay for what you use
Regional (multi-zone) MIG Spreads instances across zones in a region Survives a zonal outage
Rolling updates Gradually replaces VMs with a new template Zero/low-downtime deploys, canary, surge control
Load balancer integration MIG is a backend; LB routes to healthy members Front a fleet with one IP, drain on update

Autoscaling policies

The MIG autoscaler decides the instance count. You pick the signal it scales on:

Autoscaling signal Scales on Best for Note
CPU utilisation Average CPU across the group vs a target CPU-bound workloads; simple default Lagging signal; set sensible cooldowns
Load balancer utilisation Serving capacity of the backend HTTP services behind an LB Ties scaling to real request load
Custom / Cloud Monitoring metric Any metric you publish (queue depth, RPS) Queue workers, custom signals Most precise; needs the metric plumbed
Schedule-based Time of day / known events Predictable peaks (business hours) Combine with metric-based for spikes
Min/max replicas Hard floor and ceiling on count Cost control + capacity guarantee Always set max to bound the bill

A regional MIG with CPU autoscaling, end to end:

# 1. Create an instance template (the blueprint)
gcloud compute instance-templates create web-template-v1 \
  --machine-type=e2-standard-4 \
  --image-family=debian-12 --image-project=debian-cloud \
  --tags=http-server \
  --metadata=startup-script='#! /bin/bash
    apt-get update && apt-get install -y nginx
    systemctl enable --now nginx'

# 2. Create a regional MIG from the template, base size 3
gcloud compute instance-groups managed create web-mig \
  --template=web-template-v1 \
  --size=3 \
  --region=asia-south1

# 3. Add CPU-based autoscaling: 3–10 instances, target 60% CPU
gcloud compute instance-groups managed set-autoscaling web-mig \
  --region=asia-south1 \
  --min-num-replicas=3 \
  --max-num-replicas=10 \
  --target-cpu-utilization=0.60 \
  --cool-down-period=90

# 4. Add autohealing with a health check (recreate unhealthy VMs)
gcloud compute health-checks create http web-hc \
  --port=80 --request-path=/healthz \
  --check-interval=10s --timeout=5s \
  --healthy-threshold=2 --unhealthy-threshold=3

gcloud compute instance-groups managed update web-mig \
  --region=asia-south1 \
  --health-check=web-hc \
  --initial-delay=120

The equivalent Terraform for the template and MIG (the core of a production fleet):

resource "google_compute_instance_template" "web" {
  name_prefix  = "web-template-"
  machine_type = "e2-standard-4"
  tags         = ["http-server"]

  disk {
    source_image = "debian-cloud/debian-12"
    auto_delete  = true
    boot         = true
  }
  network_interface {
    network = "default"
    access_config {}
  }
  lifecycle { create_before_destroy = true }
}

resource "google_compute_region_instance_group_manager" "web" {
  name               = "web-mig"
  region             = "asia-south1"
  base_instance_name = "web"
  version { instance_template = google_compute_instance_template.web.id }

  named_port {
    name = "http"
    port = 80
  }
}

resource "google_compute_region_autoscaler" "web" {
  name   = "web-autoscaler"
  region = "asia-south1"
  target = google_compute_region_instance_group_manager.web.id
  autoscaling_policy {
    min_replicas    = 3
    max_replicas    = 10
    cooldown_period = 90
    cpu_utilization { target = 0.6 }
  }
}

Cloud Run deep dive: serverless containers and the scaling model

Cloud Run is the fastest path from a container image to a production HTTPS endpoint, and for most stateless web services it is the right default on GCP today. You hand it a container that listens on a port; it runs that container, gives it a TLS URL, scales it from zero to many on traffic, and bills you for the CPU and memory time used plus the requests served. No VMs, no clusters, no OS.

Cloud Run comes in two shapes:

Cloud Run resource What it is Triggered by Scales to zero?
Cloud Run service A container serving requests behind an HTTPS URL HTTP requests, events (via Eventarc) Yes (default)
Cloud Run job A container that runs to completion then exits Manual, scheduled (Cloud Scheduler), or pipeline N/A (runs, then stops)

The scaling model: concurrency, instances, and cold starts

Cloud Run’s scaling is governed by two numbers most people misconfigure. Concurrency is how many simultaneous requests a single container instance handles (default 80, max 1000). Instances is how many containers exist. Cloud Run adds instances when existing ones hit their concurrency limit and removes them (down to the minimum) when traffic drops.

Setting What it controls Default Range Tune it when…
Concurrency Simultaneous requests per instance 80 1–1000 CPU-heavy per request → lower; lightweight I/O → raise
Min instances Warm instances kept alive (no scale-to-zero) 0 0–1000 Latency-critical: pay to kill cold starts
Max instances Ceiling on instances 100 1–1000+ Bound cost; protect a fragile downstream
CPU allocation CPU only during requests, or always During requests request-time / always-on Background work / streaming → always-on
Memory RAM per instance 512 MiB 128 MiB–32 GiB Sized to your container’s footprint
CPU vCPU per instance 1 up to 8 Compute-bound requests
Request timeout Max single-request duration 5 min up to 60 min Long-running requests / streaming

The cold start is Cloud Run’s one real tax: when the service is at zero instances (or needs a new one) and a request arrives, Cloud Run must pull the image, start the container, and let it initialise before serving — typically a few hundred milliseconds to a few seconds depending on image size and start-up code. The mitigations:

Cold-start lever Effect Cost impact
Min instances ≥ 1 Keeps N instances always warm — no cold start for steady traffic You pay for the warm instances even when idle
Smaller image Faster pull and start Free (build discipline)
Lighter start-up code Defer heavy init out of the start path Free
CPU boost on start Extra CPU during the first start to speed init Slightly higher (feature-dependent)
Second-generation execution env Faster networking/CPU; trade-off vs gen1 start Same price tier

A real deploy from a container image, with the knobs set:

# Deploy a container to Cloud Run with tuned concurrency, scaling and resources
gcloud run deploy orders-api \
  --image=asia-south1-docker.pkg.dev/my-project/apps/orders-api:1.4.2 \
  --region=asia-south1 \
  --platform=managed \
  --concurrency=80 \
  --min-instances=1 \
  --max-instances=20 \
  --cpu=1 --memory=512Mi \
  --timeout=120 \
  --allow-unauthenticated \
  --service-account=orders-api@my-project.iam.gserviceaccount.com

In Terraform, the modern Cloud Run v2 resource:

resource "google_cloud_run_v2_service" "orders_api" {
  name     = "orders-api"
  location = "asia-south1"

  template {
    service_account = "orders-api@my-project.iam.gserviceaccount.com"
    scaling {
      min_instance_count = 1
      max_instance_count = 20
    }
    max_instance_request_concurrency = 80
    timeout                          = "120s"

    containers {
      image = "asia-south1-docker.pkg.dev/my-project/apps/orders-api:1.4.2"
      resources {
        limits = {
          cpu    = "1"
          memory = "512Mi"
        }
      }
    }
  }
}

Cloud Run’s deeper mechanics — revisions, traffic splitting, gradual rollouts, and concurrency tuning — are covered in Cloud Run Explained: Serverless Containers That Scale to Zero (and Back) Without Kubernetes.

GKE deep dive: when you actually need Kubernetes

Google Kubernetes Engine runs the open-source Kubernetes orchestrator as a managed service: Google operates the control plane (API server, scheduler, etcd) and you run workloads as pods on nodes (Compute Engine VMs underneath). GKE is powerful and the right answer for a specific shape of problem — but it carries the highest day-to-day operational burden here, and the most common GKE mistake is adopting it for workloads Cloud Run would have served with a fraction of the effort.

Reach for GKE when you have Kubernetes-shaped problems, not because Kubernetes is prestigious:

You genuinely need GKE when… Why Cloud Run / others fall short
You run many interdependent services with complex networking Cloud Run is per-service; service mesh and pod-to-pod policy live in K8s
You need advanced scheduling (affinity, taints, bin-packing, GPUs shared across pods) Serverless gives you little scheduling control
You depend on the Kubernetes ecosystem (operators, Helm, CRDs, Istio, Argo) That ecosystem assumes a K8s API to talk to
You need stateful workloads with ordered, stable identity (StatefulSets, PVs) Serverless is stateless by design
You want portability across clouds/on-prem on one orchestration API Cloud Run is GCP-specific
You run a platform for other teams and need fine-grained multi-tenancy A cluster gives you namespaces, quotas, RBAC

GKE itself offers modes that re-run the control-vs-abstraction trade-off within Kubernetes:

GKE mode You manage Google manages Billing Best for
Standard Node pools, node config, scaling tuning, upgrades Control plane, node auto-repair/upgrade options Nodes (VMs) + control-plane fee Teams who need node-level control
Autopilot Workloads only (pods, requests/limits) Nodes, scaling, node security, provisioning Per-pod vCPU/memory/storage requested Teams who want K8s without node ops

A minimal Autopilot cluster (the lower-toil default for most new GKE users):

# Autopilot cluster — Google manages nodes; you just deploy workloads
gcloud container clusters create-auto my-cluster \
  --region=asia-south1 \
  --project=my-project

# Get credentials, then deploy a workload
gcloud container clusters get-credentials my-cluster --region=asia-south1
kubectl create deployment web --image=asia-south1-docker.pkg.dev/my-project/apps/web:1.0
kubectl scale deployment web --replicas=3
kubectl expose deployment web --type=LoadBalancer --port=80

The choice between Autopilot, Standard and Enterprise — and whether you should be on GKE at all — is the entire subject of GKE Autopilot vs Standard vs Enterprise: Choose Your Kubernetes Mode and GKE Autopilot vs Standard: Which Google Kubernetes Engine Mode Should You Actually Use?.

Cloud Functions and App Engine: the event-handlers and the original PaaS

Cloud Functions is the highest-abstraction compute on GCP: you write a single function, declare its trigger, and Google handles everything else — build, runtime, scaling to zero and back. It exists for glue: respond to a Pub/Sub message, react to a Storage upload, handle an HTTP webhook, run a lightweight scheduled task. It is the wrong tool for anything long-running or heavy.

Cloud Functions has two generations, and the difference matters:

Aspect 1st gen 2nd gen (on Cloud Run + Eventarc)
Max execution time 9 minutes 60 minutes
Concurrency per instance 1 up to 1000 (configurable)
Max memory 8 GB 32 GB
Underlying platform Functions infra Cloud Run + Eventarc
Triggers HTTP, limited events HTTP + broad Eventarc events
Recommendation Legacy/simple Preferred for new functions

The trigger model is the point of Cloud Functions — the function fires because something happened:

Trigger type Fires when… Typical use
HTTP An HTTP request hits the function URL Webhooks, lightweight APIs
Pub/Sub A message is published to a topic Async processing, fan-out
Cloud Storage An object is created/deleted/updated Image thumbnailing, file processing
Firestore / Firebase A document changes Reactive backend logic
Eventarc (2nd gen) Any of 90+ GCP event sources fires Broad event-driven integrations
Cloud Scheduler A cron schedule triggers (via HTTP/Pub-Sub) Periodic jobs

A Pub/Sub-triggered function deployed with gcloud:

# 2nd-gen function triggered by messages on a Pub/Sub topic
gcloud functions deploy process-order \
  --gen2 \
  --region=asia-south1 \
  --runtime=python312 \
  --source=. \
  --entry-point=process_order \
  --trigger-topic=orders \
  --memory=512Mi \
  --timeout=120s

App Engine is GCP’s original platform-as-a-service, predating Cloud Run by years. You deploy app code with an app.yaml, and the platform runs it — handling scaling, patching and the runtime. It comes in two environments with very different characters:

App Engine environment What runs Scale-to-zero? Customisation Best for
Standard Your code in a Google-managed sandbox (supported runtimes) Yes Limited (sandbox constraints) Web apps in supported languages, spiky traffic, cost-sensitive
Flexible Your container on managed Compute Engine VMs No (min 1 instance) More (custom runtime, libraries) Apps needing custom runtimes / longer requests

App Engine’s distinctive features are versions (deploy multiple versions of a service and keep them addressable) and traffic splitting (route a percentage of traffic to a version for canaries and A/B tests), configured via app.yaml:

# app.yaml — App Engine Standard, Python, with automatic scaling
runtime: python312
instance_class: F2
automatic_scaling:
  min_instances: 0
  max_instances: 10
  target_cpu_utilization: 0.6
# Deploy and split traffic 90/10 between versions for a canary
gcloud app deploy --version=v2 --no-promote
gcloud app services set-traffic default --splits=v1=0.9,v2=0.1

The honest guidance in 2026: for new workloads, prefer Cloud Run over App Engine Flexible (same job, with scale-to-zero and per-use billing) and Cloud Run or Cloud Functions over App Engine Standard. App Engine remains a solid home for existing apps and teams who specifically want its versioning/traffic-splitting model and app.yaml simplicity.

Architecture at a glance

The first diagram lays the five services out side by side along the control-versus-abstraction axis so you can see the spectrum rather than memorise it. On the far left, Compute Engine is a stack of VM nodes with machine-type labels (E2, N2, C3), a boot disk, the OS you own, and a MIG wrapper showing autohealing and autoscaling — the control anchor. Moving right, GKE is a cluster: a Google-managed control plane up top and your node pools (Compute Engine VMs) running pods below, with Autopilot and Standard called out. Further right, App Engine shows the Standard sandbox and Flexible VM environments behind an app.yaml. Then Cloud Run — a container behind an HTTPS URL with the scale-to-zero arrow and the concurrency/instances knobs. On the far right, Cloud Functions is a single function box wired to its triggers (HTTP, Pub/Sub, Storage). Across the bottom runs the axis arrow — more control / more toil left, more abstraction / less toil right — with scale-to-zero flagged on every service that has it.

Compute Engine, GKE, App Engine, Cloud Run and Cloud Functions arranged along the control-versus-abstraction axis, each labelled with its unit of deployment, scaling model and scale-to-zero capability

The second diagram turns that spectrum into a decision flow — the questions, in order, that route a workload to its service. Starting from the workload: Is it event-driven and short? → Cloud Functions. Does it need OS control, GPUs, specific licenses or long-lived state? → Compute Engine (branching to a MIG for a fleet). Do you have Kubernetes-shaped problems — many services, complex scheduling, the K8s ecosystem? → GKE (Autopilot vs Standard). Is it a stateless container or job that should scale to zero and deploy fast? → Cloud Run. Do you want a managed runtime and accept the platform’s opinions? → App Engine. Each terminal node carries the one-line reason it won, so the diagram doubles as a justification you can show a teammate.

Decision flow for choosing a GCP compute service, branching on statefulness, runtime length, OS control needs, Kubernetes requirements and scale-to-zero, terminating in Compute Engine, GKE, App Engine, Cloud Run or Cloud Functions

Real-world scenario: the retail platform’s compute map

Return to the retail company from the opening. NovaCart (a fictional but realistic mid-size online retailer) ran on a single answer — Compute Engine — for everything: a 40-VM fleet hand-managed across two zones, costing roughly ₹6.2 lakh/month in compute, with one full-time engineer dedicated to patching, imaging and babysitting autoscaling scripts they’d written themselves. Black Friday exposed the cracks: their hand-rolled autoscaler reacted too slowly, the checkout API fell over under a 5× spike, and the post-mortem made it clear the team was spending 70% of its infrastructure time on keeping VMs alive rather than shipping.

The architect ran every workload through the decision flow and re-homed them:

Workload Old home New home Why it moved Result
Public product & checkout APIs (stateless HTTP, spiky) Compute Engine fleet Cloud Run (min-instances=2, max=50, concurrency=80) Stateless, scale-to-zero overnight, instant scale-out on spikes Deploy time hours → 2 min; 60% cheaper at this tier; survived a 7× spike without paging
Recommendation service (many micro-services, custom autoscalers, A/B routing) Compute Engine GKE Autopilot Genuinely K8s-shaped: a mesh of services, complex scheduling, ecosystem tools Node ops gone; pay per pod; team kept their K8s tooling
Image processing on upload (thumbnails, format conversion) Compute Engine cron VMs Cloud Functions (2nd gen), Storage-triggered Event-driven, short-lived, embarrassingly parallel VMs decommissioned; pay per invocation; scales with upload rate automatically
Nightly inventory reconciliation (45-min batch, restartable) Compute Engine Cloud Run job on a schedule Containerised batch, runs then exits, no always-on VM needed No idle VM overnight; runs only when scheduled
ML ranking-model training (GPUs, custom CUDA drivers, 200 GB scratch) Compute Engine Compute Engine (A2 GPU VMs, Spot, in a MIG) Needs specific GPUs + drivers + local SSD; nothing serverless offers this Stayed put, but moved to Spot → ~70% cheaper for the training runs
Internal admin portal (low traffic, Python web app) Compute Engine App Engine Standard Managed runtime, scales to zero, the team already knew app.yaml One always-on VM eliminated; near-zero cost when idle

The outcome after three months: compute spend dropped from ₹6.2 lakh to about ₹2.7 lakh/month (a 56% cut), the dedicated VM-babysitting role moved to feature work, and the next Black Friday autoscaled cleanly because Cloud Run and Autopilot handle scale-out far faster than the old scripts. The thesis of this article, learned the hard way: there is no single right compute service — there is a right service per workload, and the cost of defaulting to one is paid in money and toil. Note the answer was not “abandon Compute Engine” — the GPU training stayed there because it genuinely needs the control. The dial was simply turned as far toward abstraction as each workload allowed.

Advantages and disadvantages

Each service is a sharp tool. The trade-offs, side by side:

Service Advantages Disadvantages
Compute Engine Maximum flexibility (any OS/software, GPUs, custom hardware, licenses); lowest unit compute cost at steady high utilisation (with CUDs); full state/persistent disk; no cold starts; Spot for up-to-91% savings Highest operational burden (patching, imaging, scaling glue, hardening); no scale-to-zero (idle VMs cost money); you own availability and autoscaling design
GKE Full container orchestration and scheduling; rich ecosystem (Helm, operators, mesh); portability across clouds; stateful workloads; multi-tenancy for platforms Steepest learning curve; highest day-to-day complexity (Standard); control-plane fee; easy to over-adopt for workloads Cloud Run would serve
App Engine Fully managed runtime; fast scaling and (Standard) scale-to-zero; built-in versions + traffic splitting; very low ops Platform opinions and sandbox constraints (Standard); Flexible has no scale-to-zero; largely superseded by Cloud Run for new work
Cloud Run Any container, scale-to-zero, HTTPS in minutes, per-use billing, near-zero ops, jobs + services; fast deploys and traffic splitting Stateless only (no local persistent state); cold starts (mitigable); not for processes that must always run a background loop without a request
Cloud Functions Lowest possible ops; event triggers built in; scale-to-zero; ideal glue Tight time/memory limits (esp. 1st gen); stateless; per-invocation pricing can add up at very high volume; easy to outgrow

The meta-point: advantages on the left of the spectrum (control, flexibility) are exactly the disadvantages on the right (you’d have to give them up), and vice versa. The “best” service is the one whose advantages you need and whose disadvantages your workload can tolerate.

Hands-on lab: deploy the same app three ways and compare

This lab deploys a trivial containerised web service three ways — Compute Engine (in a MIG), Cloud Run, and Cloud Functions — so you feel the difference in effort, deploy time, and scaling directly. It is free-tier-friendly if you tear everything down promptly. Set your project and region first.

Step 0 — Set up.

gcloud config set project my-project
gcloud config set compute/region asia-south1
export REGION=asia-south1
export ZONE=asia-south1-a
# Enable the APIs you'll touch
gcloud services enable compute.googleapis.com run.googleapis.com \
  cloudfunctions.googleapis.com cloudbuild.googleapis.com

Step 1 — Compute Engine path (a MIG behind autoscaling). Create a template, a MIG, and autoscaling.

gcloud compute instance-templates create lab-tpl \
  --machine-type=e2-small --image-family=debian-12 --image-project=debian-cloud \
  --tags=http-server \
  --metadata=startup-script='#! /bin/bash
    apt-get update && apt-get install -y nginx
    echo "hello from $(hostname)" > /var/www/html/index.html'

gcloud compute instance-groups managed create lab-mig \
  --template=lab-tpl --size=2 --zone=$ZONE

gcloud compute instance-groups managed set-autoscaling lab-mig \
  --zone=$ZONE --min-num-replicas=2 --max-num-replicas=5 --target-cpu-utilization=0.6

Expected: gcloud compute instance-groups managed list-instances lab-mig --zone=$ZONE shows two RUNNING instances after a minute or two. Note the effort: a template, a group, an autoscaler, a firewall rule for port 80, and you still own the OS.

Step 2 — Cloud Run path (the same idea, far less effort). Deploy a public container image (using a sample hello image to skip the build).

gcloud run deploy lab-run \
  --image=us-docker.pkg.dev/cloudrun/container/hello \
  --region=$REGION --allow-unauthenticated \
  --min-instances=0 --max-instances=5 --concurrency=80

Expected: the command prints a Service URL in under a minute. curl it and you get a response. No VM, no OS, scales to zero automatically.

RUN_URL=$(gcloud run services describe lab-run --region=$REGION --format='value(status.url)')
curl -s "$RUN_URL" | head -n 3

Step 3 — Cloud Functions path (an HTTP snippet). Create a tiny function locally and deploy it.

mkdir -p lab-fn && cd lab-fn
cat > main.py <<'PY'
import functions_framework

@functions_framework.http
def hello(request):
    return "hello from a cloud function\n"
PY
cat > requirements.txt <<'TXT'
functions-framework==3.*
TXT

gcloud functions deploy lab-hello --gen2 --region=$REGION \
  --runtime=python312 --source=. --entry-point=hello \
  --trigger-http --allow-unauthenticated
cd ..

Expected: after the build completes, a trigger URL is printed; curl it to get the greeting. You wrote five lines of code and zero infrastructure.

Step 4 — Validate and compare. Note three things you just observed: (a) deploy effort and time grew dramatically from Functions → Cloud Run → Compute Engine; (b) only Compute Engine left you owning an OS; © the MIG keeps two VMs running (and billing) even with no traffic, whereas Cloud Run and Functions sit at zero. That is the spectrum, felt directly.

Step 5 — Teardown (do this to avoid charges).

# Cloud Functions
gcloud functions delete lab-hello --gen2 --region=$REGION --quiet
# Cloud Run
gcloud run services delete lab-run --region=$REGION --quiet
# Compute Engine MIG + template
gcloud compute instance-groups managed delete lab-mig --zone=$ZONE --quiet
gcloud compute instance-templates delete lab-tpl --quiet

Confirm nothing lingers: gcloud compute instances list, gcloud run services list, and gcloud functions list should show no lab resources.

Common mistakes & troubleshooting

The failure modes here are mostly decision failures and a handful of operational gotchas. Symptom → root cause → how to confirm → fix:

# Symptom Root cause How to confirm Fix
1 Compute bill is far higher than expected for simple web apps Stateless services running on always-on VMs instead of scale-to-zero serverless gcloud compute instances list shows many low-utilisation VMs; check CPU metrics Move stateless HTTP services to Cloud Run; let them scale to zero
2 Team spends most of its time patching/imaging VMs Over-rotation on Compute Engine; everything defaulted to VMs Headcount audit: who does infra toil vs features Re-home VM-shaped-only workloads; push the rest right on the spectrum
3 Adopted GKE, now drowning in cluster ops for 3 services Kubernetes adopted without K8s-shaped problems or a platform team Count services and the ops hours the cluster consumes For few stateless services, Cloud Run is far less toil; reserve GKE for real K8s needs
4 Cloud Run service has slow first requests after idle Cold start at zero instances Latency spikes after gaps; logs show new instance starts Set --min-instances=1+; shrink image; defer heavy start-up init
5 Cloud Functions job keeps timing out Workload exceeds the function time limit (9 min gen1 / 60 min gen2) Logs show timeout at the ceiling Use Cloud Run jobs or Compute Engine for long batch; or move to gen2
6 Spot VMs keep disappearing and work is lost Preemption with no checkpointing / no MIG to recreate Operations logs show PREEMPTED; instances vanish Checkpoint work; run Spot in a MIG so capacity self-replenishes; keep an on-demand baseline
7 MIG isn’t scaling under load No/incorrect autoscaler, or wrong signal (CPU vs LB) gcloud compute instance-groups managed describe shows autoscaler config Attach autoscaler with the right signal; set sensible min/max and cooldown
8 VMs in a MIG flap (recreated repeatedly) Autohealing health check too aggressive or app slow to start Check --initial-delay vs real start time; health-check thresholds Raise --initial-delay; loosen thresholds; fix slow start-up
9 Cloud Run instance count explodes, bill spikes Concurrency set too low (1 instance per request) Service config shows low concurrency; instance count high Raise concurrency for I/O-bound services; cap with --max-instances
10 App Engine Flexible costs money even at zero traffic Flexible has a minimum of 1 instance (no scale-to-zero) gcloud app instances list shows ≥1 always Move to App Engine Standard or Cloud Run for scale-to-zero
11 Custom container won’t serve on Cloud Run Container doesn’t listen on $PORT / binds 127.0.0.1 Logs show no requests served; container started Listen on the injected $PORT env var; bind 0.0.0.0
12 Picked the wrong machine family; performance poor or wasteful General-purpose type for a memory- or compute-bound job Compare workload profile to family; check CPU/mem utilisation Move to highmem/highcpu/compute-optimised; consider a custom machine type

Best practices

Security notes

Compute security is mostly about identity, least privilege, network isolation, and patching — and the right rung of the spectrum changes who owns each.

Cost & sizing

What drives the bill is fundamentally different per service, and understanding the billing unit is how you right-size:

Service Primary cost drivers Discount levers Scales to zero (no idle cost)?
Compute Engine vCPU + memory per second (1-min min), disk, network egress, GPUs Sustained-use (automatic), committed-use (1/3-yr), Spot (up to ~91%), custom machine types No — running VMs bill continuously
GKE Standard Node VMs (as Compute Engine) + per-cluster management fee Node CUDs/Spot, right-sized node pools, autoscaling, free zonal cluster tiers Nodes can scale down; control-plane fee persists
GKE Autopilot Per-pod vCPU/memory/storage requested, + cluster fee Right-size pod requests; no paying for unused node headroom Pods can scale to zero; cluster fee persists
App Engine Standard: instance-hours by class; Flexible: underlying VM-hours Standard scale-to-zero; right instance class Standard: yes; Flexible: no (min 1)
Cloud Run Requests + CPU-time + memory-time while serving (per 100 ms), egress Scale-to-zero; tune concurrency; CPU only during requests Yes (at min-instances=0)
Cloud Functions Invocations + CPU/memory time + egress Scale-to-zero; right-size memory (memory also sets CPU) Yes

Three sizing rules that decide most cost outcomes:

Rough order-of-magnitude figures (vary by region; relative, not a quote): a small always-on e2-small VM runs on the order of ₹1,000–1,500/month; the same low-traffic workload on Cloud Run with scale-to-zero can be under ₹100/month; a GKE Autopilot cluster carries a control-plane fee of a few thousand rupees/month before any workloads — which is why a single small service rarely justifies a cluster. Model your real request volume and utilisation in the GCP Pricing Calculator before committing.

Interview & exam questions

These map to the Google Cloud Associate Cloud Engineer and Professional Cloud Architect exams and to real architecture interviews.

  1. Q: Place GCP’s compute services on the control-vs-abstraction axis and explain the trade-off. A: From most control to most abstraction: Compute Engine → GKE → App Engine → Cloud Run → Cloud Functions. Moving toward abstraction trades configurability and control (OS access, scheduling, custom hardware) for the elimination of operational toil (patching, scaling, imaging). You choose the right-most service the workload’s requirements allow.

  2. Q: A stateless HTTP API with spiky traffic and a containerised build — which service and why? A: Cloud Run. It runs any container, scales to zero (cheap when idle), scales out fast on spikes, gives an HTTPS URL in minutes, and bills per use — a perfect match for stateless spiky HTTP.

  3. Q: When is GKE the right choice over Cloud Run? A: When you have Kubernetes-shaped problems: many interdependent services, advanced scheduling (affinity/taints/GPU sharing), dependence on the K8s ecosystem (Helm, operators, mesh), stateful workloads (StatefulSets), multi-cloud portability, or running a platform for other teams. Not merely because Kubernetes is familiar.

  4. Q: What are Spot VMs and which workloads suit them? A: VMs on spare capacity at up to ~91% discount that Google can preempt with ~30 seconds’ notice. They suit fault-tolerant, restartable work — batch, CI runners, checkpointed ML training, render farms — ideally inside a MIG so preempted capacity is recreated. Not for stateful or latency-critical single instances.

  5. Q: What does a managed instance group give you over a single VM? A: Autohealing (recreate VMs failing a health check), autoscaling (CPU/LB/metric-driven count), regional spread across zones for resilience, rolling updates from a versioned instance template, and load-balancer integration — turning raw VMs into a self-healing, autoscaling fleet.

  6. Q: Explain Cloud Run concurrency and its cost/latency effect. A: Concurrency is the number of simultaneous requests one instance handles (default 80). Higher concurrency means fewer instances for I/O-bound traffic (cheaper) but risks CPU contention for compute-heavy requests; lower concurrency isolates heavy requests but spawns more instances (costlier). Tune to the workload’s CPU profile.

  7. Q: What is a cold start and how do you mitigate it on Cloud Run? A: The latency the first request pays when an instance must be started (image pull, container start, init) from zero. Mitigate with min-instances ≥ 1 (warm instances), smaller images, lighter start-up code, and startup CPU boost. Min-instances trades idle cost for predictable latency.

  8. Q: Cloud Functions 1st gen vs 2nd gen — key differences? A: 2nd gen runs on Cloud Run + Eventarc, supporting up to 60-minute execution (vs 9), high configurable concurrency (vs 1), up to 32 GB memory, and far broader event triggers. 2nd gen is preferred for new functions.

  9. Q: Why might a steady, high-CPU 24/7 service be cheaper on Compute Engine than Cloud Run? A: Serverless per-request pricing assumes you benefit from scale-to-zero. A workload pinned at high utilisation never scales to zero, so a committed-use (or even on-demand) VM can be cheaper than paying per-request/CPU-time for capacity you use constantly. Model both at real utilisation.

  10. Q: Choose a machine family for (a) an in-memory cache, (b) CPU-bound video encoding, © a balanced web tier. A: (a) Memory-optimised (M-series) or highmem — high memory per vCPU; (b) Compute-optimised (C3/C4) or highcpu — high per-core performance; © General-purpose (E2/N2) standard — balanced price/performance.

  11. Q: App Engine Standard vs Flexible — when each? A: Standard runs your code in a managed sandbox, scales to zero, and scales fast — best for supported-runtime web apps with spiky traffic and cost sensitivity. Flexible runs your container on managed VMs with more customisation but a 1-instance minimum (no scale-to-zero) — for custom runtimes/longer requests. For new container work, Cloud Run usually beats Flexible.

  12. Q: A 45-minute nightly batch job, containerised and restartable — where does it run? A: A Cloud Run job on a schedule (runs to completion then exits, no idle VM), a GKE Job, or a Spot Compute Engine VM in a MIG. Not an always-on VM (wasteful overnight), and a Cloud Run job is cleaner than pushing a 45-minute job near the Cloud Functions ceiling.

Quick check

  1. Which two GCP compute services sit at the extreme abstraction end of the spectrum, and which sits at the extreme control end?
  2. Name three workload characteristics that push a decision toward Compute Engine rather than Cloud Run.
  3. What is the maximum discount range for Spot VMs, and what is the catch?
  4. What does a MIG add to a raw set of VMs (name three things)?
  5. On Cloud Run, what setting eliminates cold starts for steady traffic, and what does it cost you?

Answers

  1. Cloud Functions and Cloud Run sit at the abstraction end; Compute Engine sits at the control end (with GKE and App Engine in between).
  2. Any three of: needs OS-level / kernel access; needs specific GPUs/TPUs or custom drivers; needs a specific OS license; holds long-lived state on local disk; runs an always-on process or a very long batch job; needs a custom CPU platform or local SSD.
  3. Roughly 60–91% off on-demand; the catch is that Google can preempt the VM at any time with about 30 seconds’ notice (and legacy preemptible VMs also have a 24-hour hard cap), so the workload must be fault-tolerant and restartable.
  4. Any three of: autohealing (recreate failed VMs), autoscaling (CPU/LB/metric-based count), regional multi-zone spread for resilience, rolling updates from a versioned instance template, and load-balancer backend integration.
  5. Min instances ≥ 1 keeps warm instances so steady traffic never hits a cold start; the cost is that you pay for those warm instances even when idle (you lose scale-to-zero for that floor).

Glossary

Next steps

GCPCompute EngineCloud RunGKECloud FunctionsApp EngineServerlessAutoscaling
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading