LAB19_GCP_Static Delivery: Cloud CDN caching a Cloud Storage Bucket

Static Delivery: Cloud CDN caching a Cloud Storage Bucket

☁ GCP 🟢 Beginner Cloud CDN Backend Bucket Load Balancing

Scenario

You have a folder of static frontend assets (images, CSS, JS) that need to be delivered to global users with extremely low latency. Instead of serving them directly from a Cloud Storage bucket in one region, you will place a Global HTTP Load Balancer with Cloud CDN in front of the bucket.

Your Objectives
  • Create a google_storage_bucket for your assets, and grant `allUsers` the `roles/storage.objectViewer` role to make it public.
  • Create a google_compute_backend_bucket mapped to the storage bucket, and set enable_cdn = true.
  • Create the Load Balancing frontend: google_compute_url_map, google_compute_target_http_proxy, and google_compute_global_forwarding_rule.
  • Output the global IP address of the CDN.

Additional Context

Backend Buckets vs Backend Services: In GCP Load Balancing, if you are routing traffic to VMs or Cloud Run, you use a `backend_service` (which requires a health check). If you are routing traffic to an S3/GCS bucket, you use a special `backend_bucket` resource (which natively integrates with Cloud Storage and requires no health check).

Enabling CDN: Once traffic hits the `backend_bucket`, if `enable_cdn = true`, Google's edge nodes intercept the request, check their local cache, and only forward the request down to the actual Cloud Storage bucket if it's a cache miss.

variables.tf

variable "project_id" { type = string }
variable "gcp_region" { type = string; default = "us-central1" }

main.tf

provider "google" {
  project = var.project_id
}

resource "random_id" "suffix" { byte_length = 4 }

# 1. The underlying Storage Bucket
resource "google_storage_bucket" "assets" {
  name          = "cdn-assets-${random_id.suffix.hex}"
  location      = "US" # multi-region
  force_destroy = true
}

# Make bucket contents public (required for Backend Buckets without complex signed URLs)
resource "google_storage_bucket_iam_member" "public_read" {
  bucket = google_storage_bucket.assets.name
  role   = "roles/storage.objectViewer"
  member = "allUsers"
}

# 2. Add an index.html so there's something to serve
resource "google_storage_bucket_object" "index" {
  name    = "index.html"
  bucket  = google_storage_bucket.assets.name
  content = "

Hello from Cloud CDN Edge Cache!

" content_type = "text/html" } # 3. The Backend Bucket (ties the bucket to the Load Balancer, enables CDN cache) resource "google_compute_backend_bucket" "cdn_backend" { name = "assets-backend-bucket" bucket_name = google_storage_bucket.assets.name enable_cdn = true } # 4. The URL Map (routes requests to the backend bucket) resource "google_compute_url_map" "cdn_map" { name = "cdn-url-map" default_service = google_compute_backend_bucket.cdn_backend.id } # 5. Target Proxy & Global Forwarding Rule (The frontend IP) resource "google_compute_target_http_proxy" "http_proxy" { name = "cdn-http-proxy" url_map = google_compute_url_map.cdn_map.id } resource "google_compute_global_forwarding_rule" "http_rule" { name = "cdn-frontend-ip" target = google_compute_target_http_proxy.http_proxy.id port_range = "80" load_balancing_scheme = "EXTERNAL_MANAGED" }

outputs.tf

output "cdn_ip_address" {
  value = google_compute_global_forwarding_rule.http_rule.ip_address
}

Workflow Commands

terraform init
terraform apply -var="project_id=my-gcp-project-123"

# It takes ~5 minutes for GCP Load Balancers to propagate DNS and routes globally.
# Then curl the specific asset:
curl http://$(terraform output -raw cdn_ip_address)/index.html

# Look for x-goog-cache status headers
curl -I http://$(terraform output -raw cdn_ip_address)/index.html

terraform destroy -var="project_id=my-gcp-project-123"
✓ Expected Output After Apply
Apply complete! Resources: 7 added, 0 changed, 0 destroyed.

Outputs:

cdn_ip_address = "34.111.12.34"