GCP for DevOps — Practice Projects Exercises

4 minute read

Practice Exercises — Practice Projects

Exercise 1: Extend the Production VPC

Add a third subnet for a GKE cluster with secondary IP ranges for Pods and Services.

  1. Add a gke-subnet (10.0.3.0/24) to the VPC module
  2. Configure secondary ranges: pods (10.4.0.0/14), services (10.8.0.0/20)
  3. Add a firewall rule allowing GKE master access (port 443) from the GKE control plane CIDR
Show Answer
# Add to modules/vpc/main.tf
resource "google_compute_subnetwork" "gke" {
  name          = "${var.vpc_name}-gke"
  ip_cidr_range = "10.0.3.0/24"
  region        = var.region
  network       = google_compute_network.vpc.id

  secondary_ip_range {
    range_name    = "pods"
    ip_cidr_range = "10.4.0.0/14"
  }

  secondary_ip_range {
    range_name    = "services"
    ip_cidr_range = "10.8.0.0/20"
  }

  private_ip_google_access = true
}

resource "google_compute_firewall" "allow_gke_master" {
  name    = "${var.vpc_name}-allow-gke-master"
  network = google_compute_network.vpc.id

  allow {
    protocol = "tcp"
    ports    = ["443", "10250"]
  }

  source_ranges = ["172.16.0.0/28"]  # GKE master CIDR
  target_tags   = ["gke-node"]
}
$ terraform plan
Plan: 2 to add, 0 to change, 0 to destroy.

$ terraform apply -auto-approve
Apply complete! Resources: 2 added.

Exercise 2: Add Health Check Endpoint to the CI/CD App

Enhance the GKE Autopilot application with a /ready endpoint that checks database connectivity.

  1. Add a /ready endpoint that returns 503 if the database is unreachable
  2. Update the Kubernetes deployment to use /ready for readinessProbe
  3. Keep /health as the livenessProbe (always returns 200)
Show Answer
// Add to main.go
http.HandleFunc("/ready", func(w http.ResponseWriter, r *http.Request) {
    // Check database connectivity
    dbHost := os.Getenv("DB_HOST")
    if dbHost == "" {
        // No DB configured, just report ready
        w.WriteHeader(http.StatusOK)
        fmt.Fprint(w, "READY")
        return
    }
    
    conn, err := net.DialTimeout("tcp", dbHost+":5432", 2*time.Second)
    if err != nil {
        w.WriteHeader(http.StatusServiceUnavailable)
        fmt.Fprintf(w, "NOT READY: %v", err)
        return
    }
    conn.Close()
    w.WriteHeader(http.StatusOK)
    fmt.Fprint(w, "READY")
})
# Update k8s/deployment.yaml probes
livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10
readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 3
  periodSeconds: 5
  failureThreshold: 3

Exercise 3: Add Authentication to the Serverless API

Secure the REST API with API key authentication via API Gateway.

  1. Add API key validation to the OpenAPI spec
  2. Create an API key in the Console
  3. Test that requests without the API key are rejected
Show Answer
# Update openapi-spec.yaml — add security definition
swagger: '2.0'
info:
  title: Items API
  version: '1.0'
schemes:
  - https
produces:
  - application/json
securityDefinitions:
  api_key:
    type: apiKey
    name: x-api-key
    in: header
security:
  - api_key: []
paths:
  /api/items:
    get:
      summary: List all items
      operationId: listItems
      x-google-backend:
        address: https://items-api-abc123-uc.a.run.app
      security:
        - api_key: []
      responses:
        '200':
          description: A list of items
# Create a new API config with the updated spec
$ gcloud api-gateway api-configs create items-config-v2 \
    --api=items-api \
    --openapi-spec=openapi-spec.yaml

# Update the gateway
$ gcloud api-gateway gateways update items-gateway \
    --api=items-api \
    --api-config=items-config-v2 \
    --location=us-central1

# Test without API key (should fail)
$ curl -i https://items-gateway-abc123.uc.gateway.dev/api/items
HTTP/2 401
{"message": "UNAUTHENTICATED: Method doesn't allow unregistered callers"}

# Test with API key (should work)
$ curl -H "x-api-key: YOUR_API_KEY" \
    https://items-gateway-abc123.uc.gateway.dev/api/items
[{"id": "abc123", "name": "Widget"}]

Exercise 4: Add Terraform Modules to the 3-Tier Project

Refactor the 3-tier architecture into reusable Terraform modules.

  1. Create a modules/cloudsql module for the database layer
  2. Create a modules/mig module for the compute layer
  3. Use both modules from the root main.tf
Show Answer
# modules/cloudsql/variables.tf
variable "instance_name" { type = string }
variable "region" { type = string }
variable "network_id" { type = string }
variable "db_name" { type = string }
variable "db_user" { type = string }
variable "db_password" { type = string; sensitive = true }
variable "tier" { type = string; default = "db-custom-2-4096" }

# modules/cloudsql/main.tf
resource "google_sql_database_instance" "main" {
  name             = var.instance_name
  database_version = "POSTGRES_15"
  region           = var.region
  settings {
    tier = var.tier
    ip_configuration {
      ipv4_enabled    = false
      private_network = var.network_id
    }
    backup_configuration {
      enabled                        = true
      point_in_time_recovery_enabled = true
    }
  }
  deletion_protection = false
}

resource "google_sql_database" "db" {
  name     = var.db_name
  instance = google_sql_database_instance.main.name
}

resource "google_sql_user" "user" {
  name     = var.db_user
  instance = google_sql_database_instance.main.name
  password = var.db_password
}

# modules/cloudsql/outputs.tf
output "private_ip" {
  value = google_sql_database_instance.main.private_ip_address
}
# Root main.tf using modules
module "database" {
  source        = "./modules/cloudsql"
  instance_name = "app-db"
  region        = var.region
  network_id    = google_compute_network.main.id
  db_name       = "appdb"
  db_user       = "appuser"
  db_password   = var.db_password
}

Exercise 5: Add SLO Burn Rate Alerts to the Monitoring System

Create multi-window burn rate alerts for a 99.9% availability SLO.

  1. Create a fast burn alert (14.4x burn rate over 1 hour, confirmed over 5 minutes)
  2. Create a slow burn alert (3x burn rate over 1 day, confirmed over 6 hours)
  3. Route fast burn to PagerDuty, slow burn to Slack
Show Answer
# Fast burn alert (pages on-call immediately)
$ gcloud alpha monitoring policies create \
    --display-name="SLO Fast Burn - Page" \
    --condition-display-name="14.4x burn rate (1h window)" \
    --condition-filter='select_slo_burn_rate("projects/my-project/services/items-api-service/serviceLevelObjectives/xyz", "60m")' \
    --condition-threshold-value=14.4 \
    --condition-threshold-comparison=COMPARISON_GT \
    --condition-threshold-duration=300s \
    --notification-channels="projects/my-project/notificationChannels/pagerduty-channel" \
    --documentation='FAST BURN: Error budget depleting rapidly. 
    At this rate, monthly budget exhausts in ~3 days.
    Immediate investigation required.'

# Slow burn alert (notifies team in Slack)
$ gcloud alpha monitoring policies create \
    --display-name="SLO Slow Burn - Notify" \
    --condition-display-name="3x burn rate (1d window)" \
    --condition-filter='select_slo_burn_rate("projects/my-project/services/items-api-service/serviceLevelObjectives/xyz", "1440m")' \
    --condition-threshold-value=3 \
    --condition-threshold-comparison=COMPARISON_GT \
    --condition-threshold-duration=21600s \
    --notification-channels="projects/my-project/notificationChannels/slack-channel" \
    --documentation='SLOW BURN: Error budget depleting steadily.
    At this rate, monthly budget exhausts in ~10 days.
    Schedule investigation this sprint.'

Burn rate reference table:

Window Burn Rate Budget Consumed Time to Exhaust
1 hour 14.4x 2% ~3 days
6 hours 6x 5% ~5 days
1 day 3x 10% ~10 days
3 days 1x 10% ~30 days

Cleanup

# Destroy all Terraform resources from projects 1 and 4
$ cd terraform-3tier && terraform destroy -auto-approve
$ cd ../gcp-production-vpc && terraform destroy -auto-approve

# Delete GKE cluster from project 2
$ gcloud container clusters delete gke-autopilot-dev --region=us-central1 --quiet

# Delete Cloud Run and API Gateway from project 3
$ gcloud run services delete items-api --region=us-central1 --quiet
$ gcloud api-gateway gateways delete items-gateway --location=us-central1 --quiet

# Delete monitoring resources from project 5
$ gcloud monitoring dashboards delete DASHBOARD_ID
$ gcloud alpha monitoring policies delete POLICY_ID

Next Chapter → Next Steps

Updated: