Gcp
GcpIntermediate

GCP Serverless Architecture: A Complete Implementation Guide

DevHub Team
5 min read
ServerlessCloud FunctionsCloud RunApp Engine

TL;DR

Master serverless architecture on Google Cloud Platform with this comprehensive guide covering Cloud Functions, Cloud Run, App Engine, and best practices

GCP Serverless Architecture: A Complete Implementation Guide

Google Cloud Platform offers multiple serverless computing options to build scalable and efficient applications without managing infrastructure. This guide explores the various serverless options and their implementation patterns.

$1

``mermaid

graph TB

subgraph "Compute Options"

A["Cloud Functions"]

B["Cloud Run"]

C["App Engine"]

end

subgraph "Event Sources"

D["HTTP"]

E["Pub/Sub"]

F["Storage"]

G["Firestore"]

end

subgraph "Integration"

H["API Gateway"]

I["Load Balancer"]

J["Cloud Tasks"]

end

A --> D

A --> E

B --> D

B --> H

C --> I

E --> J

F --> A

G --> A

classDef gcp fill:#1a73e8,stroke:#fff,color:#fff

class A,B,C,D,E,F,G,H,I,J gcp

`

$1

Service Use Case Benefits
Cloud Functions Event-driven Simplicity
Cloud Run Containers Flexibility
App Engine Web apps Managed platform

$1

$1

`typescript

import { HttpFunction } from '@google-cloud/functions-framework';

export const helloWorld: HttpFunction = (req, res) => {

const name = req.query.name || 'World';

res.send(Hello ${name}!);

};

`

$1

`typescript

import { CloudEvent } from '@google-cloud/functions-framework';

import { Storage } from '@google-cloud/storage';

import { PubSub } from '@google-cloud/pubsub';

export const processFile = async (cloudEvent: CloudEvent) => {

const storage = new Storage();

const pubsub = new PubSub();

const file = storage.bucket(cloudEvent.data.bucket)

.file(cloudEvent.data.name);

const [content] = await file.download();

// Process the file content

const result = await processContent(content);

// Publish result

await pubsub.topic('processed-files')

.publish(Buffer.from(JSON.stringify(result)));

};

`

$1

$1

`dockerfile

Dockerfile

FROM node:16-slim

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

ENV PORT=8080

EXPOSE 8080

CMD ["npm", "start"]

`

$1

`typescript

import express from 'express';

import { Firestore } from '@google-cloud/firestore';

const app = express();

const firestore = new Firestore();

app.post('/api/data', async (req, res) => {

try {

const docRef = firestore.collection('data').doc();

await docRef.set({

...req.body,

timestamp: new Date()

});

res.status(201).json({ id: docRef.id });

} catch (error) {

res.status(500).json({ error: error.message });

}

});

const port = process.env.PORT || 8080;

app.listen(port, () => {

console.log(Server running on port ${port});

});

`

$1

$1

`yaml

app.yaml

runtime: nodejs16

env: standard

automatic_scaling:

target_cpu_utilization: 0.65

min_instances: 1

max_instances: 10

env_variables:

NODE_ENV: "production"

handlers:

  • url: /.*
  • script: auto

    secure: always

    `

    $1

    `yaml

    service.yaml

    service: api

    runtime: nodejs16

    env_variables:

    DATABASE_URL: ${DATABASE_URL}

    API_KEY: ${API_KEY}

    vpc_access_connector:

    name: projects/${PROJECT_ID}/locations/${REGION}/connectors/vpc-connector

    `

    $1

    $1

    `typescript

    import { PubSub } from '@google-cloud/pubsub';

    export const publishMessage = async (

    topicName: string,

    data: any

    ): Promise => {

    const pubsub = new PubSub();

    const topic = pubsub.topic(topicName);

    const messageId = await topic.publish(

    Buffer.from(JSON.stringify(data))

    );

    return messageId;

    };

    export const subscribeTopic = async (

    subscriptionName: string,

    callback: (message: any) => Promise

    ): Promise => {

    const pubsub = new PubSub();

    const subscription = pubsub.subscription(subscriptionName);

    subscription.on('message', async (message) => {

    try {

    const data = JSON.parse(message.data.toString());

    await callback(data);

    message.ack();

    } catch (error) {

    console.error('Error processing message:', error);

    message.nack();

    }

    });

    };

    `

    $1

    $1

    Pattern Implementation Use Case
    Fan-out Pub/Sub + Functions Parallel processing
    Chain Cloud Tasks Sequential processing
    Aggregation Cloud Run + Firestore Data collection

    $1

    $1

    `typescript

    import { auth } from '@google-cloud/functions-framework';

    const authenticate = async (req: any, res: any, next: any) => {

    try {

    const token = req.headers.authorization?.split('Bearer ')[1];

    if (!token) {

    throw new Error('No token provided');

    }

    const decodedToken = await auth().verifyIdToken(token);

    req.user = decodedToken;

    next();

    } catch (error) {

    res.status(401).json({ error: 'Unauthorized' });

    }

    };

    export const secureFunction: HttpFunction = (req, res) => {

    authenticate(req, res, () => {

    // Protected function logic

    res.json({ message: 'Secure endpoint' });

    });

    };

    `

    $1

    `typescript

    const checkRole = (requiredRole: string) => {

    return (req: any, res: any, next: any) => {

    const userRole = req.user?.role;

    if (userRole !== requiredRole) {

    return res.status(403).json({

    error: 'Forbidden'

    });

    }

    next();

    };

    };

    app.post('/admin', authenticate, checkRole('admin'), (req, res) => {

    res.json({ message: 'Admin endpoint' });

    });

    `

    $1

    $1

    `typescript

    import { Logging } from '@google-cloud/logging';

    const logging = new Logging();

    const log = logging.log('my-service');

    const writeLog = async (

    severity: string,

    message: string,

    metadata?: any

    ) => {

    const entry = log.entry({

    severity: severity.toUpperCase(),

    resource: {

    type: 'cloud_function',

    labels: {

    function_name: process.env.FUNCTION_NAME,

    region: process.env.FUNCTION_REGION,

    },

    },

    ...metadata,

    }, message);

    await log.write(entry);

    };

    `

    $1

    Metric Description Alert Threshold
    Latency Request processing time > 1000ms
    Error Rate Failed requests > 1%
    Invocations Function calls > 1000/min

    $1

    $1

    1. Cold Start Mitigation

    `typescript

    // Initialize global variables

    const storage = new Storage();

    const firestore = new Firestore();

    export const optimizedFunction = async (req: any, res: any) => {

    try {

    // Reuse initialized clients

    const result = await processRequest(storage, firestore, req.body);

    res.json(result);

    } catch (error) {

    res.status(500).json({ error: error.message });

    }

    };

    `

    2. Connection Pooling

    `typescript

    import { Pool } from 'pg';

    const pool = new Pool({

    max: 1,

    min: 0,

    idleTimeoutMillis: 120000,

    connectionTimeoutMillis: 10000,

    });

    export const dbFunction = async (req: any, res: any) => {

    const client = await pool.connect();

    try {

    const result = await client.query('SELECT * FROM items');

    res.json(result.rows);

    } finally {

    client.release();

    }

    };

    ``

    $1

    $1

    Issue Cause Solution
    Cold Starts Infrequent invocation Minimum instances
    Memory Leaks Resource management Proper cleanup
    Timeouts Long processing Async processing

    $1

    1. [Cloud Functions Documentation](https://cloud.google.com/functions/docs)

    2. [Cloud Run Documentation](https://cloud.google.com/run/docs)

    3. [App Engine Documentation](https://cloud.google.com/appengine/docs)

    4. [Serverless Computing](https://cloud.google.com/serverless)

    5. [Security Best Practices](https://cloud.google.com/security)

    6. [Monitoring and Logging](https://cloud.google.com/monitoring)

  • [GCP Vertex AI](/posts/gcp/vertex-ai) - ML workloads
  • [GCP Cloud Run Jobs](/posts/gcp/cloud-run-jobs) - Batch processing
  • [GCP Cost Optimization](/posts/gcp/cost-optimization) - Optimize costs
  • [GCP vs AWS](/posts/gcp/vs-aws-2024) - Cloud comparison
  • Why This Matters

    Understanding the business and technical context helps you make informed decisions rather than blindly following patterns.

    Trade-offs to Consider

    Every architectural decision involves trade-offs. Consider your specific requirements, team expertise, and scale when evaluating options.

    When NOT to Use This

    Knowing when a solution doesn't apply is as valuable as knowing when it does. Consider alternatives for your specific situation.

    Decision Framework

    Use this framework to evaluate whether this approach is right for your use case based on your specific constraints and requirements.