Compute Engine

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

See the section bibliography for the reference material consulted while preparing these pages.

Examples on this page target the gcloud CLI 586 and the Compute Engine API, checked on 2026-09-30. Machine series, image families and launch stages change often, so re-verify with gcloud --version, gcloud compute machine-types list and gcloud compute images list before relying on a specific value. The Bookshelf scenario (a static front end, catalog-api, orders-api and the notifier worker) is described in the section introduction; my-project-id, us-central1 and us-central1-a are placeholders. Compute Engine is the infrastructure-as-a-service building block: you choose the machine, the disk and the operating system, and you are responsible for patching and securing everything above the hypervisor. For most new HTTP workloads a managed option such as Cloud Run is a better starting point, and this page covers the cases where a VM is the right tool.

Core concepts

A Compute Engine instance is a virtual machine in one zone of one region (see Google Cloud Global Infrastructure). Its main parts are:

  • A machine type that fixes the vCPU count and memory, chosen from a machine family and series.

  • A boot disk created from an image, plus optional additional disks and local SSDs.

  • A network interface in a VPC subnet, with an internal IP address and optionally an external one (see VPC Networking on Google Cloud).

  • A service account attached to the VM, which is how code on the VM obtains credentials through Application Default Credentials without any key file (see Identity and Access).

  • Metadata (key-value pairs, including startup scripts) readable from the VM through the metadata server.

  • Labels and network tags, the first for cost reporting and filtering, the second for matching firewall rules.

Instances are billed per second, with a one-minute minimum, while they run, and their disks and static addresses are billed as long as they exist, running or not. A stopped VM (status TERMINATED) costs nothing for compute, but keeps costing for disks.

The relationship between the templates, the group and the load balancer used later in this page is:

flowchart LR T[Instance template] --> M[Regional managed instance group] M --> V1[VM zone a] M --> V2[VM zone b] M --> V3[VM zone c] HC[Health check] -. autohealing .-> M A[Autoscaler] -. size .-> M LB[Load balancer] --> V1 LB --> V2 LB --> V3

Machine families and series

Machine types are grouped by workload. The families and the series inside each one are listed on the machine families resource and comparison guide, which is the page to consult before choosing, because new series appear every year.

Family Typical series Use it for

General purpose

E2, N4, N4A, N4D, N2, N2D, N1, T2D, T2A

Web and application servers, small databases, development environments. N4 is the current recommended balanced series, and E2 is the low-cost option.

Compute optimized

C4, C4A (Arm, Google Axion), C4D, C3, H3

Latency-sensitive services, game servers, high-performance computing. C4 and C4A pair high clock speeds with Hyperdisk storage.

Memory optimized

M4, M3, X4

In-memory databases and large analytics.

Storage optimized

Z3

Workloads with large local SSD requirements.

Accelerator optimized

A4, A3, G2, G4

GPU workloads for training, inference and rendering.

Three practical rules follow:

  • Prefer a recent series. Older guides still create VMs with n1-standard-1 from a long-retired Ubuntu image, which works but is both slower and usually more expensive per unit of work than a current series.

  • Newer series (C4, N4 and their relatives) support only Hyperdisk volumes, not the older Persistent Disk types, so the machine series constrains the disk choice (see Disks and Hyperdisk).

  • Arm series (C4A, N4A, T2A) need an Arm image (for example debian-13-arm64) and software built for arm64. Java bytecode runs unchanged, but native libraries and container images must be multi-architecture.

Besides predefined machine types such as n4-standard-4, custom machine types let you pick the vCPU and memory independently, in series that support them, with the prefix n4-custom-4-20480, or --custom-cpu and --custom-memory flags on the CLI. Shared-core types (the e2-micro, e2-small and e2-medium sizes) can burst above a baseline and are the cheapest way to run a small VM.

Related options, covered only briefly here:

  • Shielded VM (secure boot, a virtual TPM and integrity monitoring) is on by default for most current public images.

  • Confidential VMs encrypt memory in use on supported series and are enabled with --confidential-compute-type.

  • Sole-tenant nodes give you a physical server dedicated to your project for licensing or isolation reasons.

Images and image families

An image is a bootable disk snapshot. Google publishes public images for Debian, Ubuntu, Rocky Linux, Red Hat Enterprise Linux, SUSE, Windows Server and others, each in a project named for the vendor (for example debian-cloud). Rather than a specific image name, use an image family, a pointer that always resolves to the newest non-deprecated image in that family, such as debian-13. Checking the current list on 2026-09-30 shows the Debian 12 and 13 families, and Ubuntu 24.04 LTS and 26.04 LTS families.

Production fleets usually bake a custom image from a configured VM (or build it with Packer) so that new VMs start ready, instead of installing software on every boot. Custom images can be grouped into your own family, and each new version added to the family is picked up by the next template that references the family. Container-Optimized OS is a Google-maintained, minimal image for hosts that only run containers.

gcloud compute images list --filter="family~'^debian-1[23]$'" \
  --format="table(name,family,creationTimestamp.date())"

gcloud compute images describe-from-family debian-13 --project=debian-cloud \
  --format="value(name,family)"

Disks and Hyperdisk

Every VM has a boot disk. Hyperdisk is the current block-storage family: Hyperdisk Balanced, Balanced High Availability, Extreme, Throughput and ML, with provisioned IOPS and throughput that you tune independently of the size. Older Persistent Disk types (pd-balanced, pd-ssd, pd-standard) remain available on the series that support them, such as E2 and N2. Local SSD is fast, ephemeral storage that is lost when the VM stops. This page uses the default boot disk for each example, and the details of disk types, regional disks, storage pools and file shares are on Block and File Storage on Google Cloud.

Creating a VM

In the Google Cloud console

  1. Select the project in the project picker at the top of the console, and enable the Compute Engine API when prompted (the first visit to Compute Engine does this for you).

  2. Open Compute Engine, then VM instances, then Create instance.

  3. Give the VM a name, choose a Region and Zone, and pick a machine configuration, for example the General purpose tab with the E2 or N4 series and a small preset.

  4. Under OS and storage, choose Change to select the operating system, a version (an image family) and the boot disk type and size.

  5. Under Identity and API access, choose the service account the VM runs as. Prefer a dedicated one over the Compute Engine default service account, and grant it only the roles the application needs.

  6. Under Networking, add network tags, and decide whether the VM gets an external IP. Under Security, tick Turn on OS Login if the project does not already enforce it.

  7. Under Advanced options, then Management, paste a startup script (see Startup scripts and metadata).

  8. Read the monthly estimate on the right, choose Equivalent code to see the gcloud command and Terraform that would do the same, then choose Create.

You can also open a Cloud Shell terminal (the terminal icon at the top right), which is a preauthenticated VM with the gcloud CLI already installed, and run the commands below there.

With the gcloud CLI

Enable the API once per project, create a dedicated service account for the VM, and create the instance:

gcloud services enable compute.googleapis.com iap.googleapis.com osconfig.googleapis.com

PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
ZONE=us-central1-a
VM=bookshelf-web-1

gcloud iam service-accounts create bookshelf-vm \
  --display-name="Bookshelf VM runtime"

gcloud compute instances create "$VM" \
  --zone="$ZONE" \
  --machine-type=e2-small \
  --image-family=debian-13 --image-project=debian-cloud \
  --boot-disk-size=20GB \
  --service-account="bookshelf-vm@$PROJECT_ID.iam.gserviceaccount.com" \
  --scopes=cloud-platform \
  --no-address \
  --tags=bookshelf-web \
  --metadata=enable-oslogin=TRUE \
  --labels=app=bookshelf,env=dev

gcloud compute instances list --filter="labels.app=bookshelf" \
  --format="table(name,zone.basename(),machineType.basename(),status,networkInterfaces[0].networkIP)"

The --scopes=cloud-platform flag grants the VM the widest OAuth scope, which makes the service account’s IAM roles the only access control, and is the recommended pattern. A VM with --no-address has no external IP, so it cannot be reached from the internet and can reach the internet only through Cloud NAT (see VPC Networking on Google Cloud). To run a Windows Server VM, change the image to a family such as windows-2025 and project windows-cloud; Windows images carry a licence surcharge, and you set the password with gcloud compute reset-windows-password.

Spot VMs

Spot VMs use spare Compute Engine capacity at a deeply discounted price, with the trade-off that Google can reclaim them at any time with a short notice (a 30-second ACPI signal). They replace the older preemptible VMs, which are still supported but had a fixed 24-hour maximum lifetime that Spot VMs do not. Use them for fault-tolerant, restartable work such as batch processing, CI runners and stateless worker pools, never for a single instance holding the only copy of data.

gcloud compute instances create bookshelf-batch-1 \
  --zone="$ZONE" \
  --machine-type=e2-standard-4 \
  --image-family=debian-13 --image-project=debian-cloud \
  --provisioning-model=SPOT \
  --instance-termination-action=STOP \
  --no-address

--instance-termination-action may be STOP (keep the disks, restart later) or DELETE. Spot VMs are excluded from the Compute Engine SLA, capacity may be unavailable in a zone, and they do not qualify for committed-use discounts. The same flag works in instance templates, so a MIG can maintain a pool of Spot VMs.

Access to VMs

OS Login

OS Login ties SSH access to IAM instead of per-VM key files. When it is enabled, Compute Engine creates a Linux account for each authorised Google identity and checks IAM at each login, so removing a role removes access, and the audit log records who logged in. It is not enabled by default for projects; enable it per project, per VM, or enforce it for a whole organization with the compute.requireOsLogin organization policy constraint (see Governance, Security and Compliance).

Grant one of these roles on the project or the instance:

  • roles/compute.osLogin for a standard Linux user without sudo.

  • roles/compute.osAdminLogin for administrator access with sudo.

  • roles/compute.osLoginExternalUser for identities outside the organization, in addition to the role above.

  • roles/iam.serviceAccountUser on the VM’s service account, because connecting to a VM that runs as a service account also requires permission to act as it.

With OS Login 2-step verification, set the metadata enable-oslogin-2fa=TRUE and users are prompted for a second factor at login.

# Enable for the whole project (all VMs, including new ones)
gcloud compute project-info add-metadata --metadata=enable-oslogin=TRUE

# Require a second factor
gcloud compute project-info add-metadata --metadata=enable-oslogin-2fa=TRUE

# Let a group log in with sudo on the project
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member="group:platform-admins@example.com" \
  --role="roles/compute.osAdminLogin"

# Enforce it organization-wide (needs the Organization Policy Administrator role)
gcloud resource-manager org-policies enable-enforce compute.requireOsLogin \
  --organization=ORGANIZATION_ID

See Set up OS Login, OS Login with 2-step verification and Manage OS Login in an organization. Older guides rely on SSH keys placed in project metadata, which are shared by every VM and do not expire. OS Login is the current approach; where it is not an option, keep metadata keys short-lived.

SSH from the console and the CLI

In the console, the SSH button next to the VM on the VM instances page opens a browser terminal that uses OS Login or temporary keys, and its gear menu can upload and download files. From a terminal, gcloud compute ssh creates a key pair if needed, registers it through OS Login, and connects. gcloud compute scp copies files with the same authentication.

gcloud compute ssh "$VM" --zone="$ZONE" --tunnel-through-iap --command="uname -a"

gcloud compute scp ./catalog-api.jar "$VM":~/ --zone="$ZONE" --tunnel-through-iap
gcloud compute scp "$VM":/var/log/syslog ./syslog.copy --zone="$ZONE" --tunnel-through-iap

IAP TCP forwarding: no external IP needed

Identity-Aware Proxy (IAP) TCP forwarding lets administrators reach SSH and RDP on VMs that have no external IP address. Traffic goes from the client through an IAP-authenticated tunnel to the VM’s internal address, so the only inbound path from the internet is Google’s IAP service, and every connection is authorised by IAM and logged. Two things are required: a firewall rule that allows ingress from the IAP range 35.235.240.0/20 on the target ports, and the roles/iap.tunnelResourceAccessor role for the user.

gcloud compute firewall-rules create allow-iap-ssh-rdp \
  --network=default \
  --direction=INGRESS --action=ALLOW \
  --rules=tcp:22,tcp:3389 \
  --source-ranges=35.235.240.0/20 \
  --target-tags=bookshelf-web

gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member="group:platform-admins@example.com" \
  --role="roles/iap.tunnelResourceAccessor"

# SSH through the tunnel
gcloud compute ssh "$VM" --zone="$ZONE" --tunnel-through-iap

# Forward a local port (for example to RDP into a Windows VM) through IAP
gcloud compute start-iap-tunnel bookshelf-win-1 3389 --local-host-port=localhost:3389 --zone="$ZONE"

On Windows, the open-source IAP Desktop application manages these tunnels and RDP sessions with a graphical interface. Because Google Cloud has no managed client VPN service, IAP TCP forwarding is the documented alternative for administrative access; see VPN and Hybrid Connectivity.

Startup scripts and metadata

Metadata is a set of key-value pairs attached to an instance or a project. The VM reads it at http://metadata.google.internal/computeMetadata/v1/ (requests need the header Metadata-Flavor: Google). The special key startup-script holds a script that runs as root on every boot, and startup-script-url points to one in Cloud Storage. Because the script re-runs each time the VM starts, write it to be idempotent, and keep secrets out of it: fetch them from Secret Manager at run time using the VM’s service account (see Secret Manager and Cloud KMS).

Save the following as startup.sh. It installs NGINX and serves a page that shows the instance name read from metadata:

#!/bin/bash
set -euo pipefail
apt-get update
apt-get install -y nginx
NAME=$(curl -s -H "Metadata-Flavor: Google" \
  http://metadata.google.internal/computeMetadata/v1/instance/name)
echo "Bookshelf front end served by ${NAME}" > /var/www/html/index.html
systemctl enable --now nginx
gcloud compute instances create bookshelf-web-2 \
  --zone="$ZONE" \
  --machine-type=e2-small \
  --image-family=debian-13 --image-project=debian-cloud \
  --tags=bookshelf-web \
  --metadata-from-file=startup-script=startup.sh

# Read the output of the script
gcloud compute instances get-serial-port-output bookshelf-web-2 --zone="$ZONE" | grep startup-script

# Change metadata later; the new script runs on the next boot
gcloud compute instances add-metadata bookshelf-web-2 --zone="$ZONE" \
  --metadata-from-file=startup-script=startup.sh

See Use startup scripts on Linux VMs and About VM metadata. Windows VMs use the windows-startup-script-ps1 key instead.

Containers on VMs

Older guides run a container on a VM with gcloud compute instances create-with-container or the Deploy container option in the console, both of which depend on the container startup agent (konlet). That agent was deprecated on 2025-07-21. Since 2026-07-31 you can no longer create VMs or managed instance groups that deploy a container through the agent (the gce-container-declaration metadata), and workflows relying on it stop working. On 2027-07-31 Google ends support for the agent entirely, with no further updates for VMs still running it. The current approaches are:

  • Run Docker on a VM with a startup script or cloud-init, from an image that has Docker installed (a Debian or Ubuntu image plus the Docker packages, or Container-Optimized OS, which includes Docker and cloud-init).

  • Move the workload to Cloud Run for stateless services, GKE when you need orchestration, or Batch for jobs that run to completion.

A startup script that pulls and runs catalog-api from Artifact Registry on a Container-Optimized OS VM (which includes Docker and the docker-credential-gcr helper) looks like this:

#!/bin/bash
docker-credential-gcr configure-docker --registries=us-central1-docker.pkg.dev
docker run -d --restart=always --name catalog-api -p 8080:8080 \
  us-central1-docker.pkg.dev/my-project-id/bookshelf/catalog-api:1.0.0

See Container startup agent deprecation and Container-Optimized OS. For the registry, see Container Registry and Builds; for Docker itself, the site’s Docker section.

Instance templates and managed instance groups

A single VM is a pet; a managed instance group (MIG) is a fleet. A MIG creates identical VMs from an instance template (an immutable description of machine type, image, disks, service account, metadata and network), keeps the requested number running, replaces failed VMs, and can scale on load. A MIG is zonal (one zone) or regional (spread across zones of a region, which survives a zone outage and is the recommended choice for production).

In the Google Cloud console

  1. Open Compute Engine, then Instance templates, then Create instance template, and fill in the same fields as for a VM (the startup script goes under Advanced options, then Management). Choose Create.

  2. Open Instance groups, then Create instance group, and choose New managed instance group (stateless).

  3. Select the template, set Location to Multiple zones and a region, and set the Autoscaling mode (On: add and remove instances), the minimum and maximum number of instances and the target CPU utilization.

  4. Under Autohealing, create a health check (HTTP on port 80 and path /) and set an Initial delay long enough for the startup script to finish.

  5. Choose Create, then add the group to a load balancer (see Load Balancing and Cloud Armor).

With the gcloud CLI

Instance templates are global resources by default, which lets a regional MIG in any region use them:

gcloud compute instance-templates create bookshelf-web-v1 \
  --machine-type=e2-small \
  --image-family=debian-13 --image-project=debian-cloud \
  --service-account="bookshelf-vm@$PROJECT_ID.iam.gserviceaccount.com" \
  --scopes=cloud-platform \
  --no-address \
  --tags=bookshelf-web \
  --metadata-from-file=startup-script=startup.sh

gcloud compute health-checks create http bookshelf-web-hc \
  --port=80 --request-path=/ \
  --check-interval=10s --timeout=5s \
  --healthy-threshold=2 --unhealthy-threshold=3

# Firewall rule so health checks can reach the VMs
gcloud compute firewall-rules create allow-health-checks \
  --network=default --direction=INGRESS --action=ALLOW \
  --rules=tcp:80 \
  --source-ranges=130.211.0.0/22,35.191.0.0/16 \
  --target-tags=bookshelf-web

gcloud compute instance-groups managed create bookshelf-web-mig \
  --region="$REGION" \
  --template=bookshelf-web-v1 \
  --size=2 \
  --health-check=bookshelf-web-hc \
  --initial-delay=120

gcloud compute instance-groups managed set-autoscaling bookshelf-web-mig \
  --region="$REGION" \
  --min-num-replicas=2 --max-num-replicas=6 \
  --target-cpu-utilization=0.6 \
  --cool-down-period=90

gcloud compute instance-groups managed list-instances bookshelf-web-mig --region="$REGION"

The behaviours that matter in operation:

  • Autohealing recreates a VM when the application health check fails, which is different from the load balancer’s health check that only removes the VM from rotation. The initial delay protects a VM from being recreated while it is still starting up.

  • Autoscaling uses signals such as average CPU utilization, load-balancing serving capacity, Cloud Monitoring metrics, or schedules. The autoscaler never goes below the minimum or above the maximum, and the cool-down period tells it how long a new VM takes to become useful.

  • Templates are immutable. To change the fleet, create bookshelf-web-v2 and start a rolling update, which replaces VMs a few at a time while keeping capacity:

gcloud compute instance-groups managed rolling-action start-update bookshelf-web-mig \
  --region="$REGION" \
  --version=template=bookshelf-web-v2 \
  --max-surge=3 --max-unavailable=0

gcloud compute instance-groups managed wait-until bookshelf-web-mig --region="$REGION" --stable

See Rolling out updates to MIGs. Adding a second template with --canary-version=template=bookshelf-web-v2,target-size=20% sends only a share of VMs to the new version first.

Fronting a MIG with a load balancer

A MIG becomes an HTTP back end by adding it to a backend service behind a load balancer, which provides one anycast IP address, TLS termination, health checks and, for the external application load balancer, optional Cloud CDN and Cloud Armor. The commands that build the URL map, proxy and forwarding rule belong with the networking material in Load Balancing and Cloud Armor; here only the link between the group and the service is shown.

gcloud compute instance-groups set-named-ports bookshelf-web-mig --region="$REGION" \
  --named-ports=http:80

gcloud compute backend-services create bookshelf-web-bes \
  --global --protocol=HTTP --port-name=http \
  --health-checks=bookshelf-web-hc \
  --load-balancing-scheme=EXTERNAL_MANAGED

gcloud compute backend-services add-backend bookshelf-web-bes --global \
  --instance-group=bookshelf-web-mig --instance-group-region="$REGION"

VM Manager and OS patching

VM Manager is the set of tools in the OS Config service for managing fleets of VMs: OS patch management (schedule and apply updates), OS inventory management (installed packages and OS version, collected per VM), and OS configuration management (policies, written as OS policy assignments, that keep files, packages and repositories in a desired state). It requires the osconfig.googleapis.com API and the OS Config agent, which is preinstalled on current Google public images and is enabled per VM or project with the metadata key enable-osconfig=TRUE.

gcloud compute project-info add-metadata --metadata=enable-osconfig=TRUE

# Inventory of one VM, once the agent has reported
gcloud compute os-config inventories describe "$VM" --zone="$ZONE" \
  --format="value(osInfo.longName,osInfo.shortName)"

# Patch every VM labelled env=dev, every Sunday at 03:00
gcloud compute os-config patch-deployments create weekly-dev-patching \
  --file=patch-deployment.yaml

The deployment file holds the targets, schedule and rollout settings:

instanceFilter:
  groupLabels:
    - labels:
        env: dev
recurringSchedule:
  timeZone:
    id: Etc/UTC
  timeOfDay:
    hours: 3
  weekly:
    dayOfWeek: SUNDAY
rollout:
  mode: ZONE_BY_ZONE
  disruptionBudget:
    percentage: 10
patchConfig:
  apt:
    type: DIST

See VM Manager overview, Create patch jobs and deployments and gcloud compute os-config patch-deployments create. In the console, open Compute Engine, then VM Manager, and choose Patch to see compliance and to create a deployment. For MIGs the better practice is not to patch in place at all: bake a new image, create a new template, and run a rolling update.

Snapshots, schedules and Backup and DR

A snapshot is an incremental copy of a disk, stored outside the zone, and the building block for backups and for copying data to another region. Standard snapshots are the default, archive snapshots cost less for long retention, and instant snapshots are taken in seconds and stay in the same location for quick local restores. The disk types and the restore procedures are on Block and File Storage on Google Cloud; this section shows scheduling.

gcloud compute resource-policies create snapshot-schedule bookshelf-daily \
  --region="$REGION" \
  --max-retention-days=14 \
  --on-source-disk-delete=keep-auto-snapshots \
  --daily-schedule --start-time=02:00 \
  --storage-location=us

gcloud compute disks add-resource-policies "$VM" \
  --zone="$ZONE" --resource-policies=bookshelf-daily

# Restore: create a new disk from a snapshot, then attach or boot from it
gcloud compute disks create bookshelf-web-1-restored --zone="$ZONE" \
  --source-snapshot=SNAPSHOT_NAME

For application-consistent backups of whole VMs, centralised retention and protection from deletion, use the Backup and DR Service. It stores backups in a backup vault (an immutable, access-controlled store) governed by a backup plan that sets the schedule and retention, and it restores a VM, a disk, or individual files. The service has its own pricing, charged for protected data and backup storage, and its own API, so enable backupdr.googleapis.com and read the Backup and DR concepts before choosing between it and plain snapshot schedules. Snapshot schedules are enough for simple disk recovery; Backup and DR is the choice for compliance-driven retention and ransomware resilience.

Pricing model and cost drivers

Compute Engine bills the following, and the prices are on the Compute Engine pricing page and in the pricing calculator (check them on the day you plan, since they vary by region and series, and this page quotes none):

  • vCPU and memory for as long as the VM runs, per second with a one-minute minimum.

  • Boot and data disks, with provisioned IOPS and throughput for Hyperdisk, plus snapshot storage.

  • Licences for premium operating systems such as Windows Server and Red Hat Enterprise Linux.

  • Network egress between regions and to the internet, and external IPv4 addresses, which are billed whether used or not.

  • Discounts: sustained-use discounts apply automatically to some older series for VMs that run much of the month; committed-use discounts trade a one- or three-year commitment for a lower rate, either resource-based or flexible, and Spot VMs give the deepest discount with no commitment.

Right-sizing recommendations (idle and over-provisioned VMs) are shown in the console and by the Recommender. Many labelled development VMs can be stopped overnight with an instance schedule resource policy, which starts and stops VMs on a timetable. The Free Program (Always Free) includes one e2-micro VM per month in a few US regions, with limits on disk and egress, listed on the free features page. See Cost Management and Billing for budgets and alerts.

Quotas and limits

Compute Engine enforces regional quotas (vCPUs by family, in-use IP addresses, disks and total persistent disk capacity, committed CPUs) and global quotas (networks, firewall rules, instance templates). A new project starts with low limits, and a request such as "Quota 'CPUS' exceeded" is solved by requesting an increase in IAM & Admin, then Quotas & System Limits, or by choosing another region. Some GPU and large-machine quotas are zero until requested. See Resource quotas.

Recent changes and where older guides are outdated

Change What it means

Container startup agent (konlet) deprecated 2025-07-21; VM/MIG creation with it blocked since 2026-07-31; support ends 2027-07-31

create-with-container and "deploy container to VM" no longer work. Use a startup script or cloud-init with Docker, or Cloud Run, GKE or Batch.

Spot VMs replace preemptible VMs

Use --provisioning-model=SPOT; there is no 24-hour limit.

C4, C4A, N4 and later series use Hyperdisk only

Disk choice depends on the series; pd-* types are not available on them.

Debian 12 and 13 and Ubuntu 24.04 and 26.04 LTS in the image catalog

Examples that use ubuntu-1604-lts, debian-9 or n1-standard-1 are outdated.

OS Login still not on by default

Enforce it with compute.requireOsLogin; do not rely on shared metadata SSH keys.

Instant and archive snapshots, and Backup and DR with backup vaults

Newer than most backup guides, which show only standard snapshots.

gsutil is legacy

Use gcloud storage for copies to and from VMs.

Troubleshooting

Symptom Check

SSH fails with a timeout

No IAP firewall rule for 35.235.240.0/20, or no roles/iap.tunnelResourceAccessor; the VM has no external IP and --tunnel-through-iap was not used.

SSH says permission denied (publickey)

OS Login is enabled but the user lacks roles/compute.osLogin or osAdminLogin, or roles/iam.serviceAccountUser on the VM’s service account.

VM stuck in a create/stop loop in a MIG

The health check fails before the initial delay ends; read the startup script output in the serial console.

ZONE_RESOURCE_POOL_EXHAUSTED

The zone has no capacity for the machine type; retry in another zone, use a regional MIG with several zones, or another series.

Quota exceeded

Request a quota increase for the region and family.

The startup script runs but nothing works

gcloud compute instances get-serial-port-output and journalctl -u google-startup-scripts.service on the VM.

Application gets 403 calling a Google API

The VM’s service account lacks the role, or the API is not enabled; check with curl -H "Metadata-Flavor: Google" …​/instance/service-accounts/default/email.

Clean up

Delete in dependency order so that nothing keeps billing. Resources created on this page are the instances and groups, templates, firewall rules, snapshot schedule, policies, and the service account:

# Group (deletes its VMs), autoscaler goes with it
gcloud compute instance-groups managed delete bookshelf-web-mig --region="$REGION" --quiet

# Backend service from the load balancer example, if you created it
gcloud compute backend-services delete bookshelf-web-bes --global --quiet

# Standalone VMs (disks are deleted with the VM unless auto-delete was disabled)
gcloud compute instances delete "$VM" bookshelf-web-2 bookshelf-batch-1 --zone="$ZONE" --quiet

# Templates, health check and firewall rules
gcloud compute instance-templates delete bookshelf-web-v1 bookshelf-web-v2 --quiet
gcloud compute health-checks delete bookshelf-web-hc --quiet
gcloud compute firewall-rules delete allow-iap-ssh-rdp allow-health-checks --quiet

# Snapshots and schedule (snapshots made by the schedule are kept per its retention)
gcloud compute snapshots list --filter="labels.app=bookshelf OR sourceDisk~bookshelf" --format="value(name)"
gcloud compute snapshots delete SNAPSHOT_NAME --quiet
gcloud compute resource-policies delete bookshelf-daily --region="$REGION" --quiet

# Restored disk, patch deployment, service account and project metadata
gcloud compute disks delete bookshelf-web-1-restored --zone="$ZONE" --quiet
gcloud compute os-config patch-deployments delete weekly-dev-patching
gcloud iam service-accounts delete "bookshelf-vm@$PROJECT_ID.iam.gserviceaccount.com" --quiet

Remove any IAM bindings you added for OS Login and IAP with gcloud projects remove-iam-policy-binding, and disable the project metadata flags (gcloud compute project-info remove-metadata --keys=enable-osconfig) if you do not want them in the project. Backups taken by Backup and DR stay in the backup vault until their retention expires and cannot be removed earlier while a vault enforces a minimum retention, so delete the plan first and expect the vault to remain for a while. Deleting a throwaway project removes all of it after a 30-day recovery window; see Shutting down projects.