Google Cloud · lesson 3 of 10
Compute Engine Fundamentals
Create a Compute Engine VM from the command line, open a firewall rule for SSH, and connect to it — the smallest complete GCP virtual machine workflow.
By SkillByExample · Published
Compute Engine is GCP’s raw virtual machine service — the layer everything more managed (Cloud Run, GKE, Cloud SQL) is ultimately built on. This lesson creates a VM, opens exactly the firewall hole it needs, and connects to it, which is the smallest loop that touches all three things Compute Engine actually is: an instance, a disk, and a network.
Enabling the API
gcloud services enable compute.googleapis.com
Operation "operations/acat.p2-918273645102-4f3a2b1c-9e8d-4a3b" finished successfully.
Every GCP service is an API that must be explicitly turned on per project — this is a one-time step per project, not per VM.
Creating a VM
gcloud compute instances create web-1 \
--machine-type=e2-micro \
--zone=us-central1-a \
--image-family=debian-12 \
--image-project=debian-cloud \
--tags=http-server
Created [https://www.googleapis.com/compute/v1/projects/skillbyexample-437219/zones/us-central1-a/instances/web-1].
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS
web-1 us-central1-a e2-micro 10.128.0.2 34.121.55.207 RUNNING
e2-micro is the machine type covered by the Always Free tier in this region — worth
knowing before the cost lesson later in this track. --tags=http-server doesn’t open any ports
by itself; a network tag only becomes meaningful once a firewall rule targets it.
The SSH attempt that fails first
gcloud compute ssh web-1 --zone=us-central1-a
Updating project ssh metadata...done.
Waiting for SSH key to propagate.
ssh: connect to host 34.121.55.207 port 22: Connection timed out
ERROR: (gcloud.compute.ssh) [/usr/bin/ssh] exited with return code [255].
The key propagated fine — the timeout is a network-level refusal, not an authentication one.
gcloud compute firewall-rules list shows why:
gcloud compute firewall-rules list
NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED
An empty list. This project’s default network has no firewall rules at all yet — every port,
including 22, is closed to everything outside the VPC.
Opening the port
gcloud compute firewall-rules create allow-ssh \
--network=default \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=0.0.0.0/0
Creating firewall...done.
NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED
allow-ssh default INGRESS 1000 tcp:22 False
source-ranges=0.0.0.0/0 means “from anywhere” — fine for a lesson VM, deliberately too broad
for anything real; the VPC lesson ahead narrows this to a specific IP range.
gcloud compute ssh web-1 --zone=us-central1-a
Updating project ssh metadata...done.
Waiting for SSH key to propagate.
Linux web-1 6.1.0-18-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.76-1 (2024-02-01) x86_64
you@web-1:~$
Same command, same VM — only the firewall changed, and the exact same timeout became an immediate connection.
Practice
1. Restrict allow-ssh to your own IP instead of the whole internet.
gcloud compute firewall-rules update allow-ssh --source-ranges=203.0.113.42/32
gcloud compute firewall-rules describe allow-ssh --format="value(sourceRanges)"
Updated [allow-ssh].
['203.0.113.42/32']
/32 means exactly one address. This is the realistic version of the rule from a laptop with a
stable IP; a dynamic home IP would need a wider range or a VPN-based approach instead.
2. Stop the VM and confirm its billing state changes.
gcloud compute instances stop web-1 --zone=us-central1-a
gcloud compute instances describe web-1 --zone=us-central1-a --format="value(status)"
Updating instance...done.
TERMINATED
TERMINATED (not STOPPED, oddly enough — that’s the actual API status string) means vCPU and
memory billing stops, but the boot disk keeps accruing storage charges until it’s deleted.
3. Reserve a static external IP and attach it after restarting.
gcloud compute addresses create web-1-ip --region=us-central1
gcloud compute instances start web-1 --zone=us-central1-a
gcloud compute instances add-access-config web-1 \
--zone=us-central1-a --address=$(gcloud compute addresses describe web-1-ip --region=us-central1 --format="value(address)")
Created [https://www.googleapis.com/compute/v1/projects/skillbyexample-437219/regions/us-central1/addresses/web-1-ip].
Updating instance...done.
Updating instance...done.
Now web-1 keeps the same external IP across future stop/start cycles, instead of getting a
new ephemeral one each time.
4. List all firewall rules and confirm only allow-ssh exists.
gcloud compute firewall-rules list --format="table(name,sourceRanges.list(),allowed[].map().firewall_rule().list())"
NAME SRC_RANGES ALLOW
allow-ssh ['203.0.113.42/32'] tcp:22
One narrowly-scoped rule — this is the state to leave a lesson VM in, and the state the VPC lesson deliberately breaks next by removing outbound internet access.
5. Delete the instance and its disk together to stop all billing.
gcloud compute instances delete web-1 --zone=us-central1-a --quiet
Deleted [https://www.googleapis.com/compute/v1/projects/skillbyexample-437219/zones/us-central1-a/instances/web-1].
By default instances delete also deletes the boot disk, since it was created with
autoDelete=true (the default for a disk created alongside its instance) — no separate disk
cleanup step needed for this VM.
Next: Cloud Storage — buckets, gsutil vs gcloud storage, and storage classes.