GCP Fundamentals

gcloud CLI Quickstart: The Essential Commands That Cover 90% of Your Day

Open a terminal, type gcloud, and Google Cloud’s entire surface area is suddenly one command away — every VM, bucket, database, IAM grant and billing report, all reachable without ever opening a browser. That is the promise. The reality, for most newcomers, is a wall: hundreds of subcommands, a sprawling man page, cryptic flags, and an authentication model that fails in ways the error message doesn’t explain. People learn three commands by copy-paste, never understand why they work, and stay slow forever.

This quickstart fixes that. The secret nobody tells you is that gcloud is not hundreds of commands — it’s one predictable sentence pattern with a small, reusable vocabulary. Once you see the pattern (gcloud GROUP SUBGROUP VERB NAME --flags), every command in the tool becomes guessable, and the twenty or so you actually use every day fit on a single screen. We will lock down that mental model first, then walk the daily-driver commands one verb at a time, untangle the auth-and-config setup that causes 90% of “it worked yesterday” tickets, and finish with a hands-on lab where you spin up a real (free-tier) server and tear it down — all from the command line.

By the end you will not be memorising commands; you will be composing them — you will know the difference between gcloud auth login and gcloud auth application-default login (and why mixing them up wastes an afternoon), how named configurations flip you between projects in one keystroke, and how --format and --filter quietly turn gcloud into a data-extraction tool. This is the cheat sheet I wish someone had handed me on day one.

What problem this solves

The Console is wonderful for learning and one-off clicks, but it has a hard ceiling: it is not repeatable, not scriptable, not reviewable. The moment a task happens more than once — create five VMs, grant the same role across ten projects, wire a step into CI — clicking becomes a liability. You cannot diff a click, paste a screenshot into a runbook, or put a mouse movement in version control.

What breaks without CLI fluency is speed and correctness at scale. A Console-only engineer spends ten minutes navigating menus to do what gcloud does in one line, makes inconsistent changes (this VM got the right tag, that one didn’t), and produces nothing anyone can audit. And when they do reach for the CLI under pressure, they hit the authentication wall — “your default credentials were not found,” or a command runs against the wrong project — and retreat to the Console, reinforcing the slowness. It bites everyone who operates GCP beyond a toy project, hardest on people from a pure-Console background, anyone juggling multiple projects (where “wrong project” is a daily hazard), and first-time scripters (where the human-login model silently doesn’t apply). The fix is not “memorise more commands” — it is “understand the four-part sentence, the two logins, and the configuration that pins your context,” after which the commands write themselves. A confident user keeps a tiny, finite set in their head: one command shape, ~6 verbs, ~6 service groups, ~5 global flags, and the two logins — that is genuinely enough to cover the day, with --help filling the rest.

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You need a Google account, a browser, and one Google Cloud project you can treat as a sandbox (with billing enabled — the lab stays inside the Always Free tier, but a billing account must be attached). You do not need any prior command-line experience; every command here is explained and every one of them runs unmodified inside Cloud Shell with nothing installed locally. Comfort with the idea of a “terminal” — a place where you type a command and read text back — is the only soft prerequisite.

This sits at the very start of the hands-on Google Cloud journey. It assumes you grasp the shape of the platform — that resources live inside projects, which live inside the GCP resource hierarchy of organization, folders and projects — and that permissions come through Google Cloud IAM. Everything downstream is operated through the commands you learn here, making this the highest-leverage hour in the curriculum. For the wider tour of every interface (SDK install paths, client libraries, ADC internals), the companion lesson Google Cloud Hands-On First Steps: Console, gcloud CLI, Cloud Shell & SDKs goes broad; this article goes fast and practical — the 90% you reach for daily.

A quick map of where each interface earns its place, so you reach for the right one:

Interface What it is Reach for it when Don’t use it for
Cloud Console The web UI at console.cloud.google.com Exploring a new service, dashboards, billing, one-off changes Anything you’ll do twice; anything that must be auditable
gcloud CLI The command-line tool in the Cloud SDK Fast repeatable changes, scripts, CI, copy-paste runbooks Visual exploration of an unfamiliar service
Cloud Shell A browser terminal with the SDK pre-installed and pre-authenticated Running gcloud with zero install; the lab below Long-running jobs (it idles out) or > 5 GB of files
Terraform / IaC Declarative infra-as-code Reproducible, reviewed, version-controlled infrastructure A quick one-line lookup or ad-hoc fix

Core concepts

Five ideas make the entire tool click. Internalise these and you stop searching Stack Overflow for commands you can simply derive.

A gcloud command is a sentence with a fixed grammar. Every command reads gcloud GROUP [SUBGROUP] VERB [NAME] [--flags]: the group is the service area (compute), an optional subgroup narrows it (compute instances), the verb is the action (create), the name is the resource, and flags supply the details. So gcloud compute instances create web-1 --zone us-central1-a is just “in compute/instances, create one named web-1, in this zone.” The whole tool is this one sentence with different nouns — you don’t memorise it, you speak it.

The same verbs repeat everywhere. GCP services share a common CRUD shape, so the verbs you learn for VMs work almost identically for buckets, IAM and DNS: create makes a thing, list shows many, describe shows one in full, update changes a thing, delete removes it, set configures a property. Learn the six once and only the nouns change after that.

gcloud is self-documenting — --help is a feature, not a fallback. Append --help to any point in a command and gcloud tells you what comes next: gcloud compute --help lists every subgroup, gcloud compute instances create --help every flag. Because the grammar is regular, you drill from “I want to do X” to the exact command without leaving the terminal.

Two completely different “logins” exist, and confusing them is the #1 newcomer trap. gcloud auth login authenticates you, the human, so the gcloud commands you type work. gcloud auth application-default login writes a separate credential file — Application Default Credentials (ADC) — that your code, Terraform and client libraries read. Run the wrong one and you get the maddening “your default credentials were not found” while gcloud itself works perfectly. Two logins, two purposes — keep them straight and a whole class of errors disappears.

Your “active context” is set once, then assumed. Rather than typing --project and --region on every command, gcloud holds an active configuration — a named bundle of properties (account, project, default region/zone) that commands inherit silently. gcloud config set project my-proj pins it; juggling two clients means two configurations you switch with one command. This is what makes “wrong project” mistakes avoidable instead of routine.

The vocabulary in one table

Before the daily commands, pin down every moving part. The glossary at the end repeats these for lookup; this is the mental model side by side:

Term One-line definition Why it matters day to day
Cloud SDK The package that contains gcloud (and gsutil, bq) What you install; what Cloud Shell pre-installs
Component An add-on bundled with the SDK (gke-gcloud-auth-plugin, beta, alpha) Installed with gcloud components install
Group / subgroup The service area in a command (compute, compute instances) The first thing you type; how you find the verb
Verb The action (create, list, describe, delete, update) The same six cover most of your day
Property A stored setting (project, compute/zone, account) Set once; inherited by every command
Configuration A named bundle of properties Switch projects/identities in one command
gcloud auth login Logs in you (the human) for the CLI Makes the commands you type work
ADC (application-default login) Credentials for code / Terraform / libraries Makes your programs authenticate
Impersonation Borrowing a service account’s permissions for one command Run as a robot identity without downloading a key
--format / --filter Reshape and narrow command output Turn gcloud into a scriptable data tool

Anatomy of a gcloud command

Everything starts here. Spend two minutes on this section and the rest of the tool stops being a memory test. A gcloud command has up to five parts, left to right:

gcloud  compute  instances  create  web-1  --zone=us-central1-a --machine-type=e2-micro
#  ^        ^         ^         ^      ^        ^
#  CLI    group   subgroup    verb   name      flags

Read it as plain English: “gcloud — in the compute service, the instances area — create one called web-1, in zone us-central1-a, of machine type e2-micro.” That’s it. Now map each slot to what it does and how you discover its options:

Slot What it is Example values How to discover options
gcloud The CLI itself always gcloud
Group The service area compute, storage, iam, projects, config, dns, run gcloud --help lists all groups
Subgroup A narrower area inside the group instances, disks, firewall-rules, service-accounts gcloud compute --help
Verb The action create, list, describe, update, delete, set, add-iam-policy-binding gcloud compute instances --help
Name The specific resource web-1, my-bucket, [email protected] you choose it (or list to find it)
Flags Per-command details --zone, --machine-type, --format, --project gcloud compute instances create --help

The habit that makes this anatomy pay off: list before you describe, describe before you deletelist finds the exact name, describe confirms it’s the right resource, and only then do you act. That three-step rhythm prevents the most common destructive mistake: deleting the wrong thing because you guessed its name. The next section walks each verb with real commands.

The daily-driver commands, one verb at a time

This is the 90%. Almost every day on Google Cloud is some combination of the six verbs, and the pattern repeats — list/describe/create/delete look nearly identical whether the noun is a VM, a bucket, or an IAM grant. Here they are end to end against one VM, in the order you actually use them:

# list — read-only; your most-typed, safest command. "What do I have?"
gcloud compute instances list

# describe — full config of ONE resource (YAML); confirm before you change
gcloud compute instances describe web-1 --zone=us-central1-a

# create — NAME + flags; anything you omit takes a default (describe to check)
gcloud compute instances create web-1 \
  --zone=us-central1-a --machine-type=e2-micro \
  --image-family=debian-12 --image-project=debian-cloud

# update / set / add-* — change an existing resource
gcloud compute instances add-tags web-1 --zone=us-central1-a --tags=http-server

# delete — prompts for confirmation (suppress with --quiet only when certain)
gcloud compute instances delete web-1 --zone=us-central1-a

The single most useful cross-service verb is add-iam-policy-binding (with its mirror remove-iam-policy-binding), which grants a role on any resource via a rigid --member + --role shape:

gcloud projects add-iam-policy-binding my-project-id \
  --member="user:[email protected]" --role="roles/storage.objectViewer"

Now the payoff: the same verbs across the services you touch most. This single matrix table is most of your job — swap the noun, keep the verb:

Task Compute (compute) Storage (storage) IAM (iam / projects)
List gcloud compute instances list gcloud storage buckets list gcloud iam service-accounts list
Describe one gcloud compute instances describe NAME --zone=Z gcloud storage buckets describe gs://B gcloud iam service-accounts describe SA_EMAIL
Create gcloud compute instances create NAME --zone=Z gcloud storage buckets create gs://B --location=L gcloud iam service-accounts create NAME
Change gcloud compute instances add-tags NAME --tags=T gcloud storage buckets update gs://B --flag gcloud projects add-iam-policy-binding P --member=M --role=R
Delete gcloud compute instances delete NAME --zone=Z gcloud storage rm --recursive gs://B gcloud iam service-accounts delete SA_EMAIL
Connect/act gcloud compute ssh NAME --zone=Z gcloud storage cp FILE gs://B gcloud iam service-accounts keys list ...

And the handful of “everyday” commands outside the CRUD verbs that you will reach for constantly:

Command What it does When you use it
gcloud init Interactive first-time setup (login + project + region) Once per machine / new identity
gcloud config list Show active account, project and region Every time you’re unsure where you are
gcloud auth login Log in your human identity for the CLI When the CLI says you’re not authenticated
gcloud auth application-default login Write ADC for code/Terraform Before running scripts or Terraform locally
gcloud components update Update the SDK and components Every few weeks; when a command is missing
gcloud compute ssh NAME SSH into a VM (handles keys for you) To get a shell on a Compute Engine VM
gcloud info Dump environment, paths and config for debugging When something is mysteriously broken

Authentication and configuration: the setup that trips everyone

This is the section that saves you the most hours. Two distinct mechanisms — who you are and what context you’re in — cause the vast majority of “it worked yesterday” tickets.

The two logins, finally untangled

There are two separate credential stores, for two separate purposes, and they are not interchangeable. gcloud auth login authenticates you, the human typing commands (it’s what gcloud init runs); after it, your terminal’s gcloud commands succeed. gcloud auth application-default login writes a separate Application Default Credentials (ADC) file your programs read — the GCP client libraries, Terraform, any SDK looking for “ambient” credentials. The trap: you run auth login, your gcloud commands work, then a Python script or terraform plan errors with “your default credentials were not found” — the script isn’t broken, it’s looking for ADC you never created. The fix is to also run gcloud auth application-default login. The clean comparison to keep:

Aspect gcloud auth login gcloud auth application-default login
Authenticates You (the human) for the CLI Your code / Terraform / client libraries
Used by gcloud commands you type Programs that call the GCP client libraries
Stored where gcloud’s own credential store An ADC JSON file (e.g. ~/.config/gcloud/application_default_credentials.json)
Symptom if missing gcloud: “you do not currently have an active account” Code: “your default credentials were not found”
You run it when Setting up the CLI on a new machine Before running scripts/Terraform locally

On Cloud Shell and on GCP VMs you usually need neither for basic work — Cloud Shell logs you in automatically, and a VM has an attached service account whose credentials the libraries find on their own. The two-login dance is mostly a local laptop concern.

Where the laptop gets its identity — and where you should never go

A related hazard is the old habit of downloading a service-account JSON key file and pointing GOOGLE_APPLICATION_CREDENTIALS at it. It works, but a long-lived key on a laptop is a standing credential an attacker can use until someone revokes it. The safer path for “run as a robot identity” is impersonation: stay logged in as yourself and add --impersonate-service-account to borrow the SA’s permissions for that one command, no key on disk. The ways code finds its credentials, best to worst:

How credentials are provided Where it’s used Safety Notes
Attached service account (metadata) GCP VMs, Cloud Run, Cloud Shell Best No key exists; platform supplies short-lived tokens
Impersonation (--impersonate-service-account) Your laptop, acting as a robot Strong You keep your identity; no downloaded key
Workload Identity Federation CI/CD outside GCP (GitHub Actions, etc.) Strong Keyless; external identity trades for short-lived tokens
ADC user login (application-default login) Local dev with the libraries Good Your own identity; fine for development
Downloaded JSON key + GOOGLE_APPLICATION_CREDENTIALS Legacy / last resort Weak Long-lived secret on disk; avoid; rotate/disable if used

Configurations: your context, named and switchable

A configuration is a named bundle of properties — at minimum your active account, your project, and your default compute/region and compute/zone. Commands inherit these silently, which is why a correctly-set config means you almost never type --project. Set the basics:

gcloud config set project my-project-id
gcloud config set compute/region us-central1
gcloud config set compute/zone   us-central1-a
gcloud config list                              # confirm what's active

The power move is multiple named configurations — one per client, environment or identity — and switching between them in a single command:

gcloud config configurations create client-acme
gcloud config set project acme-prod
gcloud config set account [email protected]
# ...later, flip back to your default context:
gcloud config configurations activate default
gcloud config configurations list               # see them all, * marks active

This is the antidote to “wrong project” disasters: instead of remembering to pass --project acme-prod and forgetting it on the one destructive command, you activate the acme configuration and every command targets the right place. The properties worth knowing and where each one bites:

Property What it sets Set with If unset, the symptom
project The active project for all commands gcloud config set project ID “project is required” or wrong-project changes
account Which logged-in identity is active gcloud config set account EMAIL Commands run as the wrong user
compute/region Default region for regional resources gcloud config set compute/region R gcloud prompts you for a region each time
compute/zone Default zone for zonal resources (VMs, disks) gcloud config set compute/zone Z You must pass --zone on every VM command
core/disable_prompts Suppress interactive prompts globally gcloud config set disable_prompts true Scripts hang waiting for a Y/N answer

A clean separation rule of thumb: pick your default region/zone once based on where your users and data live (see GCP regions and zones explained), set it in your configuration, and only override with a per-command --zone when you have a specific reason.

Shaping output: --format and --filter (the superpower)

Most newcomers treat gcloud output as fixed text to read with their eyes; professionals treat it as data. --filter narrows which rows you get using simple field expressions; --format controls how the result is rendered — a human table, a bare value for a script, JSON for a program, CSV for a spreadsheet. Together they turn any list/describe into a precise query:

# Only running VMs, showing just name and zone, as a clean table
gcloud compute instances list \
  --filter="status=RUNNING" \
  --format="table(name, zone, machineType.basename())"

# Just one value — the external IP of a VM — perfect to capture in a script
gcloud compute instances describe web-1 --zone=us-central1-a \
  --format="value(networkInterfaces[0].accessConfigs[0].natIP)"

# Every bucket as JSON, for a program to consume
gcloud storage buckets list --format=json

# Projects whose ID starts with "prod", as CSV
gcloud projects list --filter="projectId:prod*" --format="csv(projectId, name)"

The second example is the one you’ll use constantly: --format="value(...)" returns a bare string with no header, so you can assign it to a shell variable (IP=$(gcloud ... --format='value(...)')) and build real automation. The format types and when to choose each:

--format value Output shape Use it for Example
table(...) Aligned columns (the default-ish view) Human reading; pick exactly the columns you want --format="table(name, status)"
value(...) Bare value(s), no header Capturing a single field in a script --format="value(name)"
json Full JSON document Feeding another program / jq --format=json
yaml YAML (the describe default) Reading a full resource by eye --format=yaml
csv(...) Comma-separated rows Importing into a spreadsheet --format="csv(name, zone)"
flattened One key: value per line Grepping deeply-nested fields --format=flattened

Common --filter patterns, which read almost like English once you’ve seen a few:

You want… --filter expression Notes
Exact match status=RUNNING = is exact, case-insensitive for enums
Substring / prefix name:web or projectId:prod* : is “contains”; * is a wildcard
Numeric comparison diskSizeGb>=100 >, <, >=, <= work on numbers
Combine conditions status=RUNNING AND zone:us-central1 AND, OR, NOT, parentheses
Negate NOT name:test Exclude rows
Label match labels.env=prod Filter on resource labels

The mental model: --filter is your WHERE clause, --format is your SELECT clause. If you’ve ever written SQL, gcloud’s data flags will feel instantly familiar — and if you haven’t, “narrow the rows, then choose the columns” is all you need to remember.

Architecture at a glance

There is no box-and-arrow diagram here, because the architecture of gcloud is a mental one — a short pipeline every command flows through. Picture four stages, left to right. You type a sentence (gcloud GROUP VERB NAME --flags): the CLI parses the grammar, merges your explicit flags with the active configuration’s properties (so an omitted --project is filled in from gcloud config), and resolves which identity to use (your gcloud auth login credentials, or an impersonated service account). Nothing has left your machine yet — gcloud is assembling a complete, authenticated request from your terse input plus your stored context. Then gcloud calls a Google Cloud REST API: under the hood gcloud compute instances create is an HTTPS call to compute.googleapis.com, signed with an OAuth token. This is the key insight — gcloud, the Console and the client libraries are three front doors to the same APIs, which is exactly why the Console can show the “Equivalent command line” for a form and why a gcloud command maps cleanly onto a Terraform resource later.

Finally, Google Cloud checks IAM and acts: the API verifies your identity holds a role granting the permission the verb needs (e.g. compute.instances.create), performs the operation, and returns a result — often an operation handle for long-running work like booting a VM — which gcloud renders back to your terminal through --format, as a table for your eyes or a bare value for your script. Type → assemble-with-context → call API → render: that is the whole machine, and every command you write is just a different sentence poured into the same pipeline.

Real-world scenario

Northwind Books, a mid-sized online retailer, hired a junior platform engineer named Priya to help manage their Google Cloud estate. Northwind runs two projects — northwind-prod and northwind-staging — plus does occasional contracting work in a client’s project, bluewave-prod, that they have guest access to. In her first week, Priya hit every classic gcloud wall, and how she climbed each one is the whole curriculum in miniature.

Day one: the wrong-project scare. Asked to “delete the old test VM,” Priya ran gcloud compute instances list, saw a test-runner instance, and was one keystroke from deleting it — until she noticed gcloud config list reported the active project as bluewave-prod, the client’s. The test-runner she was about to delete was theirs, not Northwind’s. The lesson landed hard: always gcloud config list before any write. She fixed the root cause by creating three named configurations — nw-prod, nw-staging, bluewave — each pinned to its project and the right account. From then on, switching context was gcloud config configurations activate nw-staging, and “wrong project” became structurally impossible rather than a thing she had to remember.

Day two: the credentials that “weren’t there.” Priya wrote a small Python script to tag every untagged bucket. It failed instantly: “your default credentials were not found.” She’d run gcloud auth login and her gcloud commands worked fine, so she assumed she was authenticated. The penny dropped when a colleague explained the two logins: her human login made the CLI work, but the script needed ADC. One gcloud auth application-default login later, the script ran. She wrote both commands into the team’s onboarding doc so the next hire wouldn’t lose an afternoon to it.

Day three: turning gcloud into a report. Finance asked, “how many VMs are running across staging, and what are they costing roughly?” Instead of clicking through the Console three times, Priya wrote one line: gcloud compute instances list --filter="status=RUNNING" --format="csv(name, zone, machineType.basename())", piped it into a spreadsheet, and had the answer in thirty seconds. She turned the same query into a daily Cloud Scheduler check that flags any VM larger than e2-medium left running overnight — her first piece of real automation, built entirely from the --filter/--format she’d learned two days earlier.

The arc is the point: every senior gcloud habit Priya now has — config-per-context, the two-login discipline, output-as-data — started as a small, specific mistake, and none of it required memorising commands, only understanding the shape of the tool. Three weeks in, she was the person other juniors asked, and her runbooks (copy-pasteable gcloud, not screenshots) became the team standard.

Advantages and disadvantages

The CLI is not always the right tool — knowing when to drop back to the Console (or jump forward to Terraform) is part of fluency:

Aspect gcloud CLI — advantage gcloud CLI — disadvantage
Repeatability Identical results every run; paste into runbooks None — this is its core strength
Speed One line beats a menu safari, especially in bulk Steep at first; you must know roughly what to type
Scriptability Composes with shell, --format=value, CI pipelines Imperative — no built-in state/drift tracking like Terraform
Auditability Commands are text: diff-able, reviewable, version-controllable Ad-hoc commands run outside a pipeline still aren’t reviewed
Discoverability --help at every level; self-documenting grammar Worse than the Console for exploring a brand-new service visually
Safety Confirmation prompts; describe before delete --quiet + wrong config = fast, silent damage
Reproducibility Great for one-off ops and glue For long-lived infra, Terraform’s declarative model is better

When each matters: reach for the Console to learn a service you’ve never used (its forms teach you the options, and many show the equivalent gcloud command), gcloud the instant a task is repetitive or belongs in a runbook, and Terraform when infrastructure must be reproducible, reviewed and tracked over time. gcloud is the scalpel for operations and quick fixes; IaC is the blueprint for the building. A healthy pattern is prototype in gcloud, then codify in Terraform once it’s proven.

Hands-on lab

This is the centerpiece. You will create a real Linux VM on the free tier, log into it, attach a firewall rule, capture its IP with --format, then tear everything down — all from the command line. It stays inside the Always Free tier (one e2-micro in an eligible US region), but you must run delete at the end so nothing lingers. About fifteen minutes end to end.

Where to run it: the zero-install path is Cloud Shell — open console.cloud.google.com, click the terminal icon (top-right), and you have an authenticated SDK instantly. Everything below also works on a local SDK install after gcloud init. Console equivalents are noted so you see both worlds.

Step 0 — Confirm where you are

Never act blind. Check your active account, project and region first:

gcloud config list
gcloud auth list                 # which identity is active (marked with *)

Expected output: a block showing account, project, and (ideally) compute/region + compute/zone. If project is unset or wrong, fix it before going further:

gcloud config set project YOUR_PROJECT_ID
gcloud config set compute/region us-central1
gcloud config set compute/zone   us-central1-a

Console equivalent: the project picker in the top bar shows the active project; the avatar (top-right) shows the active account.

Validate: rerun gcloud config list and confirm project, region and zone are all set. This one habit prevents the wrong-project mistake from the scenario above.

Step 1 — Enable the Compute Engine API

A service’s API must be enabled in the project before use (a fresh project has almost everything off):

gcloud services enable compute.googleapis.com

Expected output: Operation "operations/..." finished successfully. (It can take 30–60 seconds the first time.)

Console equivalent: APIs & Services → Library → search “Compute Engine API” → Enable.

Validate: gcloud services list --enabled --filter="config.name:compute" --format="value(config.name)" should print compute.googleapis.com.

Step 2 — Create the VM

Create a single free-tier e2-micro running Debian (the backslashes just split one long command across lines):

gcloud compute instances create kv-lab-vm \
  --zone=us-central1-a \
  --machine-type=e2-micro \
  --image-family=debian-12 \
  --image-project=debian-cloud \
  --tags=kv-lab

Expected output: a one-row table showing NAME (kv-lab-vm), ZONE, MACHINE_TYPE (e2-micro), an internal IP and an external IP, and STATUS: RUNNING.

Console equivalent: Compute Engine → VM instances → Create instance → name it, pick e2-micro / us-central1 / Debian 12 → Create. (The “Equivalent command line” link on that page shows the very command above.)

Validate:

gcloud compute instances list --filter="name=kv-lab-vm" \
  --format="table(name, status, machineType.basename())"

You should see kv-lab-vm RUNNING e2-micro.

Step 3 — Capture the VM’s external IP with --format

Practise output-as-data: pull just the external IP into a shell variable using --format="value(...)":

IP=$(gcloud compute instances describe kv-lab-vm --zone=us-central1-a \
  --format="value(networkInterfaces[0].accessConfigs[0].natIP)")
echo "VM external IP is: $IP"

Expected output: VM external IP is: 34.x.x.x (a real public IP).

Validate: echo $IP prints a non-empty IP. This is the pattern behind nearly all gcloud scripting — a single field, captured cleanly, no header to strip.

Step 4 — SSH into the VM

gcloud compute ssh handles SSH key generation and injection for you — no manual key management:

gcloud compute ssh kv-lab-vm --zone=us-central1-a

Expected output: the first time, it generates a key pair, then drops you at a shell prompt on the VM, e.g. your_user@kv-lab-vm:~$. Run a command to prove you’re inside the box:

hostname && cat /etc/os-release | grep PRETTY_NAME
exit

hostname returns kv-lab-vm and the OS line shows Debian 12. Type exit to return to your own shell.

Console equivalent: the “SSH” button next to the instance opens a browser SSH session — same result, no key handling on your part.

Validate: you saw kv-lab-vm as the hostname from inside the VM, then returned to your local/Cloud Shell prompt.

Step 5 — Add a firewall rule (allow HTTP)

Suppose this VM will serve web traffic. The network blocks inbound HTTP by default; add a rule opening port 80 only to VMs carrying the kv-lab tag:

gcloud compute firewall-rules create allow-http-kv-lab \
  --direction=INGRESS \
  --action=ALLOW \
  --rules=tcp:80 \
  --target-tags=kv-lab \
  --source-ranges=0.0.0.0/0

Expected output: a one-row table for allow-http-kv-lab showing INGRESS, ALLOW, and tcp:80.

Console equivalent: VPC network → Firewall → Create firewall rule → ingress, allow, tcp:80, target tag kv-lab.

Validate:

gcloud compute firewall-rules list --filter="name=allow-http-kv-lab" \
  --format="table(name, direction, allowed[].map().firewall_rule().list())"

You should see the rule listing tcp:80. (We won’t install a web server — the goal is the firewall command pattern, which is identical for any port.)

Step 6 — The same VM as Terraform (a peek forward)

Everything you did imperatively can be declared. You won’t run this, but seeing the gcloud-to-Terraform mapping makes your next stage concrete — the same VM as code:

resource "google_compute_instance" "kv_lab_vm" {
  name         = "kv-lab-vm"
  zone         = "us-central1-a"
  machine_type = "e2-micro"
  tags         = ["kv-lab"]

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-12"
    }
  }

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

The shape is the same — name, zone, machine type, image, tag — just declarative instead of a verb. The mental jump from gcloud compute instances create to this is small, which is exactly why prototyping in gcloud first pays off.

Step 7 — Tear everything down

The most important step — leaving resources running is how surprise bills happen. Delete in reverse order (rule, then VM). Each command prompts for confirmation; answer Y:

gcloud compute firewall-rules delete allow-http-kv-lab
gcloud compute instances delete kv-lab-vm --zone=us-central1-a

Expected output: each prompts The following ... will be deleted ... Do you want to continue (Y/n)? — confirm, and each reports deletion.

Validate (the proof it’s clean):

gcloud compute instances list --filter="name=kv-lab-vm" --format="value(name)"
gcloud compute firewall-rules list --filter="name=allow-http-kv-lab" --format="value(name)"

Both should return nothing (empty output) — confirming the VM and rule are gone and nothing is billing. An e2-micro is free-tier eligible, but a forgotten external IP or non-eligible region can still cost a little, so “empty output” is your all-clear.

A compact recap of the whole lab — the verb each step exercised and what it proved:

Step Command verb What it taught
0 config list / auth list Always confirm context before acting
1 services enable APIs are off until enabled per project
2 compute instances create The create NAME --flags pattern
3 describe + --format=value Output-as-data; capture one field
4 compute ssh gcloud manages SSH keys for you
5 firewall-rules create The firewall command pattern (any port)
6 (Terraform) The gcloud → IaC mapping
7 delete + validate-empty Always tear down; prove it’s clean

Common mistakes & troubleshooting

These are the failures that actually consume newcomer hours. Each is symptom → root cause → how to confirm → fix. Bookmark this; you will hit most of them in your first month.

1. “Your default credentials were not found” when running a script or Terraform. Root cause: You ran gcloud auth login (which authenticates the CLI) but never created ADC for your code. The script looks for Application Default Credentials, which don’t exist. Confirm: gcloud auth application-default print-access-token errors; the file ~/.config/gcloud/application_default_credentials.json is missing. Fix: Run gcloud auth application-default login. Two logins, two purposes — the script needs the second one.

2. A command changed (or nearly deleted) the wrong resource — wrong project. Root cause: Your active configuration points at a different project than you assumed; commands silently inherit project from config. Confirm: gcloud config list shows an unexpected project (or account). Fix: gcloud config set project RIGHT_ID, or gcloud config configurations activate the-right-one. Build the habit of gcloud config list before any write. Use one named configuration per project/client.

3. “Permission denied” / PERMISSION_DENIED even though you’re logged in. Root cause: You’re authenticated but your identity lacks the IAM role granting the permission the verb needs (e.g. compute.instances.create). Authentication ≠ authorization. Confirm: The error names the missing permission; gcloud projects get-iam-policy PROJECT --flatten="bindings[].members" --filter="bindings.members:YOUR_EMAIL" shows your roles. Fix: Have an admin grant the right role (see Google Cloud IAM explained simply), or — if you should act as a service account — add --impersonate-service-account=SA_EMAIL.

4. “API [compute.googleapis.com] not enabled on project.” Root cause: A fresh project has most service APIs disabled; you must enable each one before use. Confirm: The error itself names the API; gcloud services list --enabled doesn’t list it. Fix: gcloud services enable compute.googleapis.com (swap in the named API). Enabling can take up to a minute to propagate.

5. gcloud keeps asking “Did you mean zone…?” or “region is required.” Root cause: No default zone/region is set in your configuration, so zonal/regional commands have nothing to inherit. Confirm: gcloud config list shows no compute/zone or compute/region. Fix: gcloud config set compute/zone us-central1-a and gcloud config set compute/region us-central1, or pass --zone/--region per command.

6. A command “the docs mention” doesn’t exist — Invalid choice. Root cause: The command lives in a beta or alpha surface (or a component you haven’t installed), not the stable gcloud. Confirm: gcloud GROUP --help doesn’t list the verb; the docs show gcloud beta .... Fix: Prefix with beta/alpha (gcloud beta ...) and/or gcloud components install COMPONENT; run gcloud components update if your SDK is simply old.

7. A script hangs forever, waiting at a prompt. Root cause: A delete (or other destructive verb) is asking Do you want to continue (Y/n)? and there’s no human to answer in a non-interactive run. Confirm: The job is stuck with no output after a destructive command. Fix: Add --quiet to suppress prompts in automation (gcloud compute instances delete X --quiet) — but only where you’re certain, since --quiet removes your safety net.

8. gcloud: command not found after installing the SDK. Root cause: The SDK’s bin directory isn’t on your PATH (the post-install step that adds it was skipped). Confirm: which gcloud returns nothing; the SDK folder exists but isn’t referenced in your shell profile. Fix: Re-run the installer’s path step, or add the SDK bin to PATH in your shell profile and restart the shell. (Cloud Shell sidesteps this entirely — gcloud is already on the path.)

9. SSH to a VM hangs or is refused. Root cause: No firewall rule allows inbound SSH (tcp:22) from your source, or the VM has no external IP / is still booting. Confirm: gcloud compute firewall-rules list shows nothing allowing tcp:22; describe shows the VM has no natIP or isn’t RUNNING yet. Fix: Ensure a rule allows tcp:22 from your range (the default network usually has default-allow-ssh), wait for STATUS: RUNNING, and use gcloud compute ssh (it manages keys). For private VMs, use IAP-based SSH.

10. Output is hard to script — you’re grepping/cutting text fragilely. Root cause: Parsing the human table with grep/awk/cut instead of asking gcloud for exactly the field. Confirm: Your script breaks when a column width or header changes. Fix: Use --format="value(field.path)" to get the bare value, or --format=json and parse with jq. Let gcloud do the extraction; never screen-scrape its tables.

The fastest-to-diagnose cluster — the four “auth-shaped” errors and the one command that tells them apart:

Symptom It’s actually One command to confirm Fix in a phrase
Code: “default credentials were not found” Missing ADC gcloud auth application-default print-access-token Run application-default login
CLI: “you do not currently have an active account” Not logged into the CLI gcloud auth list Run gcloud auth login
“PERMISSION_DENIED” on an action Logged in, wrong role gcloud projects get-iam-policy ... Grant the role / impersonate
“API … not enabled” Service API off gcloud services list --enabled gcloud services enable ...

Best practices

Security notes

Cost & sizing

The gcloud CLI itself is free — it’s just a client for the APIs. What costs money is what you create with it, and the lab is engineered to stay free. One e2-micro VM in an eligible US region (us-central1, us-west1, us-east1) sits inside the Always Free monthly allotment, with a small standard-persistent-disk allowance and a modest egress quota; run the teardown and nothing accrues. What turns “free” into a small bill: a non-eligible region or a bigger machine type, a reserved static external IP left unattached (idle reserved IPs are billed), disks left behind after a VM is deleted, and egress beyond the allotment. The Step 7 validate-empty check is the safeguard — if list returns nothing, nothing is billing.

Rough figures so the trade-offs are concrete (prices vary by region and change over time — treat as order-of-magnitude):

Item Free-tier status Rough cost if NOT free How to stay free
e2-micro VM (eligible US region) Always Free (1/month) ~₹600–900 / month if run continuously elsewhere/larger Use e2-micro in us-central1/us-west1/us-east1
Standard persistent disk (boot) Free up to 30 GB-months ~₹3–4 / GB / month beyond Keep the default small boot disk; delete with the VM
Ephemeral external IP (in use) Free while attached to a running VM Don’t reserve a static IP for the lab
Reserved static IP (idle) Not free when unattached ~₹250–350 / month idle Don’t reserve one; release any you created
Network egress Free up to ~1 GB/month (N. America) Per-GB beyond The lab sends almost nothing
gcloud CLI / Cloud Shell Always free

The discipline that actually controls cost is the teardown habit, not the machine type — a forgotten e2-medium or an orphaned reserved IP is how a “free lab” becomes a line item. For ongoing spend control, set a budget alert on the project early (covered in GCP billing & cost management deep dive).

Interview & exam questions

1. Walk me through the anatomy of a gcloud command. gcloud GROUP [SUBGROUP] VERB [NAME] [--flags] — group is the service area (compute), subgroup narrows it (instances), verb is the action (create), name is the resource, flags supply details. The same six verbs (list/describe/create/update/delete/set) recur across services, so commands are composable rather than memorised.

2. Difference between gcloud auth login and gcloud auth application-default login? The first authenticates you, the human, so the commands you type work; the second writes Application Default Credentials (ADC) that your code, Terraform and client libraries read. A script failing with “default credentials not found” needs the second one, even if your CLI works fine.

3. A command changed the wrong resource. What happened and how do you prevent it? The active configuration pointed at a different project than assumed, and commands silently inherit it. Confirm with gcloud config list; prevent it by keeping one named configuration per project and activating the right one instead of relying on memory to pass --project.

4. How do you extract a single field — say a VM’s external IP — for a script? Use --format="value(field.path)", which returns the bare value with no header (e.g. --format="value(networkInterfaces[0].accessConfigs[0].natIP)"), and assign it to a shell variable. Never grep/cut the human table — let gcloud do the extraction.

5. Difference between --filter and --format? --filter decides which rows you get (the WHERE clause: status=RUNNING); --format decides how output is rendered (the SELECT clause: table, value, json, csv). Together they turn any list/describe into a precise, scriptable query.

6. A teammate gets “PERMISSION_DENIED” but insists they’re logged in. What’s going on? Authentication is not authorization — they’re authenticated but their identity lacks the IAM role granting the permission the verb needs (e.g. compute.instances.create). The fix is an IAM role grant or impersonating a service account that has it, not re-running auth login.

7. Why might a command “from the docs” return Invalid choice? It lives in the beta/alpha surface (or an uninstalled component), not stable gcloud. Prefix with gcloud beta ..., install the component, and/or run gcloud components update if the SDK is old.

8. What are named configurations and why use more than one? A configuration is a named bundle of properties (account, project, default region/zone) commands inherit; one per client/environment lets you switch context in a single command, eliminating wrong-project mistakes from forgetting --project.

9. When should you use gcloud versus the Console versus Terraform? Console to explore an unfamiliar service; gcloud the moment a task is repeatable, scriptable or belongs in a runbook; Terraform when infrastructure must be reproducible, reviewed and tracked. A common pattern is prototype in gcloud, then codify in Terraform.

10. Why is downloading a service-account key discouraged, and what’s the alternative? A long-lived JSON key is a standing secret that grants access until revoked — a leak risk in any laptop, log or repo. Prefer keyless paths: impersonation for human-as-robot, Workload Identity Federation for CI/CD, and the attached service account on GCP compute.

11. What does gcloud init do? It runs the interactive first-time setup — logs you in, lets you pick or create a default project, optionally sets a default region/zone — populating a configuration so subsequent commands have context. You run it once per machine or new identity.

12. A gcloud script hangs in CI. Cause and fix? A destructive verb (often delete) is waiting at a Y/n confirmation prompt no human will answer. Add --quiet (or set gcloud config set disable_prompts true), only where the action is safe and tested.

These map to the Cloud Digital Leader (CDL) and especially the Associate Cloud Engineer (ACE) exams, which probe the CLI, configurations, the auth/ADC distinction and --format/--filter — see the GCP certification prep kit for the full mapping.

Quick check

  1. In the command gcloud compute instances create web-1 --zone=us-central1-a, name the four structural parts (group, subgroup, verb, name) and the flag.
  2. Your Python script errors with “your default credentials were not found,” but your gcloud commands work fine. Which command fixes it, and why?
  3. You want just the names of all running VMs, one per line, to feed a loop. Write the --filter and --format you’d use.
  4. You manage prod and staging in two different projects and keep changing the wrong one. What gcloud feature solves this, and what command switches between them?
  5. True or false: downloading a service-account JSON key is the recommended way to let your laptop act as a service account.

Answers

  1. Group = compute, subgroup = instances, verb = create, name = web-1; the flag is --zone=us-central1-a. Reads as “in compute/instances, create web-1 in this zone.”
  2. gcloud auth application-default login. Your gcloud auth login authenticated the CLI; the script needs separate Application Default Credentials (ADC) for the client libraries. Two logins, two purposes.
  3. gcloud compute instances list --filter="status=RUNNING" --format="value(name)"--filter narrows to running VMs (the WHERE), --format="value(name)" prints bare names one per line (the SELECT).
  4. Named configurations — keep one per project (e.g. prod, staging) and switch with gcloud config configurations activate staging. Every command then inherits the right project automatically, so “wrong project” becomes structurally impossible.
  5. False. A long-lived key is a leak risk. Prefer keyless impersonation (--impersonate-service-account), Workload Identity Federation for CI/CD, or the attached service account on GCP compute.

Glossary

Next steps

You can now compose any gcloud command, set up your auth and configurations correctly, and turn output into data. Build outward:

GCPgcloud CLICloud SDKCloud ShellConfigurationsAutomationCheat SheetBasic
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