GCP Fundamentals

GCP for Azure Engineers: How Every Azure Service Maps to Google Cloud

You already know how to ship on Azure. You can size an App Service plan in your sleep, you know why a VNet peering costs money, and you can spot a missing WEBSITES_PORT from across the room. Now someone hands you a Google Cloud project and says “ship the same thing here.” The instinct is to learn GCP from scratch — but that throws away 90% of what you already know. Every cloud solves the same handful of problems: run code, store bytes, route packets, prove identity, move events, crunch data. The names change; the shapes mostly don’t. This article is the dictionary that maps what you know to what you’re about to use, so you can be productive on Google Cloud Platform (GCP) in an afternoon instead of a quarter.

Here’s the mental model to hold the whole time: Azure and GCP are two cities that grew up speaking different languages but built the same buildings. Both have a “place to run a web app,” a “warehouse for cold files,” a “post office for messages,” and a “town hall that checks your ID.” When you move, you don’t relearn what a post office is — you learn it’s now called Pub/Sub, it’s around a different corner, and it stamps your mail slightly differently. Most of this guide is that street map. The smaller, more important part is the four places where the cities are genuinely laid out differently — identity, networking, resource scope, and billing — because those are where Azure muscle memory quietly misleads you. Get the map and those four differences, and the rest is vocabulary.

By the end you’ll have a service-by-service translation grid to keep open during a build, a clear picture of the four concepts that flip between the clouds, a worked example porting a real three-tier app from Azure to GCP, and copy-pasteable gcloud and Terraform. You’ll still need the deep dives to master any one service — this guide links to them — but you’ll know exactly which service to reach for, every time.

What problem this solves

The pain is concrete and expensive: a competent Azure engineer drops onto a GCP project and loses two weeks not because GCP is hard, but because they’re searching for the wrong words. They look for a “resource group” and find no match (GCP splits that idea into project, folder, and labels). They try to size a “plan” before deploying a container and can’t find the knob (Cloud Run has none — it bills per request). They wire up cross-region VNet peering and feel clever, not realizing a GCP VPC was already global and the peering was pointless. None of this is difficulty — it’s a missing translation layer, and every hour building it by trial-and-error is an hour not shipping.

What breaks without this map: cost surprises (you provision GCP like Azure and pay for idle capacity Cloud Run would have scaled to zero), security mistakes (a broad role granted at the wrong level of the hierarchy), and architecture that fights the platform (replicating Azure’s regional-VNet mesh the global VPC made unnecessary). The teams that struggle aren’t the ones who don’t know GCP — they’re the ones who know Azure so well they assume GCP works the same way and get bitten by the four places it doesn’t.

Who hits this: Azure-first engineers joining a multi-cloud shop, architects scoping a migration or a second cloud for resilience, and anyone holding an Azure cert studying for a GCP one who wants to map new facts onto an existing scaffold. If you’ve ever thought “this must be the GCP version of X” and wished someone would just tell you — this is that someone.

To frame the whole field before we go service-by-service, here are the big-rock domains, the Azure anchor you already know, and the one GCP service that is the “first thing to reach for” in each:

Domain The job to be done Your Azure anchor First GCP service to reach for Biggest “it’s different” surprise
Run a web app/container Host an HTTP service App Service Cloud Run No plan to size; scales to zero; pay per request
Run a cluster Managed Kubernetes AKS GKE (Autopilot) Autopilot bills per pod, not per node
Run a VM Raw compute Virtual Machines Compute Engine Per-second billing; automatic sustained-use discounts
Object storage Cheap bulk file store Blob Storage Cloud Storage One global namespace for bucket names
Relational DB Managed SQL Azure SQL Database Cloud SQL You pick the engine (MySQL/Postgres/SQL Server)
Analytics warehouse Query huge datasets Synapse / Fabric BigQuery Serverless; you pay per TB scanned, not per cluster
Messaging Decouple with events Service Bus Pub/Sub At-least-once by default; global by default
Identity Who can do what Entra ID + RBAC Cloud IAM Roles bind to the resource hierarchy, not the resource
Network Private connectivity VNet VPC One VPC is global; subnets are regional
Observability Logs, metrics, traces Azure Monitor Cloud Monitoring/Logging Logs are queried with a filter language, then routed via sinks

Read that table twice. The left half is recognition (“oh, that’s the thing I already use”); the right-most column is the part that will actually save you. Everything below expands these rows.

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You should be comfortable on Azure: you’ve deployed an App Service or AKS workload, you understand that a subscription contains resource groups which contain resources, you know what a service principal and RBAC role assignment are, and you’ve drawn a VNet with subnets. You don’t need to know any GCP yet — that’s the point. Basic familiarity with a terminal and reading JSON/YAML helps, because GCP’s CLI (gcloud) and Terraform are how we’ll make the mapping concrete.

This article sits at the very front of the GCP learning path, as a bridge. It assumes the Azure side and hands you off to GCP fundamentals. The natural next stop after this map is GCP Cloud Fundamentals: Resource Hierarchy & Pricing, which goes deep on the structure we’ll only sketch here, and First Steps with gcloud, Console & Cloud Shell for getting hands-on. Think of this guide as the index page: it points at the right chapter for every topic without trying to be every chapter.

A quick orientation on the two CLIs, because you’ll switch between them and the muscle memory differs in small, annoying ways:

Task Azure CLI gcloud CLI
Log in az login gcloud auth login
Set the working scope az account set --subscription <id> gcloud config set project <id>
List the thing az webapp list gcloud run services list
Create a resource az <svc> create ... gcloud <svc> create ...
Output as JSON --output json (default table) --format=json (default human)
Filter results --query "[?...]" (JMESPath) --filter="..." + --format
Where state lives Subscription (flat) Project (inside a hierarchy)

The biggest adjustment: in Azure your CLI context is a subscription; in GCP it’s a project, living inside a tree of folders and an organization. Set the project first or every command targets the wrong place — the GCP equivalent of forgetting az account set.

Core concepts

Before the service-by-service grid, lock in five mental models. Four of them are the “this is genuinely different” ideas; getting them now means the rest of the article reads as confirmation rather than surprise.

1. The resource hierarchy replaces (and extends) resource groups. Azure’s container tree is shallow: subscription → resource group → resource. GCP’s is deeper: organization → folder(s) → project → resource. The project is the unit you’ll feel most — it’s the billing boundary, the API-enablement boundary, and the default IAM scope, roughly an Azure subscription and a resource group combined. Folders group projects the way management groups do in Azure. Mental model: a GCP project is a sealed workspace with its own walls; Azure resource groups are labelled drawers inside one big room (the subscription). That’s why “what’s the GCP resource group?” has no clean answer — the responsibilities split across project, folder, and labels (free-form key/value tags).

2. Identity binds to the hierarchy, not to the resource. The flip that trips up the most senior Azure people. In Azure RBAC you think “assign this principal the Contributor role on this resource.” In GCP IAM you think “on this project/folder/org, grant this member this role” — the role lands on a node of the hierarchy and flows down to everything beneath it. A service principal becomes a service account; a managed identity becomes a service account attached to the resource. Analogy: Azure RBAC hands out keys to specific rooms; GCP IAM gives a badge that opens a whole wing. You can still scope tightly, but the default unit of thought is the wing (project), not the room. The mechanics live in GCP IAM Fundamentals: Roles, Service Accounts & Policy.

3. The network is global, and the VPC is the surprise. In Azure a VNet is regional — to connect regions you peer VNets and pay for it. In GCP a VPC is global: a single VPC spans every region on Earth, with subnets as the regional pieces inside it. Two VMs in different continents on the same VPC talk over Google’s backbone with private IPs and no peering; firewall rules and routes are VPC-wide. Analogy: an Azure VNet is a building you replicate per city and cable together; a GCP VPC is one global property where every city is already wired into the same private network. This collapses a lot of multi-region plumbing — see Shared VPC & Multi-Project Networking.

4. Billing is consumption-shaped, with automatic discounts. Azure trained you to provision capacity — pick a plan SKU, a VM size, pay whether or not it’s busy. GCP leans into pay for what you use: Cloud Run and Cloud Functions scale to zero and bill per request; BigQuery bills per terabyte scanned; Compute Engine bills per second and automatically applies sustained-use discounts the longer a VM runs, plus deep committed-use discounts if you commit 1 or 3 years. Analogy: Azure plans are like renting an apartment (fixed rent for the space); much of GCP is a metered utility (you pay for the electricity you draw). That’s why “I provisioned it the Azure way” overpays — you bought an apartment when the platform offered a meter.

5. The same six jobs, everywhere. The reassuring one. Underneath the renamed services, both clouds do six things: run code, store objects, run databases, move messages, analyze data, prove identity. Every service below is one of those six jobs wearing a Google name. When you’re lost, ask “which of the six jobs is this?” and the right shelf appears.

The vocabulary, side by side

Pin down the words before the deep grids. This is the fast-lookup card:

Azure term GCP term One-line note on the difference
Subscription Project Project is also the API + billing boundary; sits in a hierarchy
Resource group (no direct match) Split across project, folder, and labels
Management group Folder Groups projects for policy + IAM inheritance
Region Region Same idea; GCP names like us-central1, asia-south1
Availability Zone Zone A zone is us-central1-a; some GCP services are zonal, some regional, some global
Service principal Service account The robot identity your workload runs as
Managed identity Service account (attached) Attach an SA to a VM/Cloud Run service; no secret to manage
RBAC role assignment IAM policy binding Binds member→role on a hierarchy node, inherited downward
ARM/Bicep template Deployment Manager / Terraform Terraform is the de-facto standard on GCP
VNet VPC VPC is global; subnets are regional
NSG VPC firewall rule Rules are VPC-scoped with priorities and tags
Azure Monitor Cloud Monitoring + Logging Logging uses a filter language; route with sinks

Keep this card open for your first week. Half of “learning GCP” is just stopping the reflex to type az.

The service translation grid

This is the dictionary. Each table covers one domain, with the Azure service, its closest GCP equivalent, and — the load-bearing column — where the equivalence leaks, because a translation that pretends two services are identical will hurt you. Use these as comparison grids, not gospel: the “closest match” is a starting point, and the deep dives refine it.

Compute

The richest domain, and where the Azure→GCP instinct is strongest. The key reframe: Azure’s compute is organized around plans and SKUs; GCP’s is organized around how much you want to manage, from fully serverless (Cloud Run) to raw VMs (Compute Engine).

Azure service Closest GCP service What it’s for Where the equivalence leaks
App Service (Web Apps) Cloud Run Push a container/app, get an HTTPS URL Cloud Run has no plan; it scales to zero and bills per request. Closer to “App Service + Container Apps” combined
Azure Container Apps Cloud Run Serverless containers, scale-to-zero Nearly 1:1; Cloud Run is the single answer for both App Service and ACA
Azure Functions Cloud Functions (2nd gen) Event-driven functions 2nd-gen Functions run on Cloud Run under the hood; triggers via Eventarc
AKS GKE Managed Kubernetes GKE Autopilot bills per-pod and manages nodes for you — no node pools to babysit
Virtual Machines Compute Engine Raw VMs Per-second billing; automatic sustained-use discounts; live-migration during host maintenance
VM Scale Sets Managed Instance Groups (MIGs) Autoscaling VM fleets MIGs add regional spread + autohealing as first-class features
Azure Batch Batch / Dataflow Bulk job processing For data pipelines specifically, Dataflow (Apache Beam) is often the better fit

The decision you’ll actually make — “which GCP compute?” — maps cleanly from the Azure decision. Read this as a decision table: find the row that matches what you’d choose on Azure, and the GCP answer is in the third column.

If on Azure you’d reach for… …because you want… On GCP choose…
App Service / Container Apps “Just run my container, no infra” Cloud Run
Azure Functions “Run code on an event, scale to zero” Cloud Functions (2nd gen)
AKS with full control “Kubernetes, my way, node pools and all” GKE Standard
AKS but tired of managing nodes “Kubernetes without babysitting nodes” GKE Autopilot
VMs for a legacy/stateful app “Full OS control, lift-and-shift” Compute Engine
VM Scale Sets “Autoscaling fleet of identical VMs” Managed Instance Groups

The single most useful swap: App Service → Cloud Run. If you’ve sized App Service plans, the new model is “there is no plan.” You deploy a container, set min/max instances, and pay per request plus per-100ms of CPU/memory while a request is in flight. The always-warm worker you bought with a Premium plan + Always On becomes one flag: --min-instances=1. Full picture in Cloud Run vs GKE vs Compute Engine: The Decision and GCP Compute Options Compared.

Storage and databases

Storage translates almost perfectly; databases translate well with one twist (you choose the engine). The reframe: Azure tends to split storage into Blob/File/Queue/Table under one Storage Account; GCP keeps them as separate services, with Cloud Storage owning object storage.

Azure service Closest GCP service What it’s for Where the equivalence leaks
Blob Storage Cloud Storage Object/blob storage Bucket names are globally unique across all of GCP; no “storage account” wrapper
Azure Files Filestore Managed NFS/SMB file shares Filestore is NFS-focused; SMB needs different patterns
Azure SQL Database Cloud SQL (SQL Server / MySQL / Postgres) Managed relational DB You pick the engine; for SQL Server compatibility choose the SQL Server edition
Azure Database for PostgreSQL/MySQL Cloud SQL (Postgres/MySQL) Managed OSS databases Near 1:1
Azure SQL — Hyperscale / huge scale AlloyDB (Postgres) or Spanner High-scale relational Spanner is globally-distributed, horizontally-scalable SQL — no Azure twin
Cosmos DB (NoSQL) Firestore / Bigtable NoSQL document / wide-column Firestore = document (Cosmos Core/Mongo-ish); Bigtable = wide-column (Cosmos Cassandra-ish)
Azure Cache for Redis Memorystore (Redis/Memcached) In-memory cache Near 1:1
Azure Table Storage Bigtable / Firestore Cheap key-value/wide-column Table Storage’s closest spiritual match is Bigtable at scale

Object-storage tiers are where Azure habits transfer cleanly — the names change, the idea doesn’t. Here’s the tier map; treat the right columns as the gotchas to carry over:

Azure blob tier GCP storage class Best for Minimum-storage gotcha (carries over!)
Hot Standard Frequently accessed data None
Cool Nearline Accessed < once/month ~30-day minimum storage duration
Cold Coldline Accessed < once/quarter ~90-day minimum storage duration
Archive Archive Rarely accessed, long-term ~365-day minimum storage duration; retrieval latency

If you’ve ever been billed for early deletion on Azure Cool/Archive, the same trap exists on GCP Nearline/Coldline/Archive — delete before the minimum duration and you pay the full term. The lifecycle-policy pattern is identical in spirit; see Cloud Storage Classes & Lifecycle. For databases, Cloud SQL Deep Dive: Engines, HA, Replicas, Backups covers the engine choice and HA model.

Networking

The domain with the biggest conceptual flip (global VPC) but otherwise a clean map. Reframe: stop thinking “regional network I stitch together” and start thinking “one global network I carve into regional subnets.”

Azure concept GCP concept What it does Where the equivalence leaks
VNet VPC network Private network VPC is global; one VPC spans all regions
Subnet Subnet Address range in a region GCP subnets are explicitly regional; the VPC is not
NSG (Network Security Group) VPC firewall rule Allow/deny traffic Rules are VPC-wide with priorities; target by network tags or service accounts
Route table / UDR Routes Custom routing VPC-scoped; dynamic routes via Cloud Router/BGP
VNet peering VPC Network Peering Connect two VPCs Often unnecessary within one VPC since it’s already global
Azure Load Balancer (L4) Network/Passthrough LB L4 load balancing Regional, passthrough
Application Gateway (L7) Application Load Balancer L7 routing, WAF The Global External ALB is anycast — one IP, served from the nearest edge worldwide
Front Door Global External ALB + Cloud CDN Global entry + CDN Cloud CDN plugs into the global LB
Azure Firewall Cloud NAT + firewall rules / Cloud NGFW Egress control, NAT Cloud NAT gives outbound without public IPs; no SNAT-port babysitting like App Service
ExpressRoute Cloud Interconnect Private on-prem link Near 1:1
VPN Gateway Cloud VPN (HA VPN) Site-to-site VPN HA VPN gives a 99.99% SLA with BGP
Private Endpoint Private Service Connect Private access to PaaS PSC is the producer/consumer model for private service access

The takeaway you’ll keep returning to: on GCP you often don’t need the peering, per-region replication, or global front-end stitching you’d build on Azure — the VPC is global and the External ALB is anycast by default. Detail in Shared VPC & Multi-Project Networking and Cloud Load Balancing Deep Dive.

Identity and security

The flip lives here. Reframe: in Azure you assign roles to resources; in GCP you bind roles to nodes of the hierarchy and they inherit downward.

Azure concept GCP concept What it does Where the equivalence leaks
Entra ID (Azure AD) Cloud Identity / Google Workspace Directory of humans Federation possible; Cloud Identity is the directory backing IAM
Service principal Service account Robot identity for an app The default identity unit for workloads on GCP
Managed identity Service account attached to resource Keyless workload identity Attach an SA to a VM/Cloud Run; no secret to rotate
RBAC role IAM role (basic/predefined/custom) A bundle of permissions Bound to a hierarchy node, inherited down
RBAC role assignment IAM policy binding member → role on a scope Scope = org/folder/project/resource
Key Vault Secret Manager + Cloud KMS Secrets + keys Secret Manager for secrets, Cloud KMS for keys; two services, not one
Azure Policy Organization Policy Guardrails/constraints Org Policy constraints applied at org/folder/project
Defender for Cloud Security Command Center Posture + threat detection SCC is the central security console
Conditional Access IAM Conditions + Access Context Manager Context-aware access Condition expressions + VPC Service Controls perimeters

The mental shift in one sentence: think “what can this member do on this project?” not “who has access to this resource?” Because roles inherit down the tree, a roles/editor grant at the folder level silently applies to every project beneath it — the GCP equivalent of an over-broad assignment at the management-group level. Least-privilege means choosing the right level as much as the right role. Full treatment in IAM Service Accounts & Least Privilege; for keyless CI/CD, Workload Identity Federation for Keyless CI/CD replaces stored service-account JSON.

Data, analytics, messaging and AI

The last grid. Reframe: Azure’s analytics story is consolidating into Fabric/Synapse; GCP’s center of gravity is BigQuery, a serverless warehouse you query without managing a cluster.

Azure service Closest GCP service What it’s for Where the equivalence leaks
Synapse / Microsoft Fabric BigQuery Analytics warehouse Serverless: pay per TB scanned (or reserved slots); no cluster to size
Azure Data Factory Dataflow / Cloud Composer ETL/orchestration Dataflow = Apache Beam streaming+batch; Composer = managed Airflow
Event Hubs Pub/Sub High-throughput ingestion Pub/Sub covers both Event Hubs and Service Bus topic roles
Service Bus Pub/Sub Decoupled messaging Pub/Sub is at-least-once by default; FIFO needs ordering keys/exactly-once
Event Grid Eventarc Event routing to handlers Eventarc routes events into Cloud Run/Functions
Azure Stream Analytics Dataflow Real-time stream processing Beam SQL/pipelines instead of the ASA query language
Azure ML Vertex AI Train/deploy ML models Vertex is the unified ML platform; AutoML + custom + model garden
Azure OpenAI Vertex AI (Gemini, Model Garden) Managed foundation models Gemini family + third-party models via Vertex
Azure Databricks Dataproc / Databricks on GCP Spark/Hadoop Dataproc is managed Spark; Databricks also runs on GCP directly

Two swaps to internalize: Synapse → BigQuery (billing flips from cluster-hours to TB-scanned — see BigQuery: The Analytics Warehouse) and Service Bus → Pub/Sub (the default delivery guarantee changes — Pub/Sub is at-least-once, so FIFO/sessions behavior needs ordering keys or exactly-once turned on; see Pub/Sub: Event-Driven Architecture).

Architecture at a glance

Picture the most ordinary thing you’ve ever built on Azure: a public web app behind Front Door, authenticating users with Entra ID, talking to Azure SQL and Blob Storage, dropping events on Service Bus, with Azure Monitor watching it all. Now re-draw exactly that system on Google Cloud and you get the diagram below — the same shapes, renamed and slightly re-wired. A request comes in through Cloud Load Balancing (your Front Door/App Gateway), carrying an identity proven against Cloud IAM with service accounts (your Entra ID + service principals). It lands on Cloud Run (your App Service), which reads and writes Cloud SQL (Azure SQL) and Cloud Storage (Blob), publishes events to Pub/Sub (Service Bus), and optionally enriches with Vertex AI (Azure ML). Every component streams metrics and logs to Cloud Monitoring and Logging (Azure Monitor), and the whole thing lives inside one global VPC (your VNet, but global).

Walk it left to right and the five numbered markers call out exactly where your Azure intuition needs adjusting — identity flipping inside-out, App Service becoming plan-less Cloud Run, storage tiers renaming but keeping their gotchas, Service Bus’s delivery guarantee changing under Pub/Sub, and the VNet-to-global-VPC jump that deletes a pile of peering. If you can read this one diagram, you can read 80% of GCP architectures — almost every workload is this skeleton with more boxes.

Left-to-right architecture mapping a standard Azure web application onto Google Cloud: an EDGE+IDENTITY zone (Cloud Load Balancing as Front Door, Cloud IAM and service accounts as Entra ID) feeds a COMPUTE zone (Cloud Run as App Service, GKE Autopilot as AKS, Cloud Functions as Functions), which reads and writes a STATE+DATA zone (Cloud SQL as Azure SQL, Cloud Storage as Blob, BigQuery as Synapse) and publishes to an EVENTS+AI zone (Pub/Sub as Service Bus, Vertex AI as Azure ML); all zones stream telemetry to an OPERATE zone (Cloud Monitoring as Azure Monitor, a global VPC as the VNet). Five numbered badges flag the concepts that flip: identity binding to the hierarchy, App Service to plan-less Cloud Run, storage-tier renames, at-least-once Pub/Sub delivery, and the global VPC.

Real-world scenario

NorthStar Retail runs a mid-size e-commerce platform entirely on Azure: an App Service (P1v3 plan, Always On) serving the storefront API, Azure SQL Database for orders, Blob Storage for product images, Service Bus for the order-processing pipeline, Entra ID for staff sign-in, and Azure Monitor for dashboards. After an acquisition, the parent company standardizes on Google Cloud, and Priya — NorthStar’s lead engineer, eight years deep in Azure, zero in GCP — is told to replatform the storefront in a quarter. She starts the way most Azure veterans do: trying to find the GCP “resource group” and the “App Service plan.” She loses three days.

The turning point is when she stops translating word-for-word and applies the six jobs lens plus the four flips. She maps the system in an hour: storefront API → Cloud Run (--min-instances=1 replaces Always On, --max-instances=20 for flash sales); orders DB → Cloud SQL for PostgreSQL (the app’s ORM is portable and Postgres is cheaper at their scale); images → Cloud Storage with a lifecycle rule moving objects older than 90 days to Coldline (she recognizes the minimum-duration gotcha from Azure Cool); order pipeline → Pub/Sub, where flip number four bites — it assumed Service Bus FIFO sessions per customer, so she enables ordering keys on customerId. Staff sign-in federates Entra ID into Cloud Identity, so nobody re-creates accounts. Monitoring moves to Cloud Monitoring with a log sink exporting to BigQuery for the analytics Synapse made expensive.

The flips that bit: (1) Identity — she nearly granted the app’s service account roles/editor at project level out of habit; instead she scoped it to roles/cloudsql.client, roles/storage.objectAdmin on the one bucket, and roles/pubsub.publisher. (2) Networking — she’d budgeted two weeks for cross-region VNet peering for DR; the global VPC made it a non-task. (3) Billing — her first estimate, sized “the Azure way” with always-on capacity, was 40% too high; re-modeling around Cloud Run scale-to-zero for staging and sustained-use discounts brought it well under the Azure bill.

Result: live on GCP in seven weeks, not a quarter. The biggest accelerant wasn’t a GCP feature — it was dropping the literal translation for the map: which of the six jobs, and which of the four flips? The mistake that cost the first three days was assuming GCP was “Azure with different buttons.” Same buildings, different street grid.

Advantages and disadvantages

Approaching GCP through an Azure lens is powerful but has failure modes. The honest trade-off:

Advantages of the translation approach Disadvantages / risks
You reuse years of architecture instinct instead of starting from zero You can over-trust a “closest match” that leaks (e.g. assuming Pub/Sub = Service Bus FIFO)
Faster time-to-productive — days, not a quarter You may carry Azure anti-patterns over (per-region VNet replication that GCP made unnecessary)
Cost optimization is easier once you see GCP bills per-use You might provision “the Azure way” and overpay before the model clicks
Mapping makes certs easier — new facts hang on an existing scaffold Some GCP services (Spanner, BigQuery’s serverless model) have no Azure twin and resist translation
You spot the four flips and avoid the classic mistakes Treating GCP as “Azure with new names” hides the genuinely different bits and bites later

When the translation approach shines: lift-and-shift, multi-cloud parity work, and anything where the GCP service is a near-twin (VMs, VPN, managed Postgres, object storage). When you must stop translating and learn natively: the four flips (identity scope, global networking, hierarchy, billing) and the no-Azure-twin services (Spanner, BigQuery’s pay-per-scan, Autopilot’s per-pod billing). The skill is knowing which mode you’re in.

Hands-on lab

Stand up the GCP side of the translation — a public container app, a managed database, and a bucket — entirely from Cloud Shell, on or near the free tier. This is the “hello world” of the map: App Service → Cloud Run, Azure SQL → Cloud SQL, Blob → Cloud Storage.

1. Set your project (the az account set equivalent).

# Your project is the working scope — set it first, always
gcloud config set project my-demo-project
gcloud config set run/region asia-south1   # pick a region near you

2. Enable the APIs you’ll use. Unlike Azure, GCP requires you to turn services on per project before use:

gcloud services enable run.googleapis.com sqladmin.googleapis.com \
  storage.googleapis.com artifactregistry.googleapis.com

3. Deploy a container to Cloud Run (your App Service). Using a public sample image so there’s nothing to build:

gcloud run deploy storefront \
  --image=us-docker.pkg.dev/cloudrun/container/hello \
  --allow-unauthenticated \
  --min-instances=1 \        # this is your "Always On"
  --max-instances=10 \
  --cpu=1 --memory=512Mi
# Output ends with: Service URL: https://storefront-xxxxx-el.a.run.app

Hit that URL — you have a public HTTPS service with no plan to size. Note the --min-instances=1: that single flag replaces an App Service plan + Always On.

4. Create a managed database (your Azure SQL). Smallest tier, Postgres engine:

gcloud sql instances create orders-db \
  --database-version=POSTGRES_15 \
  --tier=db-f1-micro \          # smallest, cheapest tier
  --region=asia-south1
gcloud sql databases create orders --instance=orders-db

5. Create a bucket (your Blob container) with a lifecycle rule. Bucket names are globally unique — prefix with your project:

gcloud storage buckets create gs://my-demo-project-images \
  --location=asia-south1 \
  --uniform-bucket-level-access
# Add a lifecycle rule: move objects to Coldline after 90 days (the Azure Cool→Cold habit)
cat > /tmp/lifecycle.json <<'EOF'
{ "rule": [
  { "action": {"type":"SetStorageClass","storageClass":"COLDLINE"},
    "condition": {"age":90} }
]}
EOF
gcloud storage buckets update gs://my-demo-project-images --lifecycle-file=/tmp/lifecycle.json

6. The same thing in Terraform (the GCP-native IaC, your Bicep equivalent):

resource "google_cloud_run_v2_service" "storefront" {
  name     = "storefront"
  location = "asia-south1"
  template {
    scaling { min_instance_count = 1, max_instance_count = 10 }
    containers {
      image = "us-docker.pkg.dev/cloudrun/container/hello"
      resources { limits = { cpu = "1", memory = "512Mi" } }
    }
  }
}

resource "google_sql_database_instance" "orders" {
  name             = "orders-db"
  database_version = "POSTGRES_15"
  region           = "asia-south1"
  settings { tier = "db-f1-micro" }
  deletion_protection = false   # demo only
}

resource "google_storage_bucket" "images" {
  name                        = "my-demo-project-images"
  location                    = "asia-south1"
  uniform_bucket_level_access = true
  lifecycle_rule {
    action    { type = "SetStorageClass", storage_class = "COLDLINE" }
    condition { age = 90 }
  }
}

7. Tear it all down (avoid surprise charges — Cloud SQL bills even when idle):

gcloud run services delete storefront --region=asia-south1 --quiet
gcloud sql instances delete orders-db --quiet
gcloud storage rm --recursive gs://my-demo-project-images

You just reproduced an Azure three-tier app’s core on GCP in seven steps. The shapes matched; only the words and a couple of flags changed.

Common mistakes & troubleshooting

The errors Azure engineers make on GCP are remarkably predictable — they almost all come from assuming a flip didn’t happen. Here’s the playbook: symptom, the Azure assumption behind it, how to confirm, and the fix.

# Symptom The Azure assumption behind it How to confirm Fix
1 PERMISSION_DENIED on a brand-new project “The service is just there, like in Azure” gcloud services list --enabled gcloud services enable <api>.googleapis.com — APIs are off by default
2 App can’t reach the DB / bucket despite “having access” “I gave the principal a role, that’s enough” gcloud projects get-iam-policy <proj> Bind the role to the service account, attach the SA to the Cloud Run service
3 Granted a role but it applies way too broadly “Roles scope to the resource” Check the level of the binding in the IAM policy Re-bind at project/resource level, not folder/org — roles inherit down
4 Built VNet peering for a multi-region app; still complex “Networks are regional, peer them” gcloud compute networks describe <vpc> Use one VPC — it’s global; delete the unnecessary peering
5 Bucket creation fails: name already taken “Names are unique within my account” The error: bucket already exists Bucket names are globally unique; prefix with project/org
6 Cloud Run service returns 403 to callers “Public by default like a basic App Service” gcloud run services get-iam-policy <svc> Deploy with --allow-unauthenticated or grant roles/run.invoker
7 Cost is higher than the Azure bill “Provision capacity up front” Billing report → per-SKU breakdown Use scale-to-zero (Cloud Run) for non-prod; let sustained-use discounts apply
8 Pub/Sub messages arrive out of order / twice “Service Bus FIFO + exactly-once is default” Inspect subscription: ordering + delivery settings Enable ordering keys; turn on exactly-once if needed
9 gcloud commands hit the wrong place “The CLI context is my subscription” gcloud config list gcloud config set project <id> — context is the project
10 Cloud SQL still billing after the demo “Stopping the app stops the bill” gcloud sql instances list Delete (or stop) the instance — it bills while it exists
11 Container won’t start on Cloud Run “App Service finds my port for me” Cloud Run logs: “failed to listen on PORT” Listen on $PORT (env var, default 8080); bind 0.0.0.0
12 Org Policy blocks a resource you can create in Azure “Subscriptions don’t constrain me like this” gcloud org-policies list --project=<proj> Check inherited constraints from folder/org; request an exception

The pattern to notice: nearly every row is “I assumed GCP behaves like Azure, and the flip caught me.” Once you internalize the four flips — APIs are opt-in, identity binds to the hierarchy, the network is global, billing is per-use — most of these disappear before you make them. For methodical incident work on GCP, Troubleshooting Methodology: IAM, VPC, Compute, GKE is the structured approach.

Best practices

Crisp rules for an Azure engineer going to production on GCP:

Security notes

The security model is where Azure habits are most dangerous, so be deliberate:

Cost & sizing

The thing that drives the bill on GCP is usage, not provisioned capacity, and that’s the core re-think. Here’s what moves the needle and the rough shape (figures are indicative list prices that vary by region; always confirm in the pricing calculator):

GCP service What you pay for Free-tier / cheap-start angle Azure-habit trap to avoid
Cloud Run Per request + per-100ms CPU/memory while serving Generous monthly free requests; scales to zero Don’t set high --min-instances on non-prod
Compute Engine Per second; sustained + committed-use discounts e2-micro free tier in some regions Don’t ignore committed-use discounts for steady VMs
Cloud SQL Per-hour for the instance (runs even idle) + storage db-f1-micro is cheap, not free Don’t leave demo instances running — they bill 24/7
Cloud Storage Per-GB-month by class + operations + egress 5 GB Standard free/month in some regions Mind the minimum-duration penalties on Nearline/Coldline
BigQuery Per-TB scanned (on-demand) or per-slot (reserved) 1 TB queries + 10 GB storage free/month Don’t SELECT * huge tables — you pay per byte scanned
Pub/Sub Per-GB of message throughput 10 GB/month free Fine-grained; rarely the cost driver early on
Cloud Functions Per invocation + compute time 2M invocations/month free Scales to zero; cheap for spiky workloads

A worked example to make the flip concrete. NorthStar’s three non-prod environments ran on Azure as always-on B1 App Service plans plus small Azure SQL databases — a fixed monthly floor paid 24/7, though developers touch them maybe six hours a day. On GCP the same storefronts moved to Cloud Run with --min-instances=0: outside working hours they scale to zero and cost nothing for compute; during the active hours they cost per-request. The databases stayed (they bill while they exist), but the non-prod compute line dropped close to zero. Combined with sustained-use discounts on the steady production Compute Engine VMs, the all-in monthly bill came in roughly 30–40% under the Azure equivalent — not because GCP is intrinsically cheaper, but because the team stopped paying for idle capacity. On Azure you save by right-sizing the plan; on GCP you save by letting the platform charge only when work happens. Billing & Cost Management Deep Dive covers budgets, exports, and discounts.

Interview & exam questions

Useful for the Azure engineer prepping a GCP certification (Cloud Digital Leader, Associate Cloud Engineer, or a Professional track) where mapping from prior Azure knowledge is the fast path.

1. What is the GCP equivalent of an Azure App Service, and how does the billing model differ? Cloud Run. App Service bills for a provisioned plan (fixed per-hour regardless of traffic); Cloud Run scales to zero and bills per request plus per-100ms of compute while serving. The “Always On” equivalent is --min-instances=1.

2. An Azure resource group has no single GCP equivalent. Explain why. A resource group’s responsibilities are split: the project is the API/billing/IAM boundary (closer to a subscription), folders group projects for policy inheritance (like management groups), and labels provide the free-form tagging. No one GCP object carries all of a resource group’s roles.

3. How does IAM scoping in GCP differ from Azure RBAC? Azure RBAC assigns a role to a principal on a specific resource/RG/subscription. GCP IAM binds a member→role on a node of the resource hierarchy (org/folder/project/resource), and the binding inherits downward to everything beneath it. Least privilege means choosing the right level, not just the right role.

4. Why is GCP networking simpler for multi-region apps than Azure? A GCP VPC is global — one VPC spans all regions, with regional subnets inside it. VMs in different regions on the same VPC communicate privately with no peering. Azure VNets are regional and require peering (and cost) to connect across regions.

5. What replaces an Azure service principal on GCP, and what’s the keyless pattern? A service account. The keyless pattern is to attach the service account to the workload (VM/Cloud Run) so no key file exists, and to use Workload Identity Federation for external/CI-CD identities instead of downloading service-account JSON.

6. Map Azure storage tiers to GCP and name the shared gotcha. Hot→Standard, Cool→Nearline, Cold→Coldline, Archive→Archive. The shared gotcha is minimum storage duration (~30/90/365 days): deleting early still bills for the full minimum term, on both clouds.

7. Service Bus → Pub/Sub: what breaks in a naive port? Pub/Sub is at-least-once by default and not FIFO. Code that relied on Service Bus FIFO sessions or exactly-once must enable ordering keys (for order) and/or exactly-once delivery, or handle duplicates idempotently.

8. What is BigQuery’s analog on Azure, and how does its cost model differ? Synapse/Fabric. BigQuery is serverless: on-demand pricing charges per TB scanned (or per slot-hour if you reserve capacity), with no cluster to provision or pause — versus Synapse’s provisioned/cluster model.

9. Which GCP compute would you pick to replace AKS if your team is tired of managing nodes? GKE Autopilot — it manages nodes for you and bills per running pod rather than per node, removing node-pool sizing while keeping the Kubernetes API.

10. Why might a brand-new GCP project return PERMISSION_DENIED for a service that “just works” on Azure? On GCP, APIs are disabled by default per project; you must gcloud services enable <api> (or declare it in Terraform) before use. There’s no Azure equivalent of this opt-in step at the subscription level.

11. How does Org Policy relate to Azure Policy? Both enforce guardrails. Organization Policy applies constraints (e.g. allowed regions, no public IPs) at org/folder/project, inheriting downward — the structural twin of Azure Policy with management-group-style inheritance.

12. A steady production VM runs 24/7 on Compute Engine. What discount applies automatically, and what can you add? Sustained-use discounts apply automatically the longer the VM runs in a month. You can add committed-use discounts by committing to 1 or 3 years for a larger, predictable saving — analogous to Azure Reserved Instances.

Quick check

  1. What single flag on Cloud Run reproduces an App Service plan’s “Always On” warm worker?
  2. In GCP, does a role bound at the folder level apply to projects beneath it? Why does that matter for least privilege?
  3. Your bucket creation fails with “already exists” even though you’ve never made one with that name. Why?
  4. Which is regional and which is global: a GCP subnet, a GCP VPC?
  5. Name the Azure→GCP messaging swap and the one delivery-guarantee difference to watch.

Answers

  1. --min-instances=1 — it keeps at least one warm instance resident so the first request doesn’t pay a cold start.
  2. Yes — IAM roles inherit downward, so a folder-level grant applies to every project under it. It matters because the wrong level is an over-grant even if the role is correct; least privilege is about the level as much as the role.
  3. Cloud Storage bucket names are globally unique across all of GCP, not per-account. Someone else already owns that name — prefix with your project or org.
  4. A subnet is regional; a VPC is global. One VPC spans every region, and subnets are its regional slices.
  5. Service Bus → Pub/Sub. Pub/Sub is at-least-once by default (and not FIFO), so a naive port can deliver duplicates or out-of-order; use ordering keys and/or exactly-once delivery to match Service Bus FIFO behavior.

Glossary

Next steps

GCPAzureCloud MigrationMulti-cloudCloud RunCloud IAMBigQueryService Translation
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