GCP for DevOps — Cloud CDN
Cloud CDN
Cloud CDN (Content Delivery Network) caches HTTP(S) content at Google’s globally distributed edge points of presence, reducing latency and offloading origin servers. It integrates with Cloud Load Balancing.
How Cloud CDN Works
Cloud CDN:
┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ User │───▶│ Edge PoP │───▶│ Origin │
│ (Sydney) │ │ (Sydney) │ │ (us-central1) │
│ │ │ │ │ │
│ │ │ Cache HIT ◀──│ │ Backend │
│ │◀───│ (fast!) │ │ Service │
│ │ │ │ │ │
│ │ │ Cache MISS ───│───▶│ Fetch origin │
│ │◀───│ Cache + serve │◀───│ Return data │
└──────────┘ └──────────────┘ └──────────────┘
Google has 180+ edge PoPs worldwide
Enable Cloud CDN
Cloud CDN requires a Global HTTP(S) Load Balancer:
# Enable CDN on a backend service
$ gcloud compute backend-services update my-backend \
--enable-cdn \
--global
# Enable CDN on a backend bucket (static content)
$ gcloud compute backend-buckets update my-bucket-backend \
--enable-cdn
Cache Policies
# Set cache policy on backend service
$ gcloud compute backend-services update my-backend \
--global \
--enable-cdn \
--cache-mode=CACHE_ALL_STATIC \
--default-ttl=3600 \
--max-ttl=86400 \
--client-ttl=3600
# Cache modes:
# USE_ORIGIN_HEADERS — Respect Cache-Control headers from origin
# CACHE_ALL_STATIC — Cache common static types (images, CSS, JS)
# FORCE_CACHE_ALL — Cache everything regardless of headers
Cache Key Configuration
# Customize cache key (include query string parameters)
$ gcloud compute backend-services update my-backend \
--global \
--enable-cdn \
--cache-key-include-query-string \
--cache-key-query-string-whitelist=page,sort
# Exclude host from cache key (multi-domain CDN)
$ gcloud compute backend-services update my-backend \
--global \
--enable-cdn \
--no-cache-key-include-host
Signed URLs and Cookies
Restrict access to CDN content:
# Generate a key for signed URLs
$ head -c 16 /dev/urandom | base64 | tr +/ -_ > cdn-key.txt
# Add the key to a backend service
$ gcloud compute backend-services add-signed-url-key my-backend \
--global \
--key-name=my-cdn-key \
--key-file=cdn-key.txt
# Generate a signed URL (valid for 1 hour)
$ gcloud compute sign-url \
"https://cdn.example.com/premium/video.mp4" \
--key-name=my-cdn-key \
--key-file=cdn-key.txt \
--expires-in=1h
Cache Invalidation
# Invalidate a specific path
$ gcloud compute url-maps invalidate-cdn-cache my-lb \
--path="/images/logo.png"
# Invalidate all content under a prefix
$ gcloud compute url-maps invalidate-cdn-cache my-lb \
--path="/static/*"
# Invalidate everything
$ gcloud compute url-maps invalidate-cdn-cache my-lb \
--path="/*"
Origin Headers for CDN
Set cache headers in your application:
from flask import Flask, make_response
app = Flask(__name__)
@app.route("/api/data")
def api_data():
response = make_response({"data": "cached response"})
response.headers["Cache-Control"] = "public, max-age=3600"
return response
@app.route("/api/user")
def api_user():
response = make_response({"user": "dynamic"})
response.headers["Cache-Control"] = "private, no-store"
return response
Monitoring CDN
# Check CDN hit ratio
$ gcloud logging read \
'resource.type="http_load_balancer" AND jsonPayload.cacheHit:*' \
--limit=20 \
--format="table(jsonPayload.cacheHit, httpRequest.requestUrl)"
Common Mistakes
| Mistake | Why It’s Wrong | Fix |
|---|---|---|
No Cache-Control headers |
CDN can’t cache content | Set explicit cache headers |
| Caching authenticated content | Serves other users’ data | Use private, no-store |
| Not invalidating on deploy | Stale content after update | Invalidate or use cache-busting |
| Too long TTL for dynamic | Users see stale data | Use short TTL or no-cache |
| No signed URLs for premium | Content freely accessible | Use signed URLs/cookies |
Quick Reference
| Command | Description |
|---|---|
gcloud compute backend-services update --enable-cdn |
Enable CDN |
gcloud compute url-maps invalidate-cdn-cache |
Invalidate cache |
gcloud compute sign-url |
Generate signed URL |
gcloud compute backend-services add-signed-url-key |
Add signing key |
Next → Cloud Armor