Skip to content

Monitoring and Deployment - GCP Professional Cloud Developer

Overview

Comprehensive guide to application monitoring, observability, logging, debugging, CI/CD pipelines, deployment strategies, and traffic management for cloud-native applications on Google Cloud Platform.

Application Monitoring

Cloud Monitoring API Integration

Complete Monitoring Setup:

from google.cloud import monitoring_v3
import time
from typing import Dict, Any

class CloudMonitoring:
    def __init__(self, project_id: str):
        self.project_id = project_id
        self.client = monitoring_v3.MetricServiceClient()
        self.project_name = f"projects/{project_id}"

    def write_custom_metric(self, metric_type: str, value: float,
                           labels: Dict[str, str] = None):
        """Write custom metric to Cloud Monitoring"""
        series = monitoring_v3.TimeSeries()
        series.metric.type = f"custom.googleapis.com/{metric_type}"
        series.resource.type = "global"

        # Add labels
        if labels:
            for key, val in labels.items():
                series.metric.labels[key] = val

        # Add point
        point = series.points.add()
        point.value.double_value = value
        now = time.time()
        point.interval.end_time.seconds = int(now)
        point.interval.end_time.nanos = int((now - int(now)) * 10**9)

        self.client.create_time_series(
            name=self.project_name,
            time_series=[series]
        )

    def write_business_metric(self, metric_name: str, value: float,
                             user_id: str = None, region: str = None):
        """Write business KPI metric"""
        labels = {}
        if user_id:
            labels['user_id'] = user_id
        if region:
            labels['region'] = region

        self.write_custom_metric(
            metric_type=f"business/{metric_name}",
            value=value,
            labels=labels
        )

    def record_request_latency(self, endpoint: str, latency_ms: float,
                               status_code: int):
        """Record API endpoint latency"""
        self.write_custom_metric(
            metric_type="api/request_latency",
            value=latency_ms,
            labels={
                'endpoint': endpoint,
                'status_code': str(status_code)
            }
        )

    def record_queue_depth(self, queue_name: str, depth: int):
        """Record queue depth for monitoring"""
        self.write_custom_metric(
            metric_type="queue/depth",
            value=float(depth),
            labels={'queue_name': queue_name}
        )

# Usage in application
monitoring = CloudMonitoring(project_id="my-project")

# Record business metrics
monitoring.write_business_metric(
    metric_name="order_total",
    value=299.99,
    user_id="user123",
    region="us-central1"
)

# Record API latency
monitoring.record_request_latency(
    endpoint="/api/products",
    latency_ms=125.5,
    status_code=200
)

Node.js Monitoring Integration:

const monitoring = require('@google-cloud/monitoring');

class CloudMonitoring {
  constructor(projectId) {
    this.projectId = projectId;
    this.client = new monitoring.MetricServiceClient();
    this.projectPath = this.client.projectPath(projectId);
  }

  async writeCustomMetric(metricType, value, labels = {}) {
    const dataPoint = {
      interval: {
        endTime: {
          seconds: Date.now() / 1000,
        },
      },
      value: {
        doubleValue: value,
      },
    };

    const timeSeries = {
      metric: {
        type: `custom.googleapis.com/${metricType}`,
        labels: labels,
      },
      resource: {
        type: 'global',
        labels: {
          project_id: this.projectId,
        },
      },
      points: [dataPoint],
    };

    const request = {
      name: this.projectPath,
      timeSeries: [timeSeries],
    };

    await this.client.createTimeSeries(request);
  }

  async recordUserAction(action, userId, duration) {
    await this.writeCustomMetric('user/action_duration', duration, {
      action: action,
      user_id: userId,
    });
  }

  async recordCacheHitRate(cacheName, hitRate) {
    await this.writeCustomMetric('cache/hit_rate', hitRate, {
      cache_name: cacheName,
    });
  }
}

// Middleware for automatic request monitoring
function monitoringMiddleware(monitoring) {
  return async (req, res, next) => {
    const startTime = Date.now();

    res.on('finish', async () => {
      const duration = Date.now() - startTime;
      await monitoring.writeCustomMetric('http/request_duration', duration, {
        method: req.method,
        path: req.path,
        status: res.statusCode.toString(),
      });
    });

    next();
  };
}

// Express app integration
const express = require('express');
const app = express();
const monitor = new CloudMonitoring('my-project');

app.use(monitoringMiddleware(monitor));

Custom Metrics Design Patterns

Resource Monitoring Pattern:

from google.cloud import monitoring_v3
import psutil
import threading
import time

class ResourceMonitor:
    def __init__(self, project_id: str, interval: int = 60):
        self.project_id = project_id
        self.client = monitoring_v3.MetricServiceClient()
        self.interval = interval
        self.running = False

    def start_monitoring(self):
        """Start background resource monitoring"""
        self.running = True
        thread = threading.Thread(target=self._monitor_loop)
        thread.daemon = True
        thread.start()

    def _monitor_loop(self):
        while self.running:
            self._record_resources()
            time.sleep(self.interval)

    def _record_resources(self):
        # CPU usage
        cpu_percent = psutil.cpu_percent(interval=1)
        self._write_metric("system/cpu_usage", cpu_percent)

        # Memory usage
        memory = psutil.virtual_memory()
        self._write_metric("system/memory_usage", memory.percent)

        # Disk usage
        disk = psutil.disk_usage('/')
        self._write_metric("system/disk_usage", disk.percent)

    def _write_metric(self, metric_type: str, value: float):
        series = monitoring_v3.TimeSeries()
        series.metric.type = f"custom.googleapis.com/{metric_type}"
        series.resource.type = "gce_instance"

        point = series.points.add()
        point.value.double_value = value
        point.interval.end_time.seconds = int(time.time())

        try:
            self.client.create_time_series(
                name=f"projects/{self.project_id}",
                time_series=[series]
            )
        except Exception as e:
            print(f"Failed to write metric: {e}")

# Start monitoring
monitor = ResourceMonitor(project_id="my-project", interval=60)
monitor.start_monitoring()

Distributed Tracing with Cloud Trace

Complete Trace Integration:

from google.cloud import trace_v1
from google.cloud.trace_v1 import types
import time
import uuid
from contextlib import contextmanager

class CloudTracer:
    def __init__(self, project_id: str, service_name: str):
        self.project_id = project_id
        self.service_name = service_name
        self.client = trace_v1.TraceServiceClient()
        self.project_name = f"projects/{project_id}"

    @contextmanager
    def span(self, span_name: str, parent_span_id: str = None):
        """Context manager for creating trace spans"""
        trace_id = str(uuid.uuid4().hex)
        span_id = str(uuid.uuid4().int)[:16]

        start_time = time.time()

        try:
            yield {
                'trace_id': trace_id,
                'span_id': span_id
            }
        finally:
            end_time = time.time()
            self._write_span(
                trace_id=trace_id,
                span_id=span_id,
                span_name=span_name,
                start_time=start_time,
                end_time=end_time,
                parent_span_id=parent_span_id
            )

    def _write_span(self, trace_id: str, span_id: str, span_name: str,
                    start_time: float, end_time: float,
                    parent_span_id: str = None):
        """Write span to Cloud Trace"""
        span = types.TraceSpan()
        span.span_id = int(span_id)
        span.name = span_name

        # Set timestamps
        span.start_time.seconds = int(start_time)
        span.start_time.nanos = int((start_time - int(start_time)) * 10**9)
        span.end_time.seconds = int(end_time)
        span.end_time.nanos = int((end_time - int(end_time)) * 10**9)

        if parent_span_id:
            span.parent_span_id = int(parent_span_id)

        trace = types.Trace()
        trace.project_id = self.project_id
        trace.trace_id = trace_id
        trace.spans.append(span)

        try:
            self.client.patch_traces(
                project_id=self.project_id,
                traces=types.Traces(traces=[trace])
            )
        except Exception as e:
            print(f"Failed to write trace: {e}")

# Usage in application
tracer = CloudTracer(project_id="my-project", service_name="api-service")

def process_order(order_id: str):
    with tracer.span("process_order") as parent_span:
        # Validate order
        with tracer.span("validate_order", parent_span['span_id']):
            validate_order_details(order_id)

        # Process payment
        with tracer.span("process_payment", parent_span['span_id']):
            process_payment(order_id)

        # Ship order
        with tracer.span("ship_order", parent_span['span_id']):
            ship_order(order_id)

OpenTelemetry Integration (Recommended):

from opentelemetry import trace
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.instrumentation.flask import FlaskInstrumentor

# Set up Cloud Trace exporter
trace.set_tracer_provider(TracerProvider())
cloud_trace_exporter = CloudTraceSpanExporter()
trace.get_tracer_provider().add_span_processor(
    BatchSpanProcessor(cloud_trace_exporter)
)

# Auto-instrument libraries
RequestsInstrumentor().instrument()

# Flask app instrumentation
from flask import Flask
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)

# Manual instrumentation
tracer = trace.get_tracer(__name__)

@app.route('/api/products/<product_id>')
def get_product(product_id):
    with tracer.start_as_current_span("get_product") as span:
        span.set_attribute("product_id", product_id)

        # Database call
        with tracer.start_as_current_span("db_query"):
            product = db.get_product(product_id)

        # Cache call
        with tracer.start_as_current_span("cache_check"):
            cached = cache.get(f"product:{product_id}")

        span.set_attribute("cache_hit", cached is not None)
        return product

Error Reporting Integration

Comprehensive Error Handling:

from google.cloud import error_reporting
import logging
import traceback
import sys

class ErrorReporter:
    def __init__(self, project_id: str, service_name: str):
        self.client = error_reporting.Client(project=project_id)
        self.service_name = service_name

    def report_error(self, error: Exception, user_id: str = None,
                    http_context: dict = None):
        """Report error to Cloud Error Reporting"""
        try:
            self.client.report_exception(
                http_context=http_context,
                user=user_id
            )
        except Exception as e:
            logging.error(f"Failed to report error: {e}")

    def report_with_context(self, error: Exception, **context):
        """Report error with custom context"""
        error_message = f"{type(error).__name__}: {str(error)}\n"
        error_message += f"Context: {context}\n"
        error_message += traceback.format_exc()

        try:
            self.client.report(error_message)
        except Exception as e:
            logging.error(f"Failed to report error: {e}")

# Flask integration
from flask import Flask, request, g
import functools

app = Flask(__name__)
error_reporter = ErrorReporter(
    project_id="my-project",
    service_name="api-service"
)

def report_errors(f):
    """Decorator to automatically report errors"""
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except Exception as e:
            http_context = {
                'method': request.method,
                'url': request.url,
                'user_agent': request.headers.get('User-Agent'),
                'remote_ip': request.remote_addr
            }

            error_reporter.report_error(
                error=e,
                user_id=g.get('user_id'),
                http_context=http_context
            )
            raise

    return wrapper

@app.route('/api/orders', methods=['POST'])
@report_errors
def create_order():
    # Application logic
    order = process_order_request(request.json)
    return {'order_id': order.id}

Node.js Error Reporting:

const {ErrorReporting} = require('@google-cloud/error-reporting');

const errors = new ErrorReporting({
  projectId: 'my-project',
  reportMode: 'production',
  serviceContext: {
    service: 'api-service',
    version: '1.0.0',
  },
});

// Express middleware
function errorReportingMiddleware(err, req, res, next) {
  errors.report(err, {
    user: req.user?.id,
    httpRequest: {
      method: req.method,
      url: req.url,
      userAgent: req.headers['user-agent'],
      remoteIp: req.ip,
      statusCode: res.statusCode,
    },
  });

  next(err);
}

app.use(errorReportingMiddleware);

// Manual error reporting
async function processOrder(orderId) {
  try {
    await validateOrder(orderId);
    await chargePayment(orderId);
  } catch (err) {
    errors.report(err, {
      user: orderId,
      context: {
        step: 'payment_processing',
        order_id: orderId,
      },
    });
    throw err;
  }
}

Logging Best Practices

Structured Logging

Python Structured Logging:

import logging
import json
import uuid
from google.cloud import logging as cloud_logging
from datetime import datetime

class StructuredLogger:
    def __init__(self, project_id: str, service_name: str):
        self.client = cloud_logging.Client(project=project_id)
        self.client.setup_logging()
        self.service_name = service_name
        self.logger = logging.getLogger(service_name)

    def log(self, level: str, message: str, **context):
        """Log structured message with context"""
        log_entry = {
            'timestamp': datetime.utcnow().isoformat(),
            'severity': level.upper(),
            'service': self.service_name,
            'message': message,
            **context
        }

        if level == 'info':
            self.logger.info(json.dumps(log_entry))
        elif level == 'warning':
            self.logger.warning(json.dumps(log_entry))
        elif level == 'error':
            self.logger.error(json.dumps(log_entry))
        elif level == 'debug':
            self.logger.debug(json.dumps(log_entry))

    def log_request(self, method: str, path: str, status_code: int,
                   latency_ms: float, user_id: str = None):
        """Log HTTP request with standard fields"""
        self.log('info', 'HTTP request processed',
                method=method,
                path=path,
                status_code=status_code,
                latency_ms=latency_ms,
                user_id=user_id,
                log_type='http_request')

    def log_business_event(self, event_type: str, **details):
        """Log business event"""
        self.log('info', f'Business event: {event_type}',
                event_type=event_type,
                log_type='business_event',
                **details)

# Usage
logger = StructuredLogger(
    project_id="my-project",
    service_name="api-service"
)

logger.log_request(
    method="POST",
    path="/api/orders",
    status_code=201,
    latency_ms=145.2,
    user_id="user123"
)

logger.log_business_event(
    event_type="order_created",
    order_id="order-456",
    total_amount=299.99,
    currency="USD"
)

Correlation IDs and Request Tracking

Request Correlation Pattern:

import uuid
from flask import Flask, request, g
import logging

app = Flask(__name__)

@app.before_request
def before_request():
    """Generate or extract correlation ID"""
    correlation_id = request.headers.get('X-Correlation-ID')
    if not correlation_id:
        correlation_id = str(uuid.uuid4())

    g.correlation_id = correlation_id
    g.request_start_time = time.time()

@app.after_request
def after_request(response):
    """Add correlation ID to response headers"""
    response.headers['X-Correlation-ID'] = g.correlation_id
    return response

class CorrelationFilter(logging.Filter):
    """Add correlation ID to all logs"""
    def filter(self, record):
        record.correlation_id = getattr(g, 'correlation_id', 'no-correlation-id')
        record.user_id = getattr(g, 'user_id', 'anonymous')
        return True

# Configure logging
logger = logging.getLogger(__name__)
logger.addFilter(CorrelationFilter())

# Custom formatter
formatter = logging.Formatter(
    '{"timestamp":"%(asctime)s","severity":"%(levelname)s",'
    '"correlation_id":"%(correlation_id)s","user_id":"%(user_id)s",'
    '"message":"%(message)s"}'
)

@app.route('/api/orders', methods=['POST'])
def create_order():
    logger.info(f"Processing order creation",
               extra={'order_data': request.json})

    try:
        order = process_order(request.json)
        logger.info(f"Order created successfully",
                   extra={'order_id': order.id})
        return {'order_id': order.id}, 201
    except Exception as e:
        logger.error(f"Order creation failed: {e}",
                    extra={'error_type': type(e).__name__})
        raise

Node.js Correlation Tracking:

const {Logging} = require('@google-cloud/logging');
const express = require('express');
const {v4: uuidv4} = require('uuid');

const logging = new Logging({projectId: 'my-project'});
const log = logging.log('api-service');

// Middleware for correlation ID
function correlationMiddleware(req, res, next) {
  req.correlationId = req.headers['x-correlation-id'] || uuidv4();
  res.setHeader('X-Correlation-ID', req.correlationId);
  next();
}

// Structured logging helper
function logStructured(severity, message, metadata = {}) {
  const entry = log.entry({
    resource: {type: 'global'},
    severity: severity.toUpperCase(),
  }, {
    message,
    correlation_id: req.correlationId,
    user_id: req.user?.id,
    timestamp: new Date().toISOString(),
    ...metadata,
  });

  log.write(entry);
}

app.use(correlationMiddleware);

app.post('/api/orders', async (req, res) => {
  logStructured('info', 'Processing order', {
    order_data: req.body,
  });

  try {
    const order = await processOrder(req.body);
    logStructured('info', 'Order created', {
      order_id: order.id,
    });
    res.status(201).json({order_id: order.id});
  } catch (err) {
    logStructured('error', 'Order creation failed', {
      error: err.message,
      stack: err.stack,
    });
    res.status(500).json({error: 'Internal server error'});
  }
});

Log-Based Metrics

Creating Log-Based Metrics:

# Create counter metric from logs
gcloud logging metrics create order_errors \
  --description="Count of order processing errors" \
  --log-filter='resource.type="cloud_run_revision"
    severity="ERROR"
    jsonPayload.event_type="order_processing"'

# Create distribution metric for latency
gcloud logging metrics create api_latency \
  --description="API endpoint latency distribution" \
  --log-filter='resource.type="cloud_run_revision"
    jsonPayload.log_type="http_request"' \
  --value-extractor='EXTRACT(jsonPayload.latency_ms)'

# Create metric with labels
gcloud logging metrics create http_requests_by_status \
  --description="HTTP requests by status code" \
  --log-filter='resource.type="cloud_run_revision"
    jsonPayload.log_type="http_request"' \
  --value-extractor='EXTRACT(jsonPayload.status_code)'

Python Log-Based Metrics Creation:

from google.cloud import logging_v2

def create_log_based_metrics(project_id: str):
    client = logging_v2.MetricsServiceV2Client()
    project_name = f"projects/{project_id}"

    # Error count metric
    metric = {
        'name': f'{project_name}/metrics/application_errors',
        'description': 'Count of application errors',
        'filter': 'severity>=ERROR',
        'metric_descriptor': {
            'metric_kind': 'DELTA',
            'value_type': 'INT64',
        }
    }

    client.create_log_metric(parent=project_name, metric=metric)

    # Latency distribution metric
    latency_metric = {
        'name': f'{project_name}/metrics/request_latency',
        'description': 'Request latency distribution',
        'filter': 'jsonPayload.latency_ms>0',
        'value_extractor': 'EXTRACT(jsonPayload.latency_ms)',
        'metric_descriptor': {
            'metric_kind': 'DELTA',
            'value_type': 'DISTRIBUTION',
        }
    }

    client.create_log_metric(parent=project_name, metric=latency_metric)

Debugging

Cloud Debugger

Debugger Integration:

import googleclouddebugger

# Enable Cloud Debugger
googleclouddebugger.enable(
    project_id='my-project',
    project_number='123456789',
    service='api-service',
    version='v1.0.0'
)

# Application code - debugger allows setting breakpoints
# and logpoints without code changes
def process_payment(order_id: str, amount: float):
    # Can set snapshot here to inspect variables
    payment_method = get_payment_method(order_id)

    # Can set logpoint here to log without redeploying
    charge_result = charge_payment(payment_method, amount)

    return charge_result

Using Debugger Snapshots (via gcloud):

# List debug targets
gcloud debug targets list

# Create snapshot (breakpoint)
gcloud debug snapshots create \
  --target=api-service \
  --location=main.py:42 \
  --condition="order_total > 1000"

# Create logpoint
gcloud debug logpoints create \
  --target=api-service \
  --location=payment.py:25 \
  --log-format="Processing payment for order {order_id} amount {amount}"

# List snapshots
gcloud debug snapshots list --target=api-service

# View snapshot details
gcloud debug snapshots describe SNAPSHOT_ID

Cloud Profiler Integration

Complete Profiler Setup:

import googlecloudprofiler
import logging

def setup_profiler(project_id: str, service_name: str, version: str):
    """Initialize Cloud Profiler"""
    try:
        googlecloudprofiler.start(
            service=service_name,
            service_version=version,
            project_id=project_id,
            verbose=3,  # Set to 3 for debugging
            # Profile CPU and heap
            disable_cpu_profiling=False,
            disable_heap_profiling=False,
            # Sampling configuration
            period_ms=1000,  # Sample every second
        )
        logging.info("Cloud Profiler started successfully")
    except Exception as e:
        logging.error(f"Failed to start Cloud Profiler: {e}")

# Start profiler at application startup
setup_profiler(
    project_id="my-project",
    service_name="api-service",
    version="v1.0.0"
)

# CPU-intensive function that will show in profiler
def calculate_recommendations(user_id: str):
    # This function's performance will be visible in Cloud Profiler
    user_data = fetch_user_data(user_id)
    recommendations = []

    for item in user_data.history:
        similarity_scores = calculate_similarity(item)
        recommendations.extend(similarity_scores)

    return sorted(recommendations, reverse=True)[:10]

Node.js Profiler Setup:

const profiler = require('@google-cloud/profiler');

// Start profiler
profiler.start({
  projectId: 'my-project',
  serviceContext: {
    service: 'api-service',
    version: '1.0.0',
  },
  // Profile time and heap
  disableTime: false,
  disableHeap: false,
  // Sampling configuration
  timeIntervalMicros: 1000,
  heapIntervalBytes: 512 * 1024,
}).catch((err) => {
  console.error(`Failed to start profiler: ${err}`);
});

CI/CD Pipelines

Cloud Build Configuration

Basic cloudbuild.yaml:

# cloudbuild.yaml - Simple build and deploy
steps:
  # Build Docker image
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'build'
      - '-t'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '-t'
      - 'gcr.io/$PROJECT_ID/myapp:latest'
      - '.'

  # Push image to Container Registry
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'push'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'

  # Deploy to Cloud Run
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'myapp'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--region'
      - 'us-central1'
      - '--platform'
      - 'managed'
      - '--allow-unauthenticated'

images:
  - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
  - 'gcr.io/$PROJECT_ID/myapp:latest'

timeout: '1200s'

Advanced CI/CD Pipeline with Testing:

# cloudbuild.yaml - Complete CI/CD pipeline
steps:
  # Install dependencies
  - name: 'python:3.9'
    entrypoint: 'pip'
    args:
      - 'install'
      - '-r'
      - 'requirements.txt'
      - '--user'

  # Run unit tests
  - name: 'python:3.9'
    entrypoint: 'python'
    args:
      - '-m'
      - 'pytest'
      - 'tests/unit'
      - '--cov=app'
      - '--cov-report=xml'
      - '--junitxml=test-results.xml'
    env:
      - 'PYTHONPATH=/workspace'

  # Run linting
  - name: 'python:3.9'
    entrypoint: 'python'
    args:
      - '-m'
      - 'pylint'
      - 'app/'
      - '--output-format=json'
      - '--reports=y'

  # Security scan
  - name: 'aquasec/trivy'
    args:
      - 'fs'
      - '--security-checks'
      - 'vuln,config'
      - '--severity'
      - 'HIGH,CRITICAL'
      - '.'

  # Build Docker image
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'build'
      - '-t'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '-t'
      - 'gcr.io/$PROJECT_ID/myapp:$SHORT_SHA'
      - '-t'
      - 'gcr.io/$PROJECT_ID/myapp:latest'
      - '--build-arg'
      - 'VERSION=$TAG_NAME'
      - '--cache-from'
      - 'gcr.io/$PROJECT_ID/myapp:latest'
      - '.'

  # Scan container image
  - name: 'aquasec/trivy'
    args:
      - 'image'
      - '--severity'
      - 'HIGH,CRITICAL'
      - '--exit-code'
      - '1'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'

  # Push image
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'push'
      - '--all-tags'
      - 'gcr.io/$PROJECT_ID/myapp'

  # Deploy to staging
  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-staging'
    args:
      - 'run'
      - 'deploy'
      - 'myapp-staging'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--region'
      - 'us-central1'
      - '--platform'
      - 'managed'
      - '--tag'
      - 'staging-$SHORT_SHA'
      - '--no-traffic'

  # Run integration tests against staging
  - name: 'python:3.9'
    entrypoint: 'python'
    args:
      - '-m'
      - 'pytest'
      - 'tests/integration'
      - '--base-url=https://staging-$SHORT_SHA---myapp-staging-uc.a.run.app'
    env:
      - 'PYTHONPATH=/workspace'

  # Deploy to production with traffic split
  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-production'
    args:
      - 'run'
      - 'deploy'
      - 'myapp'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--region'
      - 'us-central1'
      - '--platform'
      - 'managed'
      - '--tag'
      - 'prod-$SHORT_SHA'
      - '--no-traffic'

  # Gradual rollout - 10% traffic
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'services'
      - 'update-traffic'
      - 'myapp'
      - '--to-revisions'
      - 'prod-$SHORT_SHA=10'
      - '--region'
      - 'us-central1'

substitutions:
  _DEPLOY_REGION: 'us-central1'

options:
  machineType: 'N1_HIGHCPU_8'
  logging: 'CLOUD_LOGGING_ONLY'

timeout: '1800s'

Multi-Stage Build with Artifacts:

# cloudbuild.yaml - Multi-stage with artifact management
steps:
  # Stage 1: Build and test
  - name: 'node:16'
    id: 'install'
    entrypoint: 'npm'
    args: ['ci']

  - name: 'node:16'
    id: 'test'
    entrypoint: 'npm'
    args: ['test']
    waitFor: ['install']

  - name: 'node:16'
    id: 'build'
    entrypoint: 'npm'
    args: ['run', 'build']
    waitFor: ['install']

  # Stage 2: Create production image
  - name: 'gcr.io/cloud-builders/docker'
    id: 'docker-build'
    args:
      - 'build'
      - '-f'
      - 'Dockerfile.prod'
      - '-t'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '.'
    waitFor: ['build']

  # Stage 3: Upload artifacts
  - name: 'gcr.io/cloud-builders/gsutil'
    args:
      - 'cp'
      - '-r'
      - 'dist/*'
      - 'gs://$PROJECT_ID-artifacts/builds/$BUILD_ID/'
    waitFor: ['build']

  # Stage 4: Push image
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA']
    waitFor: ['docker-build']

  # Stage 5: Deploy
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'myapp'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--region'
      - 'us-central1'
    waitFor: ['push']

artifacts:
  objects:
    location: 'gs://$PROJECT_ID-artifacts/builds/$BUILD_ID/'
    paths:
      - 'test-results/**'
      - 'coverage/**'
      - 'dist/**'

options:
  machineType: 'E2_HIGHCPU_8'

Build Triggers

Creating Build Triggers:

# Trigger on push to main branch
gcloud builds triggers create github \
  --repo-name=myapp \
  --repo-owner=myorg \
  --branch-pattern="^main$" \
  --build-config=cloudbuild.yaml \
  --description="Deploy to production on main push"

# Trigger on pull request
gcloud builds triggers create github \
  --repo-name=myapp \
  --repo-owner=myorg \
  --pull-request-pattern="^.*$" \
  --build-config=cloudbuild-pr.yaml \
  --description="Run tests on pull request" \
  --comment-control=COMMENTS_ENABLED

# Trigger on tag
gcloud builds triggers create github \
  --repo-name=myapp \
  --repo-owner=myorg \
  --tag-pattern="v.*" \
  --build-config=cloudbuild-release.yaml \
  --description="Release on version tag"

# Trigger with substitutions
gcloud builds triggers create github \
  --repo-name=myapp \
  --repo-owner=myorg \
  --branch-pattern="^develop$" \
  --build-config=cloudbuild.yaml \
  --substitutions=_ENVIRONMENT=staging,_REGION=us-central1

cloudbuild.yaml with Substitutions:

# cloudbuild.yaml - Using substitutions
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'build'
      - '-t'
      - 'gcr.io/$PROJECT_ID/${_SERVICE_NAME}:$COMMIT_SHA'
      - '--build-arg'
      - 'ENVIRONMENT=${_ENVIRONMENT}'
      - '.'

  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - '${_SERVICE_NAME}-${_ENVIRONMENT}'
      - '--image'
      - 'gcr.io/$PROJECT_ID/${_SERVICE_NAME}:$COMMIT_SHA'
      - '--region'
      - '${_REGION}'
      - '--set-env-vars'
      - 'ENVIRONMENT=${_ENVIRONMENT},VERSION=$SHORT_SHA'

substitutions:
  _SERVICE_NAME: 'myapp'
  _ENVIRONMENT: 'production'
  _REGION: 'us-central1'

# Default substitutions can be overridden by trigger

Deployment Strategies

Blue-Green Deployment

App Engine Blue-Green:

# Deploy new version without traffic
gcloud app deploy --no-promote --version=v2

# Test new version
curl https://v2-dot-myapp.appspot.com

# Switch traffic
gcloud app services set-traffic default --splits=v2=1.0

# Rollback if needed
gcloud app services set-traffic default --splits=v1=1.0

Cloud Run Blue-Green with Traffic Split:

# Deploy blue (current) version
gcloud run deploy myapp \
  --image gcr.io/project/myapp:blue \
  --tag blue \
  --region us-central1

# Deploy green (new) version without traffic
gcloud run deploy myapp \
  --image gcr.io/project/myapp:green \
  --tag green \
  --no-traffic \
  --region us-central1

# Test green version
curl https://green---myapp-uc.a.run.app

# Switch all traffic to green
gcloud run services update-traffic myapp \
  --to-revisions LATEST=100 \
  --region us-central1

# Or gradual switch
gcloud run services update-traffic myapp \
  --to-tags green=100 \
  --region us-central1

GKE Blue-Green with Services:

# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-blue
  labels:
    app: myapp
    version: blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: blue
  template:
    metadata:
      labels:
        app: myapp
        version: blue
    spec:
      containers:
      - name: app
        image: gcr.io/project/myapp:v1
        ports:
        - containerPort: 8080
---
# green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-green
  labels:
    app: myapp
    version: green
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: green
  template:
    metadata:
      labels:
        app: myapp
        version: green
    spec:
      containers:
      - name: app
        image: gcr.io/project/myapp:v2
        ports:
        - containerPort: 8080
---
# service.yaml - Switch between blue and green
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
    version: blue  # Change to 'green' to switch traffic
  ports:
  - port: 80
    targetPort: 8080
  type: LoadBalancer

Canary Deployment

Cloud Run Canary:

# Deploy canary revision
gcloud run deploy myapp \
  --image gcr.io/project/myapp:canary \
  --tag canary \
  --no-traffic \
  --region us-central1

# Gradual rollout - 10%
gcloud run services update-traffic myapp \
  --to-tags stable=90,canary=10 \
  --region us-central1

# Monitor metrics, then increase to 50%
gcloud run services update-traffic myapp \
  --to-tags stable=50,canary=50 \
  --region us-central1

# Full rollout
gcloud run services update-traffic myapp \
  --to-tags canary=100 \
  --region us-central1

# Promote canary to stable
gcloud run services update-traffic myapp \
  --update-tags stable=LATEST \
  --region us-central1

Automated Canary with Cloud Build:

# cloudbuild-canary.yaml
steps:
  # Build and push
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'build'
      - '-t'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '.'

  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA']

  # Deploy canary with 10% traffic
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'myapp'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--tag'
      - 'canary-$SHORT_SHA'
      - '--no-traffic'
      - '--region'
      - 'us-central1'

  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'services'
      - 'update-traffic'
      - 'myapp'
      - '--to-revisions'
      - 'canary-$SHORT_SHA=10'
      - '--region'
      - 'us-central1'

  # Wait and monitor (in practice, use Cloud Monitoring)
  - name: 'gcr.io/cloud-builders/gcloud'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        sleep 300
        # Check error rate from Cloud Monitoring
        ERROR_RATE=$(gcloud monitoring time-series list \
          --filter='metric.type="run.googleapis.com/request_count" AND metric.label.response_code_class="5xx"' \
          --format='value(point.value.int64Value)')

        if [ "$ERROR_RATE" -gt 10 ]; then
          echo "Error rate too high, rolling back"
          exit 1
        fi

  # If successful, increase to 50%
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'services'
      - 'update-traffic'
      - 'myapp'
      - '--to-revisions'
      - 'canary-$SHORT_SHA=50'
      - '--region'
      - 'us-central1'

Rolling Deployment (GKE)

Rolling Update Strategy:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2        # Max pods above desired count
      maxUnavailable: 1  # Max pods unavailable during update
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: app
        image: gcr.io/project/myapp:v2
        ports:
        - containerPort: 8080
        # Health checks are critical for rolling updates
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 3

Controlled Rolling Update:

# Update deployment
kubectl set image deployment/myapp app=gcr.io/project/myapp:v2

# Watch rollout status
kubectl rollout status deployment/myapp

# Pause rollout
kubectl rollout pause deployment/myapp

# Resume rollout
kubectl rollout resume deployment/myapp

# Rollback to previous version
kubectl rollout undo deployment/myapp

# Rollback to specific revision
kubectl rollout undo deployment/myapp --to-revision=2

# View rollout history
kubectl rollout history deployment/myapp

Testing Strategies

Unit Testing

Python Unit Tests with pytest:

# tests/unit/test_order_service.py
import pytest
from unittest.mock import Mock, patch
from app.services.order_service import OrderService

@pytest.fixture
def order_service():
    return OrderService()

@pytest.fixture
def mock_db():
    with patch('app.services.order_service.db') as mock:
        yield mock

def test_create_order_success(order_service, mock_db):
    """Test successful order creation"""
    order_data = {
        'user_id': 'user123',
        'items': [{'sku': 'PROD-001', 'quantity': 2}],
        'total': 299.99
    }

    mock_db.insert.return_value = {'id': 'order-456'}

    result = order_service.create_order(order_data)

    assert result['id'] == 'order-456'
    mock_db.insert.assert_called_once()

def test_create_order_invalid_data(order_service):
    """Test order creation with invalid data"""
    invalid_data = {'user_id': 'user123'}  # Missing required fields

    with pytest.raises(ValueError):
        order_service.create_order(invalid_data)

def test_calculate_order_total(order_service):
    """Test order total calculation"""
    items = [
        {'price': 100.00, 'quantity': 2},
        {'price': 50.00, 'quantity': 1}
    ]

    total = order_service.calculate_total(items)

    assert total == 250.00

Node.js Unit Tests with Jest:

// tests/unit/orderService.test.js
const OrderService = require('../../src/services/orderService');
const db = require('../../src/db');

jest.mock('../../src/db');

describe('OrderService', () => {
  let orderService;

  beforeEach(() => {
    orderService = new OrderService();
    jest.clearAllMocks();
  });

  test('creates order successfully', async () => {
    const orderData = {
      userId: 'user123',
      items: [{sku: 'PROD-001', quantity: 2}],
      total: 299.99,
    };

    db.insert.mockResolvedValue({id: 'order-456'});

    const result = await orderService.createOrder(orderData);

    expect(result.id).toBe('order-456');
    expect(db.insert).toHaveBeenCalledTimes(1);
  });

  test('throws error for invalid data', async () => {
    const invalidData = {userId: 'user123'};

    await expect(
      orderService.createOrder(invalidData)
    ).rejects.toThrow('Invalid order data');
  });

  test('calculates order total correctly', () => {
    const items = [
      {price: 100.00, quantity: 2},
      {price: 50.00, quantity: 1},
    ];

    const total = orderService.calculateTotal(items);

    expect(total).toBe(250.00);
  });
});

Integration Testing

Integration Test with Cloud Services:

# tests/integration/test_order_workflow.py
import pytest
import requests
from google.cloud import firestore, pubsub_v1

@pytest.fixture
def api_base_url():
    return "https://myapp-staging-uc.a.run.app"

@pytest.fixture
def db_client():
    return firestore.Client(project='my-project')

@pytest.fixture
def pubsub_client():
    return pubsub_v1.SubscriberClient()

def test_create_order_workflow(api_base_url, db_client):
    """Test complete order creation workflow"""
    # Create order via API
    order_data = {
        'user_id': 'test-user',
        'items': [{'sku': 'TEST-001', 'quantity': 1}],
        'total': 99.99
    }

    response = requests.post(
        f"{api_base_url}/api/orders",
        json=order_data,
        headers={'Authorization': 'Bearer test-token'}
    )

    assert response.status_code == 201
    order_id = response.json()['order_id']

    # Verify order in database
    doc = db_client.collection('orders').document(order_id).get()
    assert doc.exists
    assert doc.to_dict()['user_id'] == 'test-user'

    # Cleanup
    db_client.collection('orders').document(order_id).delete()

def test_order_notification_flow(api_base_url, pubsub_client):
    """Test order creates notification message"""
    subscription_path = pubsub_client.subscription_path(
        'my-project', 'order-notifications-test'
    )

    # Create order
    order_data = {
        'user_id': 'test-user',
        'items': [{'sku': 'TEST-001', 'quantity': 1}],
        'total': 99.99
    }

    response = requests.post(f"{api_base_url}/api/orders", json=order_data)
    order_id = response.json()['order_id']

    # Pull message from Pub/Sub
    response = pubsub_client.pull(
        subscription=subscription_path,
        max_messages=1,
        timeout=10
    )

    assert len(response.received_messages) == 1
    message = response.received_messages[0]
    assert message.message.data.decode('utf-8') == order_id

    # Acknowledge message
    pubsub_client.acknowledge(
        subscription=subscription_path,
        ack_ids=[message.ack_id]
    )

End-to-End Testing

E2E Test with Playwright:

# tests/e2e/test_order_flow.py
from playwright.sync_api import sync_playwright
import pytest

@pytest.fixture
def browser():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        yield browser
        browser.close()

def test_complete_order_flow(browser):
    """Test complete user order flow"""
    page = browser.new_page()

    # Navigate to app
    page.goto("https://myapp.example.com")

    # Login
    page.click("text=Login")
    page.fill("input[name=email]", "test@example.com")
    page.fill("input[name=password]", "testpass123")
    page.click("button[type=submit]")

    # Wait for dashboard
    page.wait_for_selector("text=Dashboard")

    # Add product to cart
    page.click("text=Products")
    page.click("button[data-product=PROD-001]")
    page.click("text=Add to Cart")

    # Checkout
    page.click("text=Cart")
    page.click("text=Checkout")

    # Fill payment info
    page.fill("input[name=card_number]", "4242424242424242")
    page.fill("input[name=exp_date]", "12/25")
    page.fill("input[name=cvv]", "123")

    # Submit order
    page.click("button[type=submit]")

    # Verify success
    page.wait_for_selector("text=Order confirmed")
    order_id = page.locator("[data-order-id]").inner_text()

    assert len(order_id) > 0

Load Testing

Locust Load Test:

# tests/load/locustfile.py
from locust import HttpUser, task, between
import random

class OrderUser(HttpUser):
    wait_time = between(1, 5)

    def on_start(self):
        """Login user"""
        response = self.client.post("/api/auth/login", json={
            "email": f"user{random.randint(1, 1000)}@example.com",
            "password": "testpass123"
        })
        self.token = response.json()['token']

    @task(3)
    def browse_products(self):
        """Browse products - most common action"""
        self.client.get("/api/products",
                       headers={"Authorization": f"Bearer {self.token}"})

    @task(2)
    def view_product(self):
        """View specific product"""
        product_id = random.choice(['PROD-001', 'PROD-002', 'PROD-003'])
        self.client.get(f"/api/products/{product_id}",
                       headers={"Authorization": f"Bearer {self.token}"})

    @task(1)
    def create_order(self):
        """Create order - less frequent but important"""
        order_data = {
            "items": [
                {
                    "sku": random.choice(['PROD-001', 'PROD-002']),
                    "quantity": random.randint(1, 3)
                }
            ]
        }
        self.client.post("/api/orders",
                        json=order_data,
                        headers={"Authorization": f"Bearer {self.token}"})

# Run: locust -f locustfile.py --host=https://myapp.example.com

Cloud Build Load Test Pipeline:

# cloudbuild-loadtest.yaml
steps:
  # Deploy to staging
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'myapp-staging'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--region'
      - 'us-central1'

  # Run load test
  - name: 'locustio/locust'
    args:
      - '-f'
      - 'tests/load/locustfile.py'
      - '--host=https://myapp-staging-uc.a.run.app'
      - '--users=100'
      - '--spawn-rate=10'
      - '--run-time=5m'
      - '--headless'
      - '--only-summary'

  # Check performance metrics
  - name: 'gcr.io/cloud-builders/gcloud'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        # Query Cloud Monitoring for p99 latency
        P99=$(gcloud monitoring time-series list \
          --filter='metric.type="run.googleapis.com/request_latencies"' \
          --format='value(point.value.distributionValue.bucketOptions)')

        if [ "$P99" -gt 500 ]; then
          echo "P99 latency exceeds 500ms"
          exit 1
        fi

Chaos Engineering

Chaos Test with Litmus:

# chaos-experiment.yaml
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
  name: myapp-chaos
  namespace: default
spec:
  appinfo:
    appns: default
    applabel: 'app=myapp'
    appkind: deployment
  chaosServiceAccount: litmus-admin
  experiments:
    - name: pod-delete
      spec:
        components:
          env:
            - name: TOTAL_CHAOS_DURATION
              value: '60'
            - name: CHAOS_INTERVAL
              value: '10'
            - name: FORCE
              value: 'false'

Python Chaos Test:

# tests/chaos/test_resilience.py
import requests
import time
import random
from google.cloud import compute_v1

def test_instance_failure_resilience():
    """Test app resilience during instance failures"""
    compute_client = compute_v1.InstancesClient()
    project = 'my-project'
    zone = 'us-central1-a'
    instance_group = 'myapp-ig'

    # Get healthy instance count before chaos
    instances = compute_client.list(project=project, zone=zone)
    healthy_count = len([i for i in instances if i.status == 'RUNNING'])

    # Make baseline requests
    success_count = 0
    for _ in range(100):
        try:
            response = requests.get('https://myapp.example.com/health')
            if response.status_code == 200:
                success_count += 1
        except:
            pass

    baseline_success_rate = success_count / 100
    assert baseline_success_rate > 0.95

    # Inject chaos - delete random instance
    instances_list = list(instances)
    victim = random.choice(instances_list)
    compute_client.delete(project=project, zone=zone, instance=victim.name)

    # Continue making requests during chaos
    chaos_success_count = 0
    for _ in range(100):
        try:
            response = requests.get('https://myapp.example.com/health')
            if response.status_code == 200:
                chaos_success_count += 1
        except:
            pass
        time.sleep(0.5)

    chaos_success_rate = chaos_success_count / 100

    # Assert system remains available (>90% success)
    assert chaos_success_rate > 0.90

    # Verify auto-healing
    time.sleep(60)
    instances = compute_client.list(project=project, zone=zone)
    recovered_count = len([i for i in instances if i.status == 'RUNNING'])
    assert recovered_count == healthy_count

Health Checks

Liveness Probes

Python Flask Liveness Endpoint:

from flask import Flask, jsonify
import psutil

app = Flask(__name__)

@app.route('/healthz')
def liveness():
    """Liveness probe - is the application running?"""
    # Check critical dependencies
    try:
        # Verify app can still process requests
        health_status = {
            'status': 'healthy',
            'timestamp': time.time()
        }
        return jsonify(health_status), 200
    except Exception as e:
        return jsonify({
            'status': 'unhealthy',
            'error': str(e)
        }), 503

@app.route('/healthz/detailed')
def detailed_liveness():
    """Detailed health check for debugging"""
    try:
        cpu_percent = psutil.cpu_percent(interval=1)
        memory = psutil.virtual_memory()

        health = {
            'status': 'healthy',
            'timestamp': time.time(),
            'cpu_percent': cpu_percent,
            'memory_percent': memory.percent,
            'memory_available_mb': memory.available / 1024 / 1024
        }

        # Check if system is under extreme load
        if cpu_percent > 95 or memory.percent > 95:
            health['status'] = 'degraded'
            return jsonify(health), 200

        return jsonify(health), 200
    except Exception as e:
        return jsonify({
            'status': 'unhealthy',
            'error': str(e)
        }), 503

Readiness Probes

Python Readiness Check:

from flask import Flask, jsonify
from google.cloud import firestore
from redis import Redis
import requests

app = Flask(__name__)

@app.route('/ready')
def readiness():
    """Readiness probe - can the application serve traffic?"""
    checks = {
        'database': check_database(),
        'cache': check_cache(),
        'external_api': check_external_api()
    }

    all_ready = all(checks.values())

    response = {
        'status': 'ready' if all_ready else 'not ready',
        'checks': checks,
        'timestamp': time.time()
    }

    status_code = 200 if all_ready else 503
    return jsonify(response), status_code

def check_database():
    """Check database connectivity"""
    try:
        db = firestore.Client()
        # Try to read a test document
        doc_ref = db.collection('health').document('check')
        doc_ref.get(timeout=2)
        return True
    except Exception as e:
        app.logger.error(f"Database check failed: {e}")
        return False

def check_cache():
    """Check Redis connectivity"""
    try:
        redis_client = Redis(host='redis-host', port=6379, socket_timeout=2)
        redis_client.ping()
        return True
    except Exception as e:
        app.logger.error(f"Cache check failed: {e}")
        return False

def check_external_api():
    """Check external API availability"""
    try:
        response = requests.get(
            'https://api.example.com/health',
            timeout=2
        )
        return response.status_code == 200
    except Exception as e:
        app.logger.error(f"External API check failed: {e}")
        return False

Node.js Health Checks:

const express = require('express');
const {Firestore} = require('@google-cloud/firestore');
const redis = require('redis');
const axios = require('axios');

const app = express();
const db = new Firestore();
const redisClient = redis.createClient({
  host: 'redis-host',
  port: 6379,
});

// Liveness probe
app.get('/healthz', (req, res) => {
  res.status(200).json({
    status: 'healthy',
    timestamp: new Date().toISOString(),
  });
});

// Readiness probe
app.get('/ready', async (req, res) => {
  const checks = {
    database: await checkDatabase(),
    cache: await checkCache(),
    externalApi: await checkExternalApi(),
  };

  const allReady = Object.values(checks).every(check => check);

  res.status(allReady ? 200 : 503).json({
    status: allReady ? 'ready' : 'not ready',
    checks,
    timestamp: new Date().toISOString(),
  });
});

async function checkDatabase() {
  try {
    await db.collection('health').doc('check').get();
    return true;
  } catch (err) {
    console.error('Database check failed:', err);
    return false;
  }
}

async function checkCache() {
  return new Promise((resolve) => {
    redisClient.ping((err, result) => {
      if (err) {
        console.error('Cache check failed:', err);
        resolve(false);
      } else {
        resolve(result === 'PONG');
      }
    });
  });
}

async function checkExternalApi() {
  try {
    const response = await axios.get('https://api.example.com/health', {
      timeout: 2000,
    });
    return response.status === 200;
  } catch (err) {
    console.error('External API check failed:', err);
    return false;
  }
}

Startup Probes

GKE Configuration with All Probes:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: app
        image: gcr.io/project/myapp:v1
        ports:
        - containerPort: 8080

        # Startup probe - for slow-starting applications
        startupProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 0
          periodSeconds: 10
          failureThreshold: 30  # 5 minutes to start
          successThreshold: 1

        # Liveness probe - restart if unhealthy
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 10
          failureThreshold: 3
          successThreshold: 1
          timeoutSeconds: 5

        # Readiness probe - remove from service if not ready
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
          failureThreshold: 3
          successThreshold: 1
          timeoutSeconds: 3

        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"

Cloud Run Health Checks:

# cloud-run-service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: myapp
spec:
  template:
    metadata:
      annotations:
        # Startup timeout
        run.googleapis.com/startup-cpu-boost: 'true'
    spec:
      containerConcurrency: 80
      timeoutSeconds: 300
      containers:
      - image: gcr.io/project/myapp:v1
        ports:
        - containerPort: 8080
        # Liveness probe
        livenessProbe:
          httpGet:
            path: /healthz
          initialDelaySeconds: 10
          periodSeconds: 10
        # Startup probe
        startupProbe:
          httpGet:
            path: /healthz
          initialDelaySeconds: 0
          periodSeconds: 1
          failureThreshold: 3
        resources:
          limits:
            memory: 512Mi
            cpu: '1'

Traffic Management

Load Balancing

Cloud Run Traffic Split:

# Split traffic between revisions
gcloud run services update-traffic myservice \
  --to-revisions=myservice-v1=50,myservice-v2=50 \
  --region=us-central1

# Split with tags
gcloud run services update-traffic myservice \
  --to-tags=stable=80,canary=20 \
  --region=us-central1

# Route based on URL
gcloud run services update-traffic myservice \
  --to-revisions=myservice-v1=100 \
  --tag=stable \
  --region=us-central1

# Access via: https://stable---myservice-uc.a.run.app

GKE with Istio Traffic Management:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: myapp
spec:
  hosts:
  - myapp.example.com
  http:
  # Route beta users to v2
  - match:
    - headers:
        cookie:
          exact: "version=beta"
    route:
    - destination:
        host: myapp
        subset: v2
      weight: 100

  # Route specific users to canary
  - match:
    - headers:
        x-user-id:
          prefix: "test-"
    route:
    - destination:
        host: myapp
        subset: canary
      weight: 100

  # Default traffic split
  - route:
    - destination:
        host: myapp
        subset: v1
      weight: 90
    - destination:
        host: myapp
        subset: v2
      weight: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: myapp
spec:
  host: myapp
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: canary
    labels:
      version: canary

Best Practices

Monitoring Best Practices

  1. Implement Comprehensive Observability
  2. Use Cloud Monitoring for metrics
  3. Implement Cloud Trace for distributed tracing
  4. Use Cloud Logging for structured logs
  5. Set up Cloud Error Reporting for error tracking
  6. Enable Cloud Profiler for performance analysis

  7. Custom Metrics Strategy

  8. Create business KPI metrics (orders, revenue, conversions)
  9. Monitor application-specific metrics (cache hit rate, queue depth)
  10. Use metric labels for dimensional data
  11. Set up log-based metrics for derived data

  12. Alerting and SLOs

  13. Define SLIs (Service Level Indicators)
  14. Set SLOs (Service Level Objectives)
  15. Create alerting policies with appropriate thresholds
  16. Use error budgets for release decisions
  17. Implement notification channels (email, Slack, PagerDuty)

  18. Logging Standards

  19. Use structured logging (JSON format)
  20. Include correlation IDs in all logs
  21. Log at appropriate levels (DEBUG, INFO, WARNING, ERROR)
  22. Avoid logging sensitive data (PII, credentials)
  23. Use sampling for high-volume logs

  24. Observability in Code

  25. Add tracing to all microservices
  26. Include context propagation across services
  27. Monitor external API calls
  28. Track database query performance
  29. Record custom metrics for business events

Deployment Best Practices

  1. CI/CD Pipeline
  2. Automate all builds and deployments
  3. Run tests in pipeline (unit, integration, e2e)
  4. Perform security scans (Trivy, Snyk)
  5. Use artifact repositories (GCR, Artifact Registry)
  6. Implement approval gates for production

  7. Deployment Strategies

  8. Use blue-green for major changes
  9. Use canary for gradual rollouts
  10. Use rolling updates for minor changes
  11. Implement feature flags for controlled releases
  12. Always have rollback procedures

  13. Environment Management

  14. Separate dev, staging, production environments
  15. Use infrastructure as code (Terraform, Deployment Manager)
  16. Environment-specific configurations
  17. Isolate production data
  18. Use least privilege IAM for each environment

  19. Version Control

  20. Tag releases with semantic versioning
  21. Use GitOps for deployment automation
  22. Maintain deployment history
  23. Document rollback procedures
  24. Use branching strategy (GitFlow, trunk-based)

  25. Testing Strategy

  26. Run unit tests on every commit
  27. Run integration tests before deployment
  28. Perform load testing before major releases
  29. Conduct chaos engineering in staging
  30. Use canary deployments as production tests

Performance Best Practices

  1. Application Performance
  2. Profile with Cloud Profiler regularly
  3. Optimize database queries
  4. Implement caching (Memorystore, CDN)
  5. Use async processing for long tasks
  6. Optimize container images (multi-stage builds)

  7. Resource Management

  8. Right-size compute resources
  9. Use autoscaling appropriately
  10. Implement connection pooling
  11. Use regional resources for low latency
  12. Monitor and optimize costs

  13. API Performance

  14. Implement rate limiting
  15. Use API Gateway for centralized management
  16. Cache frequently accessed data
  17. Use pagination for large datasets
  18. Implement request compression

Deployment Scenarios

Scenario 1: Zero-Downtime Production Deployment

Challenge: Deploy new version to production without any downtime or user impact.

Solution:

# cloudbuild-zero-downtime.yaml
steps:
  # Build and test
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA', '.']

  - name: 'python:3.9'
    entrypoint: 'python'
    args: ['-m', 'pytest', 'tests/']

  # Deploy to Cloud Run with no traffic
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'myapp'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--tag'
      - 'rev-$SHORT_SHA'
      - '--no-traffic'
      - '--region'
      - 'us-central1'

  # Smoke test new revision
  - name: 'gcr.io/cloud-builders/curl'
    args:
      - '-f'
      - 'https://rev-$SHORT_SHA---myapp-uc.a.run.app/health'

  # Gradual traffic migration
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'services'
      - 'update-traffic'
      - 'myapp'
      - '--to-revisions'
      - 'rev-$SHORT_SHA=100'
      - '--region'
      - 'us-central1'

Key Points: - Deploy with --no-traffic first - Test new revision before routing traffic - Use instant traffic switch (100% to new) - Keep old revision for quick rollback

Scenario 2: Canary Deployment with Automated Rollback

Challenge: Deploy new version gradually, automatically rollback if error rate increases.

Solution:

# cloudbuild-canary.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA', '.']

  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA']

  # Deploy canary
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'myapp'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--tag'
      - 'canary'
      - '--no-traffic'
      - '--region'
      - 'us-central1'

  # 10% traffic to canary
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'services'
      - 'update-traffic'
      - 'myapp'
      - '--to-tags'
      - 'stable=90,canary=10'
      - '--region'
      - 'us-central1'

  # Monitor for 5 minutes
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        sleep 300
        ERROR_RATE=$(gcloud monitoring time-series list \
          --filter='metric.type="run.googleapis.com/request_count"
            AND metric.label.response_code_class="5xx"
            AND metric.label.service_name="myapp"' \
          --format='value(point.value.int64Value)' \
          --interval-start="$(date -u -d '5 minutes ago' '+%Y-%m-%dT%H:%M:%SZ')" \
          | awk '{sum+=$1} END {print sum}')

        TOTAL_REQUESTS=$(gcloud monitoring time-series list \
          --filter='metric.type="run.googleapis.com/request_count"
            AND metric.label.service_name="myapp"' \
          --format='value(point.value.int64Value)' \
          --interval-start="$(date -u -d '5 minutes ago' '+%Y-%m-%dT%H:%M:%SZ')" \
          | awk '{sum+=$1} END {print sum}')

        ERROR_PERCENTAGE=$(echo "scale=2; $ERROR_RATE * 100 / $TOTAL_REQUESTS" | bc)

        if (( $(echo "$ERROR_PERCENTAGE > 1.0" | bc -l) )); then
          echo "Error rate $ERROR_PERCENTAGE% exceeds threshold, rolling back"
          gcloud run services update-traffic myapp \
            --to-tags stable=100 \
            --region us-central1
          exit 1
        fi

  # Increase to 50%
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'services'
      - 'update-traffic'
      - 'myapp'
      - '--to-tags'
      - 'stable=50,canary=50'
      - '--region'
      - 'us-central1'

  # Monitor again
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'bash'
    args:
      - '-c'
      - 'sleep 300 && # monitoring logic repeated'

  # Full rollout
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'services'
      - 'update-traffic'
      - 'myapp'
      - '--to-tags'
      - 'canary=100'
      - '--region'
      - 'us-central1'

  # Update stable tag
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'services'
      - 'update-traffic'
      - 'myapp'
      - '--update-tags'
      - 'stable=LATEST'
      - '--region'
      - 'us-central1'

Scenario 3: Multi-Region Deployment

Challenge: Deploy application to multiple regions with proper monitoring and failover.

Solution:

# cloudbuild-multiregion.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA', '.']

  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA']

  # Deploy to us-central1
  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-us-central1'
    args:
      - 'run'
      - 'deploy'
      - 'myapp'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--region'
      - 'us-central1'
      - '--platform'
      - 'managed'

  # Deploy to us-east1
  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-us-east1'
    args:
      - 'run'
      - 'deploy'
      - 'myapp'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--region'
      - 'us-east1'
      - '--platform'
      - 'managed'

  # Deploy to europe-west1
  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-europe-west1'
    args:
      - 'run'
      - 'deploy'
      - 'myapp'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--region'
      - 'europe-west1'
      - '--platform'
      - 'managed'

  # Update global load balancer
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'compute'
      - 'backend-services'
      - 'update'
      - 'myapp-backend'
      - '--global'

  # Verify all regions
  - name: 'gcr.io/cloud-builders/curl'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        for region in us-central1 us-east1 europe-west1; do
          echo "Testing $region"
          curl -f "https://myapp-$region-uc.a.run.app/health" || exit 1
        done

Scenario 4: Database Migration with Zero Downtime

Challenge: Deploy application with database schema changes without downtime.

Solution:

# cloudbuild-db-migration.yaml
steps:
  # Build new version
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA', '.']

  # Run database migration
  - name: 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
    entrypoint: 'python'
    args:
      - '-m'
      - 'alembic'
      - 'upgrade'
      - 'head'
    env:
      - 'DB_HOST=${_DB_HOST}'
      - 'DB_NAME=${_DB_NAME}'

  # Deploy new version (compatible with old schema)
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'myapp'
      - '--image'
      - 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
      - '--region'
      - 'us-central1'

  # Wait for deployment to stabilize
  - name: 'gcr.io/cloud-builders/gcloud'
    entrypoint: 'bash'
    args:
      - '-c'
      - 'sleep 60'

  # Verify application health
  - name: 'gcr.io/cloud-builders/curl'
    args: ['-f', 'https://myapp-uc.a.run.app/health']

  # Clean up old schema (if needed)
  - name: 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
    entrypoint: 'python'
    args:
      - '-m'
      - 'scripts.cleanup_old_schema'
    env:
      - 'DB_HOST=${_DB_HOST}'
      - 'DB_NAME=${_DB_NAME}'

substitutions:
  _DB_HOST: 'cloudsql-proxy:5432'
  _DB_NAME: 'production'

Migration Strategy: 1. Make schema changes backward compatible 2. Deploy code that works with both old and new schema 3. Run migration to add new columns/tables 4. Deploy code that uses new schema 5. Remove old columns/tables in later migration

Scenario 5: Feature Flag Rollout

Challenge: Deploy new feature behind feature flag, gradually enable for users.

Python Feature Flag Implementation:

# app/feature_flags.py
from google.cloud import firestore
import functools

class FeatureFlags:
    def __init__(self, project_id: str):
        self.db = firestore.Client(project=project_id)
        self.cache = {}

    def is_enabled(self, flag_name: str, user_id: str = None) -> bool:
        """Check if feature flag is enabled for user"""
        # Check cache first
        cache_key = f"{flag_name}:{user_id}"
        if cache_key in self.cache:
            return self.cache[cache_key]

        # Get flag configuration
        flag_doc = self.db.collection('feature_flags').document(flag_name).get()
        if not flag_doc.exists:
            return False

        flag_config = flag_doc.to_dict()

        # Check if globally enabled
        if flag_config.get('enabled', False):
            return True

        # Check rollout percentage
        rollout_pct = flag_config.get('rollout_percentage', 0)
        if user_id:
            # Consistent hashing for user
            user_hash = hash(user_id) % 100
            enabled = user_hash < rollout_pct
            self.cache[cache_key] = enabled
            return enabled

        return False

    def require_flag(self, flag_name: str):
        """Decorator to require feature flag"""
        def decorator(f):
            @functools.wraps(f)
            def wrapper(*args, **kwargs):
                user_id = kwargs.get('user_id') or getattr(g, 'user_id', None)
                if not self.is_enabled(flag_name, user_id):
                    return {'error': 'Feature not available'}, 403
                return f(*args, **kwargs)
            return wrapper
        return decorator

# Usage
from flask import Flask, g
app = Flask(__name__)
flags = FeatureFlags(project_id='my-project')

@app.route('/api/new-feature', methods=['POST'])
@flags.require_flag('new_checkout_flow')
def new_feature():
    # New feature implementation
    return {'result': 'success'}

Feature Flag Configuration (Firestore):

{
  "feature_flags/new_checkout_flow": {
    "enabled": false,
    "rollout_percentage": 10,
    "description": "New checkout flow with improved UX",
    "created_at": "2024-01-15T10:00:00Z"
  }
}

Scenario 6: Rollback Procedure

Challenge: Quickly rollback a problematic deployment.

Cloud Run Rollback:

# List revisions
gcloud run revisions list --service=myapp --region=us-central1

# Identify working revision
PREVIOUS_REVISION=$(gcloud run revisions list \
  --service=myapp \
  --region=us-central1 \
  --format='value(name)' \
  --sort-by='~metadata.creationTimestamp' \
  --limit=2 | tail -1)

# Rollback to previous revision
gcloud run services update-traffic myapp \
  --to-revisions=$PREVIOUS_REVISION=100 \
  --region=us-central1

# Verify rollback
curl https://myapp-uc.a.run.app/health

GKE Rollback:

# Check rollout history
kubectl rollout history deployment/myapp

# Rollback to previous version
kubectl rollout undo deployment/myapp

# Rollback to specific revision
kubectl rollout undo deployment/myapp --to-revision=3

# Monitor rollback
kubectl rollout status deployment/myapp

Automated Rollback on High Error Rate:

# scripts/auto_rollback.py
from google.cloud import monitoring_v3, run_v2
import time

def check_error_rate(project_id: str, service_name: str) -> float:
    """Check error rate from Cloud Monitoring"""
    client = monitoring_v3.MetricServiceClient()
    project_name = f"projects/{project_id}"

    # Query for error rate
    interval = monitoring_v3.TimeInterval({
        "end_time": {"seconds": int(time.time())},
        "start_time": {"seconds": int(time.time() - 300)},  # Last 5 min
    })

    results = client.list_time_series(
        request={
            "name": project_name,
            "filter": f'metric.type="run.googleapis.com/request_count" '
                     f'AND metric.label.response_code_class="5xx" '
                     f'AND resource.label.service_name="{service_name}"',
            "interval": interval,
        }
    )

    error_count = sum([point.value.int64_value
                      for result in results
                      for point in result.points])

    # Get total requests
    total_results = client.list_time_series(
        request={
            "name": project_name,
            "filter": f'metric.type="run.googleapis.com/request_count" '
                     f'AND resource.label.service_name="{service_name}"',
            "interval": interval,
        }
    )

    total_count = sum([point.value.int64_value
                       for result in total_results
                       for point in result.points])

    if total_count == 0:
        return 0

    return (error_count / total_count) * 100

def rollback_service(project_id: str, service_name: str, region: str):
    """Rollback to previous revision"""
    client = run_v2.ServicesClient()

    # Get current service
    service_path = f"projects/{project_id}/locations/{region}/services/{service_name}"
    service = client.get_service(name=service_path)

    # Get previous revision
    revisions = list(service.traffic)
    if len(revisions) < 2:
        print("No previous revision to rollback to")
        return

    previous_revision = revisions[1].revision

    # Update traffic to previous revision
    service.traffic = [{
        "revision": previous_revision,
        "percent": 100
    }]

    client.update_service(service=service)
    print(f"Rolled back to {previous_revision}")

# Monitor and auto-rollback
if __name__ == "__main__":
    project_id = "my-project"
    service_name = "myapp"
    region = "us-central1"

    while True:
        error_rate = check_error_rate(project_id, service_name)
        print(f"Current error rate: {error_rate:.2f}%")

        if error_rate > 5.0:  # 5% threshold
            print("Error rate exceeds threshold, initiating rollback")
            rollback_service(project_id, service_name, region)
            break

        time.sleep(60)  # Check every minute

Scenario 7: A/B Testing Deployment

Challenge: Deploy two versions for A/B testing with proper tracking.

Cloud Run A/B Setup:

# Deploy version A (control)
gcloud run deploy myapp \
  --image gcr.io/project/myapp:version-a \
  --tag version-a \
  --region us-central1

# Deploy version B (variant)
gcloud run deploy myapp \
  --image gcr.io/project/myapp:version-b \
  --tag version-b \
  --no-traffic \
  --region us-central1

# Split traffic 50/50
gcloud run services update-traffic myapp \
  --to-tags version-a=50,version-b=50 \
  --region us-central1

A/B Testing with Header Routing (Istio):

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: myapp-ab-test
spec:
  hosts:
  - myapp.example.com
  http:
  - match:
    - headers:
        x-ab-test:
          exact: "variant-b"
    route:
    - destination:
        host: myapp
        subset: version-b
  - route:
    - destination:
        host: myapp
        subset: version-a
      weight: 50
    - destination:
        host: myapp
        subset: version-b
      weight: 50

Tracking A/B Test Results:

# app/ab_testing.py
from google.cloud import monitoring_v3
import hashlib

def get_ab_variant(user_id: str) -> str:
    """Consistently assign user to A/B test variant"""
    hash_value = int(hashlib.md5(user_id.encode()).hexdigest(), 16)
    return 'b' if hash_value % 2 == 0 else 'a'

def track_conversion(user_id: str, variant: str, conversion_value: float):
    """Track conversion for A/B test"""
    monitoring = CloudMonitoring(project_id='my-project')
    monitoring.write_custom_metric(
        metric_type=f"ab_test/conversion",
        value=conversion_value,
        labels={
            'variant': variant,
            'user_id': user_id
        }
    )

# Usage in endpoint
@app.route('/api/checkout', methods=['POST'])
def checkout():
    user_id = g.user_id
    variant = get_ab_variant(user_id)

    if variant == 'b':
        result = new_checkout_flow(request.json)
    else:
        result = old_checkout_flow(request.json)

    if result['success']:
        track_conversion(user_id, variant, result['order_total'])

    return result

Scenario 8: Microservices Deployment Orchestration

Challenge: Deploy multiple microservices with dependencies in correct order.

Solution:

# cloudbuild-microservices.yaml
steps:
  # Build all services in parallel
  - name: 'gcr.io/cloud-builders/docker'
    id: 'build-auth'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/auth:$COMMIT_SHA', './services/auth']
    waitFor: ['-']

  - name: 'gcr.io/cloud-builders/docker'
    id: 'build-orders'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/orders:$COMMIT_SHA', './services/orders']
    waitFor: ['-']

  - name: 'gcr.io/cloud-builders/docker'
    id: 'build-payments'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/payments:$COMMIT_SHA', './services/payments']
    waitFor: ['-']

  - name: 'gcr.io/cloud-builders/docker'
    id: 'build-notifications'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/notifications:$COMMIT_SHA', './services/notifications']
    waitFor: ['-']

  # Push all images
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/auth:$COMMIT_SHA']
    waitFor: ['build-auth']

  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/orders:$COMMIT_SHA']
    waitFor: ['build-orders']

  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/payments:$COMMIT_SHA']
    waitFor: ['build-payments']

  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/notifications:$COMMIT_SHA']
    waitFor: ['build-notifications']

  # Deploy in dependency order: auth first (no dependencies)
  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-auth'
    args:
      - 'run'
      - 'deploy'
      - 'auth-service'
      - '--image'
      - 'gcr.io/$PROJECT_ID/auth:$COMMIT_SHA'
      - '--region'
      - 'us-central1'
    waitFor: ['push-auth']

  # Deploy services that depend on auth
  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-orders'
    args:
      - 'run'
      - 'deploy'
      - 'orders-service'
      - '--image'
      - 'gcr.io/$PROJECT_ID/orders:$COMMIT_SHA'
      - '--region'
      - 'us-central1'
      - '--set-env-vars'
      - 'AUTH_SERVICE_URL=https://auth-service-uc.a.run.app'
    waitFor: ['deploy-auth']

  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-payments'
    args:
      - 'run'
      - 'deploy'
      - 'payments-service'
      - '--image'
      - 'gcr.io/$PROJECT_ID/payments:$COMMIT_SHA'
      - '--region'
      - 'us-central1'
      - '--set-env-vars'
      - 'AUTH_SERVICE_URL=https://auth-service-uc.a.run.app'
    waitFor: ['deploy-auth']

  # Deploy notifications last (depends on orders)
  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-notifications'
    args:
      - 'run'
      - 'deploy'
      - 'notifications-service'
      - '--image'
      - 'gcr.io/$PROJECT_ID/notifications:$COMMIT_SHA'
      - '--region'
      - 'us-central1'
      - '--set-env-vars'
      - 'ORDERS_SERVICE_URL=https://orders-service-uc.a.run.app'
    waitFor: ['deploy-orders']

  # Run integration tests
  - name: 'python:3.9'
    entrypoint: 'python'
    args:
      - '-m'
      - 'pytest'
      - 'tests/integration/test_microservices.py'
    env:
      - 'AUTH_URL=https://auth-service-uc.a.run.app'
      - 'ORDERS_URL=https://orders-service-uc.a.run.app'
    waitFor: ['deploy-notifications']

Exam Tips

Monitoring and Observability Questions

  1. Custom Metrics
  2. Know how to create custom metrics using Cloud Monitoring API
  3. Understand metric types: GAUGE, DELTA, CUMULATIVE
  4. Remember to use labels for dimensional data
  5. Metric naming convention: custom.googleapis.com/metric_name

  6. Distributed Tracing

  7. Prefer OpenTelemetry over native Cloud Trace API
  8. Auto-instrumentation for common frameworks (Flask, Express)
  9. Context propagation across microservices
  10. Span attributes for filtering and analysis

  11. Error Reporting

  12. Automatic error grouping by stack trace
  13. HTTP context for web applications
  14. User context for tracking affected users
  15. Integration with logging and monitoring

  16. Log-Based Metrics

  17. Create metrics from structured logs
  18. Use for derived metrics not available in Cloud Monitoring
  19. Support for counter and distribution metrics
  20. Filter expressions for log selection

CI/CD Pipeline Questions

  1. Cloud Build
  2. cloudbuild.yaml is the default configuration file
  3. Built-in substitutions: $PROJECT_ID, $COMMIT_SHA, $SHORT_SHA, $TAG_NAME
  4. Custom substitutions start with underscore: $_ENVIRONMENT
  5. Use waitFor to control step dependencies
  6. waitFor: ['-'] means run in parallel

  7. Build Triggers

  8. Can trigger on push, tag, or pull request
  9. Branch patterns use regex: ^main$, ^feature/.*$
  10. Tag patterns for releases: ^v.*
  11. Substitutions can be overridden per trigger

  12. Container Registry

  13. GCR (Container Registry) vs Artifact Registry
  14. Artifact Registry is preferred for new projects
  15. Images: gcr.io/PROJECT_ID/IMAGE:TAG
  16. Vulnerability scanning available

  17. Testing in Pipeline

  18. Unit tests should run before building container
  19. Integration tests after deployment to staging
  20. Load tests before production deployment
  21. Security scans (Trivy, Snyk) on container images

Deployment Strategy Questions

  1. Blue-Green Deployment
  2. Two identical environments (blue and green)
  3. Switch traffic instantly between versions
  4. Easy rollback by switching back
  5. Cloud Run: Use --no-traffic then switch
  6. App Engine: Use --no-promote then set-traffic

  7. Canary Deployment

  8. Gradual rollout to subset of users
  9. Monitor metrics at each stage
  10. Typically: 10% β†’ 50% β†’ 100%
  11. Cloud Run: Use traffic splitting by percentage
  12. Automated rollback based on error rate

  13. Rolling Deployment

  14. Used in GKE with Deployments
  15. maxSurge: Extra pods during update
  16. maxUnavailable: Pods down during update
  17. Health checks are critical
  18. Automatic rollback on failed health checks

  19. Traffic Splitting

  20. Cloud Run: By revision or tag
  21. App Engine: By version
  22. GKE with Istio: By headers, cookies, or percentage
  23. Use tags for persistent URLs: tag---service-region.a.run.app

Health Check Questions

  1. Liveness Probe
  2. Should the container be restarted?
  3. Simple check: Can the app respond?
  4. Don't check dependencies (use readiness for that)
  5. Failed liveness β†’ container restart

  6. Readiness Probe

  7. Can the container serve traffic?
  8. Check all dependencies (database, cache, APIs)
  9. Failed readiness β†’ removed from load balancer
  10. Container not restarted

  11. Startup Probe

  12. For slow-starting applications
  13. Disables liveness/readiness until startup succeeds
  14. Prevents premature restarts during initialization
  15. Use longer failureThreshold for startup time

  16. Probe Configuration

  17. initialDelaySeconds: Wait before first check
  18. periodSeconds: How often to check
  19. failureThreshold: Failures before action
  20. successThreshold: Successes to recover
  21. timeoutSeconds: Probe timeout

Common Exam Patterns

  1. Choose the right deployment strategy
  2. Zero downtime required β†’ Blue-green or Canary
  3. Gradual rollout with monitoring β†’ Canary
  4. Testing new version with subset β†’ A/B testing
  5. GKE with limited resources β†’ Rolling update
  6. Database migration β†’ Blue-green with compatible changes

  7. Monitoring integration

  8. Business metrics β†’ Custom metrics
  9. Request tracing β†’ Cloud Trace
  10. Error tracking β†’ Error Reporting
  11. Performance analysis β†’ Cloud Profiler
  12. Log analysis β†’ Log-based metrics

  13. CI/CD troubleshooting

  14. Build fails: Check dependencies, test, image size
  15. Deployment fails: Check IAM permissions, quotas
  16. Tests fail: Check environment variables, test data
  17. Slow builds: Use caching, parallel steps

  18. Traffic management

  19. Header-based routing β†’ Istio VirtualService
  20. Percentage-based split β†’ Cloud Run traffic split
  21. A/B testing β†’ Header routing or consistent hashing
  22. Multi-region β†’ Global Load Balancer

Quick Reference

Cloud Run Deployment:

gcloud run deploy SERVICE --image IMAGE --region REGION

Traffic Split:

gcloud run services update-traffic SERVICE --to-revisions=REV1=50,REV2=50

Build Trigger:

gcloud builds triggers create github --repo-name=REPO --branch-pattern=PATTERN

Rollback:

kubectl rollout undo deployment/NAME

Additional Resources