The most surprising thing about GCP Compute Engine is that you’re not actually renting a "virtual machine" in the traditional sense; you’re renting a slice of a massively distributed, hypervisor-less system that can seamlessly move your workloads around without you even noticing.
Let’s see this in action. Imagine you want to spin up a simple web server.
First, you need a network. GCP’s networking is global by default, but you usually want to isolate your resources. You can create a Virtual Private Cloud (VPC) network.
gcloud compute networks create my-vpc-network \
--subnet-mode=custom
This command creates a custom mode VPC network named my-vpc-network. Custom mode means you explicitly define subnets, giving you more control.
Next, create a subnet within that VPC. This subnet lives in a specific region.
gcloud compute networks subnets create my-subnet \
--network=my-vpc-network \
--range=10.0.1.0/24 \
--region=us-central1
Here, my-subnet is created in the us-central1 region with an IP address range of 10.0.1.0/24.
Now, an instance. This is your "virtual machine."
gcloud compute instances create my-web-server \
--zone=us-central1-a \
--machine-type=e2-medium \
--network-interface=network=my-vpc-network,subnet=my-subnet,no-address \
--metadata=startup-script='#! /bin/bash
sudo apt-get update
sudo apt-get install -y apache2
echo "Hello from Compute Engine!" | sudo tee /var/www/html/index.html' \
--tags=http-server
This command creates my-web-server in us-central1-a using an e2-medium machine type. It’s attached to my-vpc-network and my-subnet. The no-address means it won’t get an external IP by default, which is good practice. The startup-script automatically installs Apache and creates a simple index.html. The http-server tag is crucial for firewall rules.
To access this server, you need to allow HTTP traffic.
gcloud compute firewall-rules create allow-http \
--network=my-vpc-network \
--allow=tcp:80 \
--source-ranges=0.0.0.0/0 \
--target-tags=http-server
This rule, allow-http, permits TCP traffic on port 80 from anywhere (0.0.0.0/0) to any instance tagged with http-server.
Finally, to actually connect, you need an external IP. You can reserve a static one.
gcloud compute addresses create my-web-server-ip \
--region=us-central1
Then, attach it to your instance.
gcloud compute instances add-access-config my-web-server \
--zone=us-central1-a \
--address=my-web-server-ip
Now, if you gcloud compute addresses describe my-web-server-ip --region=us-central1 and get the address field, you can curl that IP and see "Hello from Compute Engine!".
The mental model is this: GCP’s infrastructure is a massive, unified pool. When you create an instance, you’re not provisioning a dedicated piece of hardware. Instead, you’re requesting resources (CPU, RAM, disk) from this pool, and the underlying system schedules your workload onto some physical hardware. The magic is that the system is designed to transparently migrate your running instance to different physical hardware if needed, for maintenance or load balancing, without interrupting your workload. Your instance is defined by its configuration and its state, not by its physical location.
Storage is similarly abstracted. You don’t attach a "disk" in the traditional sense; you attach a persistent disk resource. These disks are network-attached storage (NAS) devices, meaning your instance accesses them over the network. This allows them to be detached from one instance and attached to another, even across different zones, which is impossible with direct-attached storage.
The machine-type isn’t just a fixed CPU/RAM combination. It’s a performance profile. GCP maps these profiles to underlying hardware, and the specific physical cores you get can vary. For instance, e2-medium might give you 2 vCPUs, but the underlying physical cores are shared and can be "burstable," meaning they can temporarily exceed their baseline performance if the underlying hardware has capacity. This is a key difference from on-premises virtualization where your VM is rigidly tied to specific physical CPU threads.
A detail that trips many people up is the difference between ephemeral and persistent disks. When you create an instance without specifying a boot disk or explicitly attaching a persistent disk, it gets an ephemeral boot disk. This disk’s data is lost when the instance is stopped or deleted. To retain data, you must use persistent disks, either as boot disks or attached volumes.
The next concept you’ll likely encounter is the finer-grained control over machine types and custom machine types, allowing you to precisely define CPU and memory for cost optimization.