Trust is earned, not given

A different perspective

2020-05-19 · Projects

DevOps on Google Cloud, part 2: Compute — Cloud Run, GKE, and Cloud Functions

Part 2from the DevOps on Google Cloud series · 6 parts in all

Part 2: where code runs on GCP. This is the cloud where "just give me a container and an HTTPS endpoint" is a first-class product rather than a bolt-on — Cloud Run — and where Kubernetes itself was born (GKE). Our companies split across all three tiers.

Cloud Run: the PaaS that respects containers

Deploy any container listening on $PORT; get HTTPS, autoscaling (including to zero), and request-based billing. No cluster to create, no YAML to worship:

# Build with Cloud Build (or Docker locally) and deploy in one command
gcloud builds submit --tag us-central1-docker.pkg.dev/maplecart/web/web:v42
gcloud run deploy maplecart-web \
  --image us-central1-docker.pkg.dev/maplecart/web/web:v42 \
  --region us-central1 \
  --service-account [email protected] \  # identity, not keys
  --set-env-vars DB_HOST=10.0.2.3 \
  --min-instances 1 --max-instances 20 \       # keep one warm; cap the spend
  --cpu 1 --memory 512Mi \
  --ingress internal-and-cloud-load-balancing   # reachable only via our LB

# Concurrency: Cloud Run's superpower - up to 1000 requests PER instance
gcloud run services update maplecart-web --concurrency 80
# (AWS Lambda and Azure Functions handle exactly ONE request per instance -
#  Cloud Run's model means a traffic spike needs fewer instances, less money)

MapleCart and NewsGrid both run here. NewsGrid especially: scale-to-zero makes idle weekends free, and the viral spike just raises instance count — with per-instance concurrency, Cloud Run absorbs bursts that would need 10x the instances of a function-per- request platform.

GKE: Kubernetes as it was meant to be

FleetView runs a dozen microservices with service-to-service auth and per-service scaling — GKE territory. Choose Autopilot mode: Google manages nodes, capacity, and security patches; you write workloads:

gcloud container clusters create-auto fleetview \
  --region us-central1 \                        # regional cluster: 3 zones, no extra work
  --enable-private-nodes                        # pods without public IPs

# A workload with Workload Identity (the pod BECOMES a service account):
apiVersion: apps/v1
kind: Deployment
metadata: { name: ingest-api }
spec:
  replicas: 3
  template:
    spec:
      serviceAccountName: ingest-api            # mapped to a GCP SA by annotation
      containers:
      - name: api
        image: us-docker.pkg.dev/fleetview/api/ingest:v9
        resources: { requests: { cpu: 250m, memory: 512Mi } }

Workload Identity deserves the highlight: the pod's service account is a real GCP identity — no node-level credential sharing, no secrets in environment variables. It is the cleanest workload-identity story of the three clouds.

Cloud Functions: the event tier

# 2nd-gen functions ARE Cloud Run under the hood - one platform, two ergonomics.
import functions_framework
from PIL import Image

@functions_framework.http
def resize(request):
    # HTTP-triggered image resizer for NewsGrid. Runs on Cloud Run infra.
    from google.cloud import storage
    client = storage.Client()                  # credentials from the SA, as always
    bucket = client.bucket("newsgrid-media")
    blob = bucket.get_blob(request.args["path"])
    if not blob or not blob.name.lower().endswith((".jpg", ".png")):
        return ("not found", 404)
    local = "/tmp/img"; blob.download_to_filename(local)
    im = Image.open(local); im.thumbnail((800, 800)); im.save(local, optimize=True)
    bucket.blob(f"thumbs/{blob.name}").upload_from_filename(local)
    return "ok"

The decision table

Cloud RunGKECloud Functions
You managecontainerworkloads (Autopilot)function
Scale to zeroyesno (Autopilot)yes
Concurrencyup to 1000/instanceapp-defined1/instance
Fitweb/API defaultmicroservice fleetssingle events

Next: data — Cloud SQL, Firestore, and the real-time differentiator.