Road to DevFest Jakarta 2026 • Hands-on Workshop

Effortless Production Deployment with Google Cloud Run

Interactive developer workshop: achieving frictionless, zero-ops production deployments for Go and React monorepos on Google Cloud Run in Jakarta (asia-southeast2).

Compute Google Cloud Run (Serverless)
Region asia-southeast2 (Jakarta)
Services Go API + React Nginx SPA
Format Hands-on Lab & Deck
Agenda • Overview

Session Roadmap

How Google Cloud Run eliminates the operational friction of traditional Kubernetes and VM deployments across five core phases.

01. Foundations
GCP & Serverless Concepts

Core principles of serverless containers on GCP.

  • GCP Compute Spectrum
  • Scale-to-zero & cold starts
  • Concurrency multiplexing
  • Artifact Registry & IAM
02. Architecture
Go 1.24 & React Nginx

Monorepo services and containers.

  • Go 1.24 Distroless API
  • Vite React Nginx SPA
  • Dynamic PORT & 0.0.0.0
  • Graceful SIGTERM draining
03. Hands-on Labs
CLI Auth & Deployment

Step-by-step terminal execution.

  • gcloud auth & project setup
  • Deploy API & extract URL
  • Deploy Web with BACKEND_URL
  • One-click deploy.sh script
04. Automation & Observability
CI/CD, IaC & Telemetry

Automation, metrics & logging.

  • Cloud Build 5-step CI/CD
  • Terraform resource models
  • 4 Golden Signals & Metrics
  • Structured logs & Cloud Trace
05. Q&A
Discussion & Wrap-Up

Interactive discussion & recap.

  • Audience Q&A
  • Cost crossover trade-offs
  • Troubleshooting live bugs
  • Resource links & code repo
01. Foundation • GCP Compute Spectrum

Where Cloud Run Fits in Google Cloud

Comparing compute abstractions to select the optimal model for containerized web services.

Compute Engine
IaaS • Virtual Machines

Direct VM instances with full kernel & OS control.

  • Manual patching & OS updates
  • Always-on billing when idle
  • Scaling takes minutes per VM
  • Best for legacy, stateful apps
GKE
CaaS • Kubernetes Engine

Managed Kubernetes for complex multi-cluster microservices.

  • Full control over K8s APIs
  • Persistent disks & stateful sets
  • High cluster maintenance overhead
  • Pay for node pools & management
Cloud Run
Serverless Container

Fully managed environment for standard stateless containers.

  • Zero cluster ops: deploy any container
  • Scale-to-zero when idle ($0 cost)
  • Automatic sub-second scaling
  • Built-in HTTPS & domain routing
Cloud Functions
FaaS • Event Handlers

Single-purpose snippets invoked by HTTP or GCP pub/sub events.

  • Opinionated runtime constraints
  • Single concurrency per container
  • Harder to test locally in bulk
  • Best for async glue & background tasks
02. Foundation • Serverless Execution

How Cloud Run Executes Requests

Key runtime mechanics: request-driven lifecycle, horizontal scaling, and concurrency multiplexing.

Idle State
0 instances ($0 cost)
➔ HTTP req
Cold Start
<200ms Go binary boot
➔ up to 80 reqs
Multiplexing
Single container reuse
➔ load spike
Scale Out
1..N instances auto-balanced
➔ 15m idle
Scale to 0
Graceful termination
Concurrency vs Single FaaS

Unlike traditional FaaS where every single request requires its own container instance, Cloud Run multiplexes up to 80 concurrent requests per container instance by default.

Cold Starts vs Warm Traffic

After the initial container startup, incoming requests route to the warm instance with zero provisioning delay. Static Go binaries keep cold starts below 200 milliseconds.

Automatic Managed Ingress

Every deployed service receives an auto-provisioned https://*.a.run.app endpoint with managed Google SSL certificates, HTTP/2, and global Google Anycast ingress.

03. Foundation • GCP Building Blocks

Core Services in Our Deployment Pipeline

How Google Cloud projects, Artifact Registry, IAM policies, and regions interact.

Resource Hierarchy & Region
Project ID & asia-southeast2

All infrastructure belongs to a single target Project ID. Both services are co-located in Jakarta (asia-southeast2) for minimal latency and local data residency in Indonesia.

Artifact Registry
asia-southeast2-docker.pkg.dev

Google Cloud's managed OCI container registry. Images built by Cloud Build are pushed here and streamed into Cloud Run instances via Google's internal private network backbone.

IAM Security Model
roles/run.invoker & Service Accounts

Public access is granted by binding roles/run.invoker to allUsers. Containers run under an unprivileged non-root service account with minimal IAM scope.

04. Deep Dive • Architecture Topology

Monorepo Service Topology

Two decoupled, stateless container services deployed to Cloud Run in asia-southeast2.

Client Browser
Public HTTPS Traffic
➔ HTTPS GET /
roadto-jakarta-web
Alpine Nginx + Vite React SPA
➔ proxy /api/*
roadto-jakarta-api
Go 1.24 Distroless Non-Root
Frontend: apps/web

Multi-stage Nginx container serving compiled static assets.

  • Dynamic $PORT binding via envsubst at container boot
  • SPA history mode fallback: try_files $uri /index.html
  • Reverse proxies /api/* directly to backend $BACKEND_URL
  • Exposes GET /healthz returning HTTP 200
Backend: apps/api

Statically linked Go binary packaged into Google Distroless.

  • Sub-20MB image size with CGO_ENABLED=0
  • Purely stateless: scales to 0 and scales out horizontally
  • Binds strictly to 0.0.0.0:$PORT
  • Graceful shutdown intercepting SIGTERM / SIGINT
05. Deep Dive • Runtime Invariants

Cloud Run Runtime Invariants

Mandatory architectural requirements enforced by Google Cloud Run.

Dynamic PORT Variable

Cloud Run sets the PORT environment variable (default 8080).

  • Server must bind to 0.0.0.0, never 127.0.0.1
  • Binding to localhost causes probe failure and container crash
  • Nginx uses nginx.conf.template substituted at startup
Statelessness & Disk

Instances are ephemeral and scale to zero during periods of inactivity.

  • Never write permanent files to container filesystem
  • In-memory state is lost on scale-down or revision switch
  • Auto-scaling: 0 min instances, 10 max instances
SIGTERM Handling

Cloud Run sends SIGTERM before killing an instance.

  • 10-second termination grace period to drain active requests
  • Go intercepts signals via signal.NotifyContext
  • Executes server.Shutdown() cleanly
06. Deep Dive • Multi-Stage Containers

Optimized Multi-Stage Containerization

Minimal attack surface, small image footprints, and non-root execution.

Backend: apps/api/Dockerfile
# Stage 1: Build static Go binary
FROM golang:1.24-alpine AS builder
WORKDIR /app
COPY go.mod go.sum* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
    go build -ldflags="-w -s" -o /server ./cmd/server

# Stage 2: Distroless non-root runner
FROM gcr.io/distroless/static-debian12:nonroot
WORKDIR /
COPY --from=builder /server /server
EXPOSE 8080
USER nonroot:nonroot
ENTRYPOINT ["/server"]
Frontend: apps/web/Dockerfile
# Stage 1: Build React Vite SPA
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Nginx with dynamic PORT substitution
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf.template
CMD envsubst '$PORT $BACKEND_URL' < \
    /etc/nginx/conf.d/default.conf.template > \
    /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'
07. Hands-on Lab 01 • Setup & Authentication

Step 1–4: Google Cloud Authentication & Setup

Terminal setup: authenticate with GCP, configure target project and Jakarta region, and provision Artifact Registry.

Step 1 & 2: Login & Project Configuration
Terminal Execution
# 1. Authenticate with your Google account
gcloud auth login

# (Optional) Application Default Credentials for Terraform
gcloud auth application-default login

# 2. Configure target Project ID & Jakarta Region
gcloud projects list
export PROJECT_ID="YOUR_PROJECT_ID"
export REGION="asia-southeast2"

gcloud config set project "$PROJECT_ID"
gcloud config set run/region "$REGION"
Step 3 & 4: Enable APIs & Artifact Registry
Terminal Execution
# 3. Enable necessary Google Cloud APIs
gcloud services enable \
  run.googleapis.com \
  cloudbuild.googleapis.com \
  artifactregistry.googleapis.com \
  compute.googleapis.com

# 4. Create standard OCI Docker repository in Jakarta
gcloud artifacts repositories create roadto-jakarta \
  --repository-format=docker \
  --location="$REGION" \
  --description="Road to DevFest Jakarta Docker repo"

# Configure local Docker credential helper
gcloud auth configure-docker "${REGION}-docker.pkg.dev" --quiet
08. Hands-on Lab 02 • Deploying Services

Step 5–6: Deploying Go API & React SPA

Deploying the containerized backend from source, extracting its live URL, and injecting it into the frontend SPA.

Step 5: Deploy Go Backend API
Terminal Execution
# Deploy API from source with public ingress
gcloud run deploy roadto-jakarta-api \
  --source ./apps/api \
  --region "$REGION" \
  --platform managed \
  --allow-unauthenticated \
  --port 8080

# Extract live HTTPS URL and verify /healthz
API_URL=$(gcloud run services describe roadto-jakarta-api \
  --region "$REGION" --format='value(status.url)')
echo "Backend API: $API_URL"

curl -i "$API_URL/healthz"
curl -s "$API_URL/api/v1/event" | jq .
Step 6: Deploy React Frontend with BACKEND_URL
Terminal Execution
# Deploy Web SPA injecting live $API_URL
gcloud run deploy roadto-jakarta-web \
  --source ./apps/web \
  --region "$REGION" \
  --platform managed \
  --allow-unauthenticated \
  --port 8080 \
  --set-env-vars BACKEND_URL="$API_URL"

# Extract live Frontend URL and test end-to-end
WEB_URL=$(gcloud run services describe roadto-jakarta-web \
  --region "$REGION" --format='value(status.url)')
echo "Frontend: $WEB_URL"

curl -i "$WEB_URL/healthz"
curl -s "$WEB_URL/api/v1/event" | jq .
09. Hands-on Lab 03 • Script Automation

Turnkey Orchestration via deploy.sh

How the repository helper script automates project discovery, dependency ordering, and URL injection.

Automated Script Logic
  • Environment Pre-flight: Runs init to enable APIs and setup Artifact Registry.
  • Ordered Pipeline: Deploys apps/api first, extracts live URL, and injects BACKEND_URL into apps/web.
  • IAM Invoker Policy: Automatically binds roles/run.invoker to allUsers for public access.
Terminal Commands
# 1. Initialize APIs & Artifact Registry
./deploy/deploy.sh init

# 2. Deploy both API and Web in correct dependency order
./deploy/deploy.sh all

# Or deploy individually:
./deploy/deploy.sh api
./deploy/deploy.sh web

# Custom Project & Region override:
GCP_REGION=asia-southeast2 \
PROJECT_ID=my-gcp-project \
./deploy/deploy.sh all
10. Automation • Cloud Build CI/CD Pipeline

Google Cloud Build Automation

Fully automated serverless CI/CD pipeline defined in deploy/cloudbuild.yaml.

Step 1
Build & Push API
➔
Step 2
Deploy API Service
➔
Step 3
Extract API URL
➔
Step 4
Build & Push Web
➔
Step 5
Deploy Web Service
GitHub Actions & CLI Invocation
# Automatic: git push to main runs .github/workflows/deploy.yml
# Manual: submit build directly to Cloud Build
gcloud builds submit \
  --config deploy/cloudbuild.yaml \
  --substitutions=\
_REGION="asia-southeast2",\
_REPO_NAME="roadto-jakarta"
Operational Benefits
  • No local Docker daemon required on developer workstations
  • Build artifacts cached and tagged in Google Artifact Registry
  • Automated via GitHub Actions (.github/workflows/deploy.yml) on push
  • Zero-downtime rolling revision deployment with auto-rollback
11. Automation • Infrastructure as Code

Terraform & Knative Declarative Manifests

Managing Cloud Run services declaratively for version control and compliance.

Terraform: deploy/terraform/main.tf
resource "google_cloud_run_v2_service" "api" {
  name     = var.api_service_name
  location = var.region

  template {
    scaling {
      min_instance_count = 0
      max_instance_count = 10
    }
    containers {
      image = var.api_image
      resources {
        limits = { cpu = "1", memory = "256Mi" }
      }
      liveness_probe {
        http_get { path = "/healthz" }
      }
    }
  }
}
Knative Manifest: deploy/api-service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: roadto-jakarta-api
spec:
  template:
    spec:
      containers:
      - image: asia-southeast2-docker.pkg.dev/...
        resources:
          limits:
            cpu: 1000m
            memory: 256Mi
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
12. Observability • Metrics & Golden Signals

Cloud Monitoring: The 4 Golden Signals

Zero-instrumentation telemetry emitted automatically by Google Cloud Run without custom agents or Prometheus sidecars.

1. Latency
p50, p95, p99 distribution

Measures request duration from Google Anycast ingress edge to client finish.

  • Metric: run.googleapis.com/request_latencies
  • Differentiates cold-start spikes from warm hits
  • Target: <50ms p95 on warm Go API routes
2. Traffic
Request Rate & Status Breakdown

Real-time request throughput across active service revisions.

  • Metric: run.googleapis.com/request_count
  • Group by response codes: 2xx, 4xx, and 5xx
  • Monitors traffic routing across active revisions
3. Errors
5xx Rates & Error Reporting

Automatic tracking of failed requests and runtime exceptions.

  • Alerting threshold: 5xx rate > 1% for 5 mins
  • Google Cloud Error Reporting groups Go panics
  • Notifications routed to Slack, Email & PagerDuty
4. Saturation
CPU, Memory & Concurrency

Resource consumption against defined container limits.

  • Metric: container/memory/utilizations (256MiB limit)
  • Metric: container/cpu/utilizations (1 vCPU limit)
  • Live instance count: autoscale from 0 to 10 instances
13. Observability • Structured Logs, Tracing & Probes

Structured Logging, Cloud Trace & Probes

Correlating distributed requests across microservices, querying Logs Explorer, and enforcing container health.

Structured JSON Logging

All stdout/stderr is automatically parsed into Cloud Logging:

Go JSON Log Format
{
  "severity": "INFO",
  "message": "Handled RSVP request",
  "timestamp": "2026-10-24T10:00:00Z",
  "logging.googleapis.com/trace":
    "projects/PROJECT_ID/traces/TRACE_ID",
  "httpRoute": "/api/v1/rsvp"
}
Logs Explorer Query
resource.type="cloud_run_revision"
AND resource.labels.service_name="roadto-jakarta-api"
AND severity>=WARNING
Distributed Cloud Trace

Propagate trace context headers across microservice boundaries:

Client Browser
X-Cloud-Trace-Context header
▼ reverse-proxy
roadto-jakarta-web (Nginx)
Passes trace to $BACKEND_URL
▼ /api/v1/event
roadto-jakarta-api (Go)
Correlates handler spans & SQL queries

Provides waterfall latency breakdown without manual APM agent installation.

Health Check Probes & Smoke Tests

Container verification contract via GET /healthz:

  • Startup Probe: Holds user traffic during container boot (period 5s, 3 retries). Prevents HTTP 502s.
  • Liveness Probe: Periodically verifies container responsiveness; restarts deadlocked instances.
Live Post-Deploy Verification
# Check API health & live JSON
curl -i https://$API_URL/healthz
curl -s https://$API_URL/api/v1/event | jq .

# Check Frontend SPA & Nginx probe
curl -i https://$WEB_URL/healthz
curl -i https://$WEB_URL/
14. Summary • Production Readiness Checklist

Production Deployment Checklist

Key architecture principles and command reference for Cloud Run services.

Architecture Guarantees
  • Zero Cost When Idle: Scales to 0 instances when inactive with sub-second resumption.
  • Secure Container Baseline: Non-root distroless container for the API; unprivileged Nginx for the Web.
  • Dynamic Port Contract: Both services strictly honor dynamic $PORT listening on 0.0.0.0.
  • Local Latency: Deployed in asia-southeast2 (Jakarta) for rapid regional response times.
Quick Command Cheat Sheet
• Setup: ./deploy/deploy.sh init
• Deploy All: ./deploy/deploy.sh all
• CI/CD: gcloud builds submit --config deploy/cloudbuild.yaml
• IaC: terraform -chdir=deploy/terraform apply
• Verify: curl -i https://<SERVICE_URL>/healthz
15. Discussion • Q&A & Hands-on Troubleshooting

Q&A & Technical Discussion

Open floor for audience questions, architecture trade-offs, and implementation details.

Discussion Topics
  • Min Instances vs Cost: Keeping 1 warm instance to eliminate cold starts on critical paths.
  • Secret Management: Ingesting API keys via GCP Secret Manager runtime mounts.
  • VPC Connectors: Connecting Cloud Run privately to Cloud SQL or Memorystore.
  • Cloud Run vs GKE: At what scale does dedicated GKE become more cost-effective?
Repository Resources

All source code and manifests are available in this repository:

• Backend API: apps/api/
• Frontend SPA: apps/web/
• CLI Pipeline: deploy/deploy.sh
• CI/CD Config: deploy/cloudbuild.yaml
• Terraform: deploy/terraform/
Thank You!

Road to DevFest Jakarta 2026. Deploying modern web apps and APIs to Google Cloud Run in asia-southeast2.

Presentation Complete

Slide Overview