GCP for DevOps — Compute Engine Basics
Compute Engine Basics
Compute Engine lets you create and run virtual machines on Google’s infrastructure. Each VM runs in a specific zone, belongs to a project, and is connected to a VPC network.
Creating a VM Instance
# Create a basic VM
$ gcloud compute instances create my-vm \
--zone=us-central1-a \
--machine-type=e2-medium \
--image-family=debian-12 \
--image-project=debian-cloud \
--boot-disk-size=20GB \
--tags=http-server
Created [https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1-a/instances/my-vm].
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS
my-vm us-central1-a e2-medium 10.128.0.2 34.68.123.45 RUNNING
# Create a VM with a specific service account and no external IP
$ gcloud compute instances create build-agent \
--zone=us-central1-a \
--machine-type=e2-standard-4 \
--image-family=ubuntu-2204-lts \
--image-project=ubuntu-os-cloud \
--boot-disk-size=50GB \
--boot-disk-type=pd-ssd \
--no-address \
--service-account=ci-deployer@my-project.iam.gserviceaccount.com \
--scopes=cloud-platform \
--metadata=enable-oslogin=TRUE
Created [https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1-a/instances/build-agent].
NAME ZONE MACHINE_TYPE INTERNAL_IP EXTERNAL_IP STATUS
build-agent us-central1-a e2-standard-4 10.128.0.3 RUNNING
Listing and Describing Instances
# List all instances in the project
$ gcloud compute instances list
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS
build-agent us-central1-a e2-standard-4 10.128.0.3 RUNNING
my-vm us-central1-a e2-medium 10.128.0.2 34.68.123.45 RUNNING
# Describe a specific instance
$ gcloud compute instances describe my-vm --zone=us-central1-a \
--format="yaml(name,machineType,status,networkInterfaces[0].networkIP)"
machineType: zones/us-central1-a/machineTypes/e2-medium
name: my-vm
networkInterfaces:
- networkIP: 10.128.0.2
status: RUNNING
SSH Access
# SSH using gcloud (uses OS Login or project metadata keys)
$ gcloud compute ssh my-vm --zone=us-central1-a
# SSH with OS Login (recommended)
$ gcloud compute ssh my-vm --zone=us-central1-a
# SSH to a VM without external IP (via IAP tunnel)
$ gcloud compute ssh build-agent --zone=us-central1-a --tunnel-through-iap
# SSH with a specific user
$ gcloud compute ssh user@my-vm --zone=us-central1-a
# Run a command remotely via SSH
$ gcloud compute ssh my-vm --zone=us-central1-a --command="uname -a"
Linux my-vm 6.1.0-18-cloud-amd64 #1 SMP x86_64 GNU/Linux
OS Login
OS Login links SSH access to IAM — no need to manage SSH keys manually.
# Enable OS Login at the project level
$ gcloud compute project-info add-metadata \
--metadata=enable-oslogin=TRUE
# Grant SSH access via IAM
$ gcloud projects add-iam-policy-binding my-project \
--member="user:dev@example.com" \
--role="roles/compute.osLogin"
# For root/sudo access
$ gcloud projects add-iam-policy-binding my-project \
--member="user:admin@example.com" \
--role="roles/compute.osAdminLogin"
Managing VM Lifecycle
# Stop a VM (keeps the disk, stops billing for compute)
$ gcloud compute instances stop my-vm --zone=us-central1-a
Stopping instance(s) my-vm...done.
# Start a stopped VM
$ gcloud compute instances start my-vm --zone=us-central1-a
Starting instance(s) my-vm...done.
# Reset a VM (hard reboot)
$ gcloud compute instances reset my-vm --zone=us-central1-a
# Suspend a VM (saves memory state)
$ gcloud compute instances suspend my-vm --zone=us-central1-a
# Resume a suspended VM
$ gcloud compute instances resume my-vm --zone=us-central1-a
# Delete a VM
$ gcloud compute instances delete my-vm --zone=us-central1-a --quiet
Deleted [my-vm].
Labels and Metadata
# Add labels (for billing, organization)
$ gcloud compute instances add-labels my-vm \
--zone=us-central1-a \
--labels=env=dev,team=devops,cost-center=engineering
# Set custom metadata (key-value pairs available inside the VM)
$ gcloud compute instances add-metadata my-vm \
--zone=us-central1-a \
--metadata=app-version=2.1.0,config-url=gs://my-bucket/config.json
# Read metadata from inside the VM
$ curl -H "Metadata-Flavor: Google" \
http://metadata.google.internal/computeMetadata/v1/instance/attributes/app-version
2.1.0
Preemptible and Spot VMs
Preemptible and Spot VMs are heavily discounted (60–91% off) but can be terminated by GCE at any time.
# Create a Spot VM (replacement for preemptible)
$ gcloud compute instances create batch-worker \
--zone=us-central1-a \
--machine-type=e2-standard-8 \
--provisioning-model=SPOT \
--instance-termination-action=STOP \
--image-family=debian-12 \
--image-project=debian-cloud
# Create a preemptible VM (legacy, max 24 hours)
$ gcloud compute instances create batch-worker-legacy \
--zone=us-central1-a \
--machine-type=e2-standard-8 \
--preemptible \
--image-family=debian-12 \
--image-project=debian-cloud
| Feature | Standard VM | Preemptible VM | Spot VM |
|---|---|---|---|
| Max lifetime | Unlimited | 24 hours | Unlimited |
| Discount | 0% | 60–91% | 60–91% |
| Termination | User-initiated | GCE can preempt | GCE can preempt |
| SLA | Yes | No | No |
| Use case | Production | Batch, CI/CD | Batch, CI/CD, fault-tolerant |
Common Mistakes
| Mistake | Why It’s Wrong | Fix |
|---|---|---|
| Using default SA | Has roles/editor — too broad |
Create dedicated SA per VM |
Always using e2-medium |
May be over/under-provisioned | Right-size with Recommender |
Not using --no-address |
VM gets public IP unnecessarily | Use IAP or Cloud NAT |
| Forgetting to set zone | Defaults may not be what you expect | Always specify --zone |
| Not adding labels | Hard to track cost and ownership | Label everything: env, team, app |
Quick Reference
| Command | Description |
|---|---|
gcloud compute instances create NAME |
Create a VM |
gcloud compute instances list |
List all VMs |
gcloud compute instances describe NAME --zone=ZONE |
Show VM details |
gcloud compute ssh NAME --zone=ZONE |
SSH into a VM |
gcloud compute instances stop NAME --zone=ZONE |
Stop a VM |
gcloud compute instances start NAME --zone=ZONE |
Start a VM |
gcloud compute instances delete NAME --zone=ZONE |
Delete a VM |
gcloud compute instances add-labels NAME --labels=K=V |
Add labels |
Next → Machine Types & Images