
Cloud
Learning Level
Building production systems on GCP requires understanding advanced patterns for cost optimization, performance, reliability, and scalability across multiple compute services.
By the end of this lesson, you'll understand:
Optimize compute service selection based on real-time workload characteristics:
# cost_analyzer.py - Analyze workload patterns to recommend service
import json
from datetime import datetime, timedelta
class ComputeOptimizer:
"""Analyze workload patterns and recommend optimal compute service"""
def __init__(self):
self.metrics = {
'cpu_utilization': [],
'memory_utilization': [],
'request_rate': [],
'traffic_pattern': [],
'peak_to_avg_ratio': 0,
'idle_percentage': 0
}
def analyze_workload(self, metrics_data):
"""Determine optimal compute service"""
peak_traffic = max(metrics_data['request_rates'])
avg_traffic = sum(metrics_data['request_rates']) / len(metrics_data['request_rates'])
peak_ratio = peak_traffic / avg_traffic if avg_traffic > 0 else 0
idle_pct = sum(1 for rate in metrics_data['request_rates'] if rate == 0) / len(metrics_data['request_rates'])
# Decision logic
if peak_ratio > 10 and idle_pct > 0.4:
return {
'service': 'Cloud Run',
'reason': 'High traffic variance with significant idle periods',
'expected_savings': '60%'
}
elif avg_traffic > 1000 and peak_ratio < 2:
return {
'service': 'App Engine',
'reason': 'Consistent traffic with predictable patterns',
'expected_savings': '40%'
}
elif idle_pct < 0.1:
return {
'service': 'Compute Engine with CUD',
'reason': 'Continuous high utilization workload',
'expected_savings': '70% with 3-year CUD'
}
else:
return {
'service': 'GKE',
'reason': 'Complex orchestration needed',
'expected_savings': '45%'
}
# Usage
optimizer = ComputeOptimizer()
recommendation = optimizer.analyze_workload({
'request_rates': [100, 1200, 80, 1500, 0, 0, 150]
})
print(f"Recommended service: {recommendation['service']}")
print(f"Rationale: {recommendation['reason']}")#!/bin/bash
# migration_cost_estimator.sh - Compare costs across compute services
PROJECT_ID="my-project"
WORKLOAD_NAME="my-app"
# Get current Compute Engine costs
echo "=== Computing Migration Cost Analysis ==="
# Estimate current costs
COMPUTE_ENGINE_COST=$(gcloud billing export-data \
--project=$PROJECT_ID \
--filter="service.description='Compute Engine'" \
--format='value(cost)' | tail -1)
echo "Current Compute Engine monthly cost: \$$COMPUTE_ENGINE_COST"
# Estimate Cloud Run cost (based on metrics)
# Assuming 10M requests/month, 512MB memory, 500ms avg execution
REQUESTS_PER_MONTH=10000000
MEMORY_GB=0.5
AVG_EXECUTION_MS=500
vCPU_ALLOCATION=1
# Cloud Run pricing: $0.00001667 per vCPU-second, $0.0000025 per GB-second
vCPU_SECONDS=$((REQUESTS_PER_MONTH * AVG_EXECUTION_MS / 1000 * vCPU_ALLOCATION))
GB_SECONDS=$((REQUESTS_PER_MONTH * AVG_EXECUTION_MS / 1000 * MEMORY_GB))
CLOUD_RUN_COST=$(echo "scale=2; ($vCPU_SECONDS * 0.00001667) + ($GB_SECONDS * 0.0000025)" | bc)
echo "Estimated Cloud Run monthly cost: \$$CLOUD_RUN_COST"
echo "Potential savings: $(echo "scale=2; $COMPUTE_ENGINE_COST - $CLOUD_RUN_COST" | bc)%"
# Estimate App Engine cost
# Assuming 0.95 normalized instances
NORMALIZED_INSTANCES=0.95
APP_ENGINE_HOURLY_RATE=0.09
HOURS_PER_MONTH=730
APP_ENGINE_COST=$(echo "scale=2; $NORMALIZED_INSTANCES * $APP_ENGINE_HOURLY_RATE * $HOURS_PER_MONTH" | bc)
echo "Estimated App Engine monthly cost: \$$APP_ENGINE_COST"# Analyze commitment requirements
#!/bin/bash
# 1. Analyze usage patterns over past 90 days
gcloud monitoring time-series list \
--filter='resource.type="gce_instance"' \
--format='value(metric.type,resource.labels.instance_id)' | while read metric instance; do
# Calculate average CPU utilization
avg_cpu=$(gcloud monitoring read-time-series \
--filter="metric.type='compute.googleapis.com/instance/cpu/utilization' AND resource.labels.instance_id='$instance'" \
--format='value(points[0].value.double_value)' | awk '{sum+=$1; count++} END {print sum/count}')
echo "Instance: $instance, Avg CPU: ${avg_cpu}%"
done
# 2. Estimate optimal commitment level
# Calculate 3-month average to determine stable baseline
# Reserve 80% of peak usage, let burst traffic use on-demand
# 3. Create commitments
gcloud compute commitments create app-servers-commitment \
--region=us-central1 \
--plan=three-year \
--resources=vcpu=100,memory=400GBImplement unified observability and traffic management across GKE and Cloud Run:
# istio-config.yaml - Service mesh spanning GKE and Cloud Run
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: app-router
namespace: production
spec:
hosts:
- app.example.com
http:
- match:
- uri:
prefix: /api/v1
route:
- destination:
host: api-gke-service
port:
number: 8080
weight: 70
- destination:
host: api-cloud-run-service
port:
number: 443
weight: 30
timeout: 10s
retries:
attempts: 3
perTryTimeout: 2s
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: api-rule
spec:
host: api-gke-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 1000
http:
http1MaxPendingRequests: 500
http2MaxRequests: 1000
maxRequestsPerConnection: 2
outlierDetection:
consecutive5xxErrors: 5
interval: 30s
baseEjectionTime: 30s# deploy_hybrid_arch.sh - Deploy application across GKE and Cloud Run
# Deploy stateful services to GKE
kubectl apply -f - << 'EOF'
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: database-proxy
spec:
serviceName: database-proxy
replicas: 3
selector:
matchLabels:
app: database-proxy
template:
metadata:
labels:
app: database-proxy
spec:
containers:
- name: proxy
image: gcr.io/my-project/database-proxy:v1.0.0
ports:
- containerPort: 5432
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: database-proxy
spec:
type: LoadBalancer
selector:
app: database-proxy
ports:
- port: 5432
targetPort: 5432
EOF
# Deploy stateless APIs to Cloud Run
gcloud run deploy api-microservice \
--region=us-central1 \
--image=gcr.io/my-project/api-service:v1.0.0 \
--set-env-vars DB_HOST=$(kubectl get svc database-proxy -o jsonpath='{.status.loadBalancer.ingress[0].ip}') \
--set-env-vars DB_PORT=5432 \
--vpc-connector=my-connector \
--vpc-egress=private-ranges-only# Implement gradual traffic shifting for safe deployments
gcloud run services update-traffic my-service \
--region=us-central1 \
--to-revisions=my-service-v1=80,my-service-v2=20
# Monitor error rates
gcloud monitoring read-time-series \
--filter='resource.type="cloud_run_revision" AND metric.type="run.googleapis.com/request_count"' \
--format='table(resource.labels.revision_name, points[0].value.int64_value)'
# If v2 error rate is acceptable, gradually increase traffic
gcloud run services update-traffic my-service \
--region=us-central1 \
--to-revisions=my-service-v1=50,my-service-v2=50
# Complete migration when confident
gcloud run services update-traffic my-service \
--region=us-central1 \
--to-revisions=my-service-v2=100Orchestrate complex workflows across multiple compute services:
# workflow_orchestrator.py - Coordinate work across services
import functions_framework
from google.cloud import tasks_v2
from google.cloud import pubsub_v1
import json
class WorkflowOrchestrator:
def __init__(self, project_id):
self.project_id = project_id
self.tasks_client = tasks_v2.CloudTasksClient()
self.publisher = pubsub_v1.PublisherClient()
def process_large_dataset(self, dataset_id, dataset_size):
"""Orchestrate multi-service workflow for large dataset processing"""
# Step 1: Queue data validation tasks in Cloud Run
queue_path = self.tasks_client.queue_path(
self.project_id, 'us-central1', 'validation-queue'
)
chunk_size = 1000
chunks = (dataset_size + chunk_size - 1) // chunk_size
for chunk_id in range(chunks):
task = {
'http_request': {
'http_method': tasks_v2.HttpMethod.POST,
'url': 'https://validation-service-abc123.a.run.app/validate',
'headers': {'Content-Type': 'application/json'},
'body': json.dumps({
'dataset_id': dataset_id,
'chunk_id': chunk_id,
'chunk_size': chunk_size
}).encode()
}
}
self.tasks_client.create_task(request={'parent': queue_path, 'task': task})
# Step 2: Publish event for GKE-based processing
topic_path = self.publisher.topic_path(
self.project_id, 'dataset-processing'
)
message_json = json.dumps({
'dataset_id': dataset_id,
'event_type': 'validation_complete',
'timestamp': '2024-03-02T10:00:00Z'
})
self.publisher.publish(topic_path, message_json.encode())
return {
'status': 'orchestrated',
'validation_tasks': chunks,
'processing_event_published': True
}
# Cloud Function entry point
@functions_framework.http
def orchestrate_workflow(request):
request_json = request.get_json()
orchestrator = WorkflowOrchestrator('my-project')
result = orchestrator.process_large_dataset(
dataset_id=request_json.get('dataset_id'),
dataset_size=request_json.get('dataset_size')
)
return result#!/bin/bash
# batch_executor.sh - Distribute batch jobs intelligently
PROJECT_ID="my-project"
TOTAL_ITEMS=1000000
# For CPU-intensive tasks: Use Compute Engine with auto-scaling group
cat > compute_engine_batch.yaml << 'EOF'
apiVersion: autoscaling.cnrm.cloud.google.com/v1beta1
kind: ComputeInstanceGroupManager
metadata:
name: batch-processor-igm
spec:
baseInstanceName: batch-processor
instanceTemplate:
spec:
machineType: n1-highmem-8
disks:
- boot: true
initializeParams:
sourceImage: projects/debian-cloud/global/images/family/debian-11
targetSize: 10
---
apiVersion: autoscaling.cnrm.cloud.google.com/v1beta1
kind: ComputeAutoscaler
metadata:
name: batch-processor-autoscaler
spec:
target: batch-processor-igm
autoscalingPolicy:
minNumReplicas: 2
maxNumReplicas: 50
cpuUtilization:
targetUtilization: 0.7
coolDownPeriod: 60
EOF
# For I/O-bound tasks: Use Cloud Run with high concurrency
gcloud run deploy io-processor \
--region=us-central1 \
--image=gcr.io/$PROJECT_ID/io-processor:v1 \
--concurrency=1000 \
--cpu=2 \
--memory=2Gi
# For event-driven processing: Use Cloud Functions
gcloud functions deploy process-batch-item \
--runtime=nodejs18 \
--trigger-topic=batch-items \
--entry-point=processBatchItem \
--memory=512MB \
--timeout=300
# Distribute work
# Partition 1: 400k items → Compute Engine (CPU-intensive)
# Partition 2: 300k items → Cloud Run (I/O-bound)
# Partition 3: 300k items → Cloud Functions (event-driven)
echo "Distributing $TOTAL_ITEMS items across services..."-- Query: Attribute costs to business units across all compute services
SELECT
labels.user_labels.cost_center as cost_center,
labels.user_labels.team as team,
CASE
WHEN service.description LIKE '%Compute Engine%' THEN 'Compute Engine'
WHEN service.description LIKE '%Cloud Run%' THEN 'Cloud Run'
WHEN service.description LIKE '%App Engine%' THEN 'App Engine'
WHEN service.description LIKE '%Kubernetes%' THEN 'GKE'
ELSE 'Other'
END as compute_service,
SUM(cost) as total_cost,
COUNT(*) as resource_count
FROM `project.billing_export.gcp_billing_export_v1_*`
WHERE _TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY))
AND service.description IN ('Compute Engine', 'Cloud Run', 'App Engine', 'Kubernetes Engine')
GROUP BY cost_center, team, compute_service
ORDER BY cost_center, total_cost DESC;# Create comprehensive monitoring dashboard
gcloud monitoring dashboards create --config-from-file=unified-dashboard.json
cat > unified-dashboard.json << 'EOF'
{
"displayName": "Multi-Service Compute Dashboard",
"mosaicLayout": {
"columns": 24,
"tiles": [
{
"width": 12,
"height": 4,
"widget": {
"title": "Request Rate by Service",
"xyChart": {
"dataSets": [
{
"timeSeriesQuery": {
"timeSeriesFilter": {
"filter": "metric.type=\"run.googleapis.com/request_count\" AND resource.type=\"cloud_run_revision\"",
"aggregation": {
"alignmentPeriod": "60s",
"perSeriesAligner": "ALIGN_RATE"
}
}
},
"legendTemplate": "Cloud Run"
},
{
"timeSeriesQuery": {
"timeSeriesFilter": {
"filter": "metric.type=\"appengine.googleapis.com/http/server_count\" AND resource.type=\"app_engine_app\"",
"aggregation": {
"alignmentPeriod": "60s",
"perSeriesAligner": "ALIGN_RATE"
}
}
},
"legendTemplate": "App Engine"
}
]
}
}
},
{
"xPos": 12,
"width": 12,
"height": 4,
"widget": {
"title": "Cost Breakdown",
"pieChart": {
"dataSets": [
{
"timeSeriesQuery": {
"timeSeriesFilter": {
"filter": "resource.type=\"billing_account\"",
"aggregation": {
"alignmentPeriod": "2592000s",
"perSeriesAligner": "ALIGN_SUM"
}
}
}
}
]
}
}
}
]
}
}
EOFFor applications requiring minimal changes:
# 1. Create VM from custom image
gcloud compute images create legacy-app-image \
--source-uri gs://my-bucket/legacy-app-snapshot.tar.gz
# 2. Create instance from image
gcloud compute instances create legacy-app \
--image=legacy-app-image \
--machine-type=e2-highmem-4 \
--zone=us-central1-a
# 3. Network configuration
gcloud compute networks create legacy-vpc
gcloud compute firewall-rules create allow-legacy-traffic \
--network=legacy-vpc \
--allow=tcp:3000,tcp:5432
# 4. Storage migration
gsutil -m cp -r s3://old-bucket/* gs://new-bucket/For applications requiring modernization:
#!/bin/bash
# modernize_to_cloud_run.sh
APP_NAME="legacy-api"
# Step 1: Extract application from legacy system
# Step 2: Create Dockerfile with minimal dependencies
cat > Dockerfile << 'EOF'
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm ci --only=production
EXPOSE 3000
ENV PORT=3000
CMD ["node", "server.js"]
EOF
# Step 3: Build and push image
docker build -t gcr.io/$PROJECT_ID/$APP_NAME:v1 .
docker push gcr.io/$PROJECT_ID/$APP_NAME:v1
# Step 4: Deploy to Cloud Run with gradual traffic shift
gcloud run deploy $APP_NAME \
--image=gcr.io/$PROJECT_ID/$APP_NAME:v1 \
--region=us-central1 \
--memory=1Gi \
--cpu=2 \
--timeout=900
# Step 5: Setup traffic splitting between legacy and new
# (Point DNS to both old and new services with weighted routing)# Deploy identical services in multiple regions for high availability
REGIONS=("us-central1" "europe-west1" "asia-northeast1")
for region in "${REGIONS[@]}"; do
gcloud run deploy my-api \
--region=$region \
--image=gcr.io/my-project/my-api:v1.0.0 \
--set-env-vars REGION=$region
done
# Create global HTTP(S) load balancer
gcloud compute backend-services create my-api-backend \
--global \
--protocol=HTTPS
# Add Cloud Run NEGs for each region
for region in "${REGIONS[@]}"; do
gcloud compute network-endpoint-groups create my-api-$region \
--region=$region \
--network-endpoint-type=SERVERLESS \
--cloud-run-service=my-api \
--cloud-run-region=$region
gcloud compute backend-services add-backend my-api-backend \
--global \
--instance-group=my-api-$region \
--instance-group-region=$region
done# Deploy to regions based on cost and latency
# Low-cost regions: Delhi, Los Angeles
# Standard regions: us-central1, europe-west1
# Premium regions: us-east1 (only for latency-sensitive traffic)
# Route traffic based on geography and cost
gcloud compute url-maps create global-lb \
--default-service=my-api-backend
gcloud compute url-maps add-path-rule global-lb \
--path-rule="/premium/*=my-api-backend-premium" \
--service=my-api-backend-premiumExplore specialized topics like App Engine for traditional applications, Cloud Run for containerized microservices, and GKE for enterprise Kubernetes deployments.
Resources
Ojasa Mirai
Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.
Learn Deep • Build Real • Verify Skills • Launch Forward