Specialized skill for building production-ready serverless applications on GCP. Covers Cloud Run services (containerized), Cloud Run Functions (event-driven), cold start optimization, and event-driven architecture with Pub/Sub.
Specialized skill for building production-ready serverless applications on GCP. Covers Cloud Run services (containerized), Cloud Run Functions (event-driven), cold start optimization, and event-driven architecture with Pub/Sub.
risk
unknown
source
vibeship-spawner-skills (Apache 2.0)
date_added
"2026-02-27T00:00:00.000Z"
GCP Cloud Run
Specialized skill for building production-ready serverless applications on GCP.
Covers Cloud Run services (containerized), Cloud Run Functions (event-driven),
cold start optimization, and event-driven architecture with Pub/Sub.
Principles
Cloud Run for containers, Functions for simple event handlers
Optimize for cold starts with startup CPU boost and min instances
Set concurrency based on workload (start with 8, adjust)
Memory includes /tmp filesystem - plan accordingly
Use VPC Connector only when needed (adds latency)
Containers should start fast and be stateless
Handle signals gracefully for clean shutdown
Patterns
Cloud Run Service Pattern
Containerized web service on Cloud Run
When to use: Web applications and APIs,Need any runtime or library,Complex services with multiple endpoints,Stateless containerized workloads
# Dockerfile - Multi-stage build for smaller image
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:20-slim
WORKDIR /app
# Copy only production dependencies
COPY --from=builder /app/node_modules ./node_modules
COPY src ./src
COPY package.json ./
# Cloud Run uses PORT env variable
ENV PORT=8080
EXPOSE 8080
# Run as non-root user
USER node
CMD ["node", "src/index.js"]
When to use: Latency-sensitive applications,User-facing APIs,High-traffic services
1. Enable Startup CPU Boost
gcloud run deploy my-service \
--cpu-boost \
--region us-central1
2. Set Minimum Instances
gcloud run deploy my-service \
--min-instances 1 \
--region us-central1
3. Optimize Container Image
# Use distroless for minimal image
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY src ./src
CMD ["src/index.js"]
When to use: Need to optimize instance utilization,Handle traffic spikes efficiently,Reduce cold starts
Understanding Concurrency
# Default concurrency is 80# Adjust based on your workload# For I/O-bound workloads (most web apps)
gcloud run deploy my-service \
--concurrency 80 \
--cpu 1
# For CPU-bound workloads
gcloud run deploy my-service \
--concurrency 1 \
--cpu 1
# For memory-intensive workloads
gcloud run deploy my-service \
--concurrency 10 \
--memory 2Gi
Node.js Concurrency
// Node.js is single-threaded but handles I/O concurrently// Use async/await for all I/O operations// GOOD - async I/O
app.get('/api/data', async (req, res) => {
const [users, products] = awaitPromise.all([
fetchUsers(),
fetchProducts()
]);
res.json({ users, products });
});
// BAD - blocking operation
app.get('/api/compute', (req, res) => {
const result = heavyCpuOperation(); // Blocks other requests!
res.json(result);
});
Situation: Writing files to /tmp directory in Cloud Run
Symptoms:
Container killed with OOM error.
Memory usage spikes unexpectedly.
File operations cause container restarts.
"Container memory limit exceeded" in logs.
Why this breaks:
Cloud Run uses an in-memory filesystem for /tmp. Any files written
to /tmp consume memory from your container's allocation.
Common scenarios:
Downloading files temporarily
Creating temp processing files
Libraries caching to /tmp
Large log buffers
A 512MB container that downloads a 200MB file to /tmp only has
~300MB left for the application.
Recommended fix:
Calculate memory including /tmp usage
# cloudbuild.yamlsteps:-name:'gcr.io/cloud-builders/gcloud'args:-'run'-'deploy'-'my-service'-'--memory=1Gi'# Include /tmp overhead-'--image=gcr.io/$PROJECT_ID/my-service'
Stream instead of buffering
# BAD - buffers entire file in /tmpdefprocess_large_file(bucket_name, blob_name):
blob = bucket.blob(blob_name)
blob.download_to_filename('/tmp/large_file')
withopen('/tmp/large_file', 'rb') as f:
process(f.read())
# GOOD - stream processingdefprocess_large_file(bucket_name, blob_name):
blob = bucket.blob(blob_name)
with blob.open('rb') as f:
for chunk initer(lambda: f.read(8192), b''):
process_chunk(chunk)
Use Cloud Storage for large files
from google.cloud import storage
defprocess_with_gcs(bucket_name, input_blob, output_blob):
client = storage.Client()
bucket = client.bucket(bucket_name)
# Process directly to/from GCS
input_blob = bucket.blob(input_blob)
output_blob = bucket.blob(output_blob)
with input_blob.open('rb') as reader:
with output_blob.open('wb') as writer:
for chunk initer(lambda: reader.read(65536), b''):
processed = transform(chunk)
writer.write(processed)
Situation: Setting concurrency to 1 for request isolation
Symptoms:
Auto-scaling creates many container instances.
High latency during traffic spikes.
Increased cold starts.
Higher costs from more instances.
Why this breaks:
Setting concurrency to 1 means each container handles only one
request at a time. During traffic spikes:
100 concurrent requests = 100 container instances
Each instance has cold start overhead
More instances = higher costs
Scaling takes time, requests queue up
This should only be used when:
Processing is truly single-threaded
Memory-heavy per-request processing
Using thread-unsafe libraries
Recommended fix:
Set appropriate concurrency
# For I/O-bound workloads (most web apps)
gcloud run deploy my-service \
--concurrency=80 \
--max-instances=100
# For CPU-bound workloads
gcloud run deploy my-service \
--concurrency=4 \
--cpu=2
# Only use 1 when absolutely necessary
gcloud run deploy my-service \
--concurrency=1 \
--max-instances=1000 # Be prepared for many instances
Node.js - use async properly
// With high concurrency, ensure async operationsconst express = require('express');
const app = express();
app.get('/api/data', async (req, res) => {
// All I/O should be asyncconst data = awaitfetchFromDatabase();
const enriched = awaitenrichData(data);
res.json(enriched);
});
// Concurrency 80+ is safe for async I/O workloads
Python - use async framework
from fastapi import FastAPI
import asyncio
import httpx
app = FastAPI()
@app.get("/api/data")asyncdefget_data():
# Async I/O allows high concurrencyasyncwith httpx.AsyncClient() as client:
response = await client.get("https://api.example.com/data")
return response.json()
# Concurrency 80+ safe with async framework
Situation: Running background tasks or processing between requests
Symptoms:
Background tasks run extremely slowly.
Scheduled work doesn't complete.
Metrics collection fails.
Connection keep-alive breaks.
Why this breaks:
By default, Cloud Run throttles CPU to near-zero when not actively
handling a request. This is "CPU only during requests" mode.
Affected operations:
Background threads
Connection pool maintenance
Metrics/telemetry emission
Scheduled tasks within container
Cleanup operations after response
Recommended fix:
Enable CPU always allocated
# CPU allocated even outside requests
gcloud run deploy my-service \
--cpu-throttling=false \
--min-instances=1
# Note: This increases costs but enables background work
Use startup CPU boost for initialization
# Boost CPU during cold start only
gcloud run deploy my-service \
--cpu-boost \
--cpu-throttling=true# Default, throttle after request
# Move heavy processing to separate servicesteps:# Main service - responds quickly-name:'gcr.io/cloud-builders/gcloud'args: ['run', 'deploy', 'api-service',
'--cpu-throttling=true']
# Worker service - processes messages-name:'gcr.io/cloud-builders/gcloud'args: ['run', 'deploy', 'worker-service',
'--cpu-throttling=false',
'--min-instances=1']
VPC Connector 10-Minute Idle Timeout
Severity: MEDIUM
Situation: Cloud Run service connecting to VPC resources
Symptoms:
Connection errors after period of inactivity.
"Connection reset" or "Connection refused" errors.
Sporadic failures to VPC resources.
Database connections drop unexpectedly.
Why this breaks:
Cloud Run's VPC connector has a 10-minute idle timeout on connections.
If a connection is idle for 10 minutes, it's silently closed.
Affects:
Database connection pools
Redis connections
Internal API connections
Any persistent VPC connection
Recommended fix:
Configure connection pool with keep-alive
# SQLAlchemy with connection recyclingfrom sqlalchemy import create_engine
engine = create_engine(
DATABASE_URL,
pool_size=5,
max_overflow=2,
pool_recycle=300, # Recycle connections every 5 minutes
pool_pre_ping=True# Validate connection before use
)
Situation: Deploying containers with slow initialization
Symptoms:
Deployment fails with "Container failed to start".
Service never becomes healthy.
"Revision failed to become ready" errors.
Works locally but fails on Cloud Run.
Why this breaks:
Cloud Run expects your container to start listening on PORT within
4 minutes (240 seconds). If it doesn't, the instance is killed.
Common causes:
Heavy framework initialization (ML models, etc.)
Waiting for external dependencies at startup
Large dependency loading
Database migrations on startup
Recommended fix:
Enable startup CPU boost
gcloud run deploy my-service \
--cpu-boost \
--startup-cpu-boost
Lazy initialization
from functools import lru_cache
from fastapi import FastAPI
app = FastAPI()
# Don't load at import time
model = None@lru_cache()defget_model():
global model
if model isNone:
# Load on first request, not at startup
model = load_heavy_model()
return model
@app.get("/predict")asyncdefpredict(data: dict):
model = get_model() # Loads on first call onlyreturn model.predict(data)
# Startup is fast - model loads on first request
Start listening immediately
import asyncio
from fastapi import FastAPI
import uvicorn
app = FastAPI()
# Global state for async initialization
initialized = asyncio.Event()
@app.on_event("startup")asyncdefstartup():
# Start background initialization
asyncio.create_task(async_init())
asyncdefasync_init():
# Heavy initialization happens after server startsawait load_models()
await warm_up_connections()
initialized.set()
@app.get("/ready")asyncdefready():
ifnot initialized.is_set():
raise HTTPException(503, "Still initializing")
return {"status": "ready"}
@app.get("/health")asyncdefhealth():
# Always respond - health check passesreturn {"status": "healthy"}
Use multi-stage builds
# Build stage - slow
FROM python:3.11 as builder
WORKDIR /app
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt
# Runtime stage - fast startup
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /wheels /wheels
RUN pip install --no-cache /wheels/* && rm -rf /wheels
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
Run migrations separately
# Don't migrate on startup - use Cloud Build
steps:
# Run migrations first
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
args:
- '-c'
- |
gcloud run jobs execute migrate-job --wait# Then deploy
- name: 'gcr.io/cloud-builders/gcloud'
args: ['run', 'deploy', 'my-service', ...]
Second Generation Execution Enprojectnment Differences
Severity: MEDIUM
Situation: Migrating to or using Cloud Run second-gen execution enprojectnment
Symptoms:
Network behavior changes.
Different syscall support.
File system behavior differences.
Container behaves differently than in first-gen.
Why this breaks:
Cloud Run's second-generation execution enprojectnment uses a different
sandbox (gVisor) with different characteristics:
More Linux syscalls supported
Full /proc and /sys access
Different network stack
No automatic HTTPS redirect
Different tmp filesystem behavior
Recommended fix:
Explicitly set execution enprojectnment
# First generation (legacy)
gcloud run deploy my-service \
--execution-enprojectnment=gen1
# Second generation (recommended for most)
gcloud run deploy my-service \
--execution-enprojectnment=gen2
# GPUs only available in second-gen
gcloud run deploy ml-service \
--execution-enprojectnment=gen2 \
--gpu=1 \
--gpu-type=nvidia-l4
Check execution enprojectnment
import os
defget_execution_enprojectnment():
# Second-gen has different /proc structuretry:
withopen('/proc/version', 'r') as f:
version = f.read()
if'gVisor'in version:
return'gen2'except:
passreturn'gen1'
Request Timeout Configuration Mismatch
Severity: MEDIUM
Situation: Long-running requests or background processing
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
@app.get("/large-report")asyncdeflarge_report():
asyncdefgenerate():
for chunk in process_large_data():
yield chunk
return StreamingResponse(generate(), media_type="text/plain")
Validation Checks
Hardcoded GCP Credentials
Severity: ERROR
GCP credentials must never be hardcoded in source code
Message: Hardcoded GCP service account credentials. Use Secret Manager or Workload Identity.
GCP API Key in Source Code
Severity: ERROR
API keys should use Secret Manager
Message: Hardcoded GCP API key. Use Secret Manager.
Credentials JSON File in Repository
Severity: ERROR
Service account JSON files should not be in source control
Message: Credentials file detected. Add to .gitignore and use Secret Manager.
Running as Root User
Severity: WARNING
Containers should not run as root for security
Message: Dockerfile runs as root. Add USER directive for security.
Missing Health Check in Dockerfile
Severity: INFO
Cloud Run uses HTTP health checks, Dockerfile HEALTHCHECK is optional
Message: No HEALTHCHECK in Dockerfile. Cloud Run uses its own health checks.
Hardcoded Port in Application
Severity: WARNING
Port should come from PORT enprojectnment variable
Message: Hardcoded port. Use PORT enprojectnment variable for Cloud Run.
Large File Writes to /tmp
Severity: WARNING
/tmp uses container memory, large writes can cause OOM
Message: /tmp writes consume memory. Consider Cloud Storage for large files.
Synchronous File Operations
Severity: WARNING
Sync file ops block the event loop in async apps
Message: Synchronous file operations. Use async versions for better concurrency.
Global Mutable State
Severity: WARNING
Global state issues with concurrent requests
Message: Global mutable state may cause issues with concurrent requests.
Thread-Unsafe Singleton Pattern
Severity: WARNING
Singletons need thread safety for concurrency > 1
Message: Singleton pattern - ensure thread safety if using concurrency > 1.
Collaboration
Delegation Triggers
user needs AWS serverless -> aws-serverless (Lambda, API Gateway, SAM)
user needs Azure containers -> azure-functions (Azure Container Apps, Functions)
user needs database design -> postgres-wizard (Cloud SQL design, AlloyDB)
user needs authentication -> auth-specialist (Firebase Auth, Identity Platform)
user needs AI integration -> llm-architect (Vertex AI, Cloud Run + LLM)
user needs workflow orchestration -> workflow-automation (Cloud Workflows, Eventarc)
When to Use
Use this skill when the request clearly matches the capabilities and patterns described above.
Limitations
Use this skill only when the task clearly matches the scope described above.
Do not treat the output as a substitute for enprojectnment-specific validation, testing, or expert review.
Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.