GCP for DevOps — Compute Exercises
Practice Exercises — Compute
Exercise 1 — Create a Web Server VM
Task: Create an e2-small VM named web-demo in us-central1-a running Debian 12, with a startup script that installs and starts Nginx, and a firewall rule allowing HTTP traffic.
Show Answer
# Create the VM with a startup script
$ gcloud compute instances create web-demo \
--zone=us-central1-a \
--machine-type=e2-small \
--image-family=debian-12 \
--image-project=debian-cloud \
--tags=http-server \
--metadata=startup-script='#!/bin/bash
apt-get update
apt-get install -y nginx
systemctl enable nginx
systemctl start nginx
echo "<h1>Hello from $(hostname)</h1>" > /var/www/html/index.html
'
# Create a firewall rule for HTTP
$ gcloud compute firewall-rules create allow-http \
--network=default \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:80 \
--source-ranges=0.0.0.0/0 \
--target-tags=http-server
# Verify — get the external IP and test
$ gcloud compute instances describe web-demo --zone=us-central1-a \
--format="get(networkInterfaces[0].accessConfigs[0].natIP)"
34.68.123.45
$ curl http://34.68.123.45
<h1>Hello from web-demo</h1>
Key Points:
- Tags connect VMs to firewall rules
- Startup scripts run as root on every boot
- Use
--image-familyinstead of specific image names for latest versions
Exercise 2 — Create a Custom Image
Task: Create a VM, install Docker and kubectl, then create a custom image from it.
Show Answer
# Step 1: Create a builder VM
$ gcloud compute instances create image-builder \
--zone=us-central1-a \
--machine-type=e2-standard-2 \
--image-family=ubuntu-2204-lts \
--image-project=ubuntu-os-cloud \
--boot-disk-size=30GB
# Step 2: SSH and install tools
$ gcloud compute ssh image-builder --zone=us-central1-a
# Inside the VM:
$ sudo apt-get update
$ sudo apt-get install -y docker.io apt-transport-https ca-certificates curl
$ sudo systemctl enable docker
$ curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
$ sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
$ kubectl version --client
$ exit
# Step 3: Stop the VM
$ gcloud compute instances stop image-builder --zone=us-central1-a
# Step 4: Create the image
$ gcloud compute images create devops-tooling-v1 \
--source-disk=image-builder \
--source-disk-zone=us-central1-a \
--family=devops-tooling \
--description="Ubuntu 22.04 with Docker and kubectl"
# Step 5: Verify and clean up
$ gcloud compute images describe devops-tooling-v1 \
--format="table(name,family,status,diskSizeGb)"
$ gcloud compute instances delete image-builder --zone=us-central1-a --quiet
Exercise 3 — Set Up Auto-Scaling MIG
Task: Create a MIG with auto-scaling (min 2, max 6, target CPU 50%) and auto-healing with an HTTP health check.
Show Answer
# Step 1: Create an instance template
$ gcloud compute instance-templates create app-template \
--machine-type=e2-medium \
--image-family=debian-12 \
--image-project=debian-cloud \
--boot-disk-size=20GB \
--tags=http-server,health-check \
--metadata=startup-script='#!/bin/bash
apt-get update && apt-get install -y nginx
systemctl enable nginx && systemctl start nginx
echo "OK" > /var/www/html/health
'
# Step 2: Create a health check
$ gcloud compute health-checks create http app-health-check \
--port=80 \
--request-path=/health \
--check-interval=30s \
--timeout=10s \
--healthy-threshold=2 \
--unhealthy-threshold=3
# Step 3: Create the MIG
$ gcloud compute instance-groups managed create app-mig \
--zone=us-central1-a \
--template=app-template \
--size=2
# Step 4: Set auto-scaling
$ gcloud compute instance-groups managed set-autoscaling app-mig \
--zone=us-central1-a \
--min-num-replicas=2 \
--max-num-replicas=6 \
--target-cpu-utilization=0.50 \
--cool-down-period=60
# Step 5: Set auto-healing
$ gcloud compute instance-groups managed set-autohealing app-mig \
--zone=us-central1-a \
--health-check=app-health-check \
--initial-delay=120
# Step 6: Verify
$ gcloud compute instance-groups managed describe app-mig \
--zone=us-central1-a \
--format="yaml(autoscaler,autoHealingPolicies)"
$ gcloud compute instance-groups managed list-instances app-mig \
--zone=us-central1-a
Exercise 4 — Perform a Rolling Update
Task: Create a new instance template with an updated startup script, then perform a zero-downtime rolling update on the MIG.
Show Answer
# Step 1: Create an updated template
$ gcloud compute instance-templates create app-template-v2 \
--machine-type=e2-medium \
--image-family=debian-12 \
--image-project=debian-cloud \
--boot-disk-size=20GB \
--tags=http-server,health-check \
--metadata=startup-script='#!/bin/bash
apt-get update && apt-get install -y nginx
systemctl enable nginx && systemctl start nginx
echo "v2 - OK" > /var/www/html/health
echo "<h1>App v2 running on $(hostname)</h1>" > /var/www/html/index.html
'
# Step 2: Start a rolling update (zero-downtime)
$ gcloud compute instance-groups managed rolling-action start-update app-mig \
--zone=us-central1-a \
--version=template=app-template-v2 \
--max-surge=1 \
--max-unavailable=0
# Step 3: Monitor the update
$ watch -n 5 gcloud compute instance-groups managed list-instances app-mig \
--zone=us-central1-a \
--format="table(instance.basename(),status,currentAction,version.instanceTemplate.basename())"
# Step 4: Verify all instances are updated
$ gcloud compute instance-groups managed describe app-mig \
--zone=us-central1-a \
--format="get(status.versionTarget.isReached)"
True
Key Points:
--max-surge=1creates one extra VM during the update--max-unavailable=0ensures no VM is taken down until its replacement is healthy- The update respects the health check — new VMs must be healthy before old ones are removed
Exercise 5 — Secure SSH Access with IAP
Task: Create a VM with no external IP and configure SSH access through Identity-Aware Proxy (IAP).
Show Answer
# Step 1: Create a VM with no external IP
$ gcloud compute instances create private-vm \
--zone=us-central1-a \
--machine-type=e2-small \
--image-family=debian-12 \
--image-project=debian-cloud \
--no-address \
--metadata=enable-oslogin=TRUE
# Step 2: Create a firewall rule allowing SSH from IAP
$ gcloud compute firewall-rules create allow-iap-ssh \
--network=default \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=35.235.240.0/20 \
--target-tags=allow-iap
# Step 3: Add the tag to the VM
$ gcloud compute instances add-tags private-vm \
--zone=us-central1-a \
--tags=allow-iap
# Step 4: Grant IAP tunnel access
$ gcloud projects add-iam-policy-binding my-project \
--member="user:dev@example.com" \
--role="roles/iap.tunnelResourceAccessor"
# Step 5: SSH via IAP
$ gcloud compute ssh private-vm --zone=us-central1-a --tunnel-through-iap
# Verify no external IP
$ gcloud compute instances describe private-vm --zone=us-central1-a \
--format="get(networkInterfaces[0].accessConfigs)"
# Should be empty — no external IP
Key Points:
- IAP source range is
35.235.240.0/20— this is Google’s IAP proxy range --tunnel-through-iaptells gcloud to route SSH through IAP- OS Login integrates SSH access with IAM — no manual SSH key management
- This is the recommended pattern for production VMs
Cleanup
# Delete all exercise resources
$ gcloud compute instances delete web-demo private-vm --zone=us-central1-a --quiet
$ gcloud compute instance-groups managed delete app-mig --zone=us-central1-a --quiet
$ gcloud compute instance-templates delete app-template app-template-v2 web-template --quiet
$ gcloud compute health-checks delete app-health-check --quiet
$ gcloud compute firewall-rules delete allow-http allow-iap-ssh --quiet
$ gcloud compute images delete devops-tooling-v1 --quiet
Next Chapter → Networking