GCPCloudFunctions gcp-cloud-functions

Google Cloud Platform 上的无服务器计算解决方案,支持事件驱动的函数部署,适用于HTTP API、消息处理、数据触发等多种场景。

Serverless 0 次安装 0 次浏览 更新于 3/4/2026

GCP 云函数

概览

Google Cloud Functions 使您能够在 Google Cloud Platform 上实现事件驱动的无服务器计算。构建具有自动扩展、集成安全性和与 Google Cloud 服务无缝集成的函数,以实现快速开发。

何时使用

  • HTTP API 和 webhook
  • Pub/Sub 消息处理
  • 存储桶事件
  • Firestore 数据库触发器
  • Cloud Scheduler 作业
  • 实时数据处理
  • 图像和视频处理
  • 数据管道编排

实施示例

1. 使用 gcloud CLI 创建云函数

# 安装 Google Cloud SDK
curl https://sdk.cloud.google.com | bash
exec -l $SHELL

# 初始化和认证
gcloud init
gcloud auth application-default login

# 设置项目
gcloud config set project MY_PROJECT_ID

# 创建服务账户
gcloud iam service-accounts create cloud-function-sa \
  --display-name "Cloud Function Service Account"

# 授权
gcloud projects add-iam-policy-binding MY_PROJECT_ID \
  --member="serviceAccount:cloud-function-sa@MY_PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/cloudfunctions.invoker"

# 部署 HTTP 函数
gcloud functions deploy my-http-function \
  --gen2 \
  --runtime nodejs18 \
  --region us-central1 \
  --source ./src \
  --entry-point httpHandler \
  --trigger-http \
  --allow-unauthenticated \
  --timeout 60 \
  --memory 256MB \
  --max-instances 100 \
  --set-env-vars NODE_ENV=production,API_KEY=xxx \
  --service-account cloud-function-sa@MY_PROJECT_ID.iam.gserviceaccount.com

# 部署 Pub/Sub 函数
gcloud functions deploy my-pubsub-function \
  --gen2 \
  --runtime nodejs18 \
  --region us-central1 \
  --source ./src \
  --entry-point pubsubHandler \
  --trigger-topic my-topic \
  --memory 256MB \
  --timeout 300 \
  --service-account cloud-function-sa@MY_PROJECT_ID.iam.gserviceaccount.com

# 部署 Cloud Storage 函数
gcloud functions deploy my-storage-function \
  --gen2 \
  --runtime nodejs18 \
  --region us-central1 \
  --source ./src \
  --entry-point storageHandler \
  --trigger-bucket my-bucket \
  --trigger-location us-central1 \
  --timeout 60 \
  --service-account cloud-function-sa@MY_PROJECT_ID.iam.gserviceaccount.com

# 列出函数
gcloud functions list

# 获取函数详情
gcloud functions describe my-http-function --gen2 --region us-central1

# 调用函数
gcloud functions call my-http-function \
  --region us-central1 \
  --data '{"name":"John"}'

# 查看日志
gcloud functions logs read my-http-function --limit 50 --gen2 --region us-central1

# 删除函数
gcloud functions delete my-http-function --gen2 --region us-central1

2. 云函数实现(Node.js)

// HTTP 触发器函数
exports.httpHandler = async (req, res) => {
  try {
    // 启用 CORS
    res.set('Access-Control-Allow-Origin', '*');
    res.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');

    if (req.method === 'OPTIONS') {
      res.status(204).send('');
      return;
    }

    // 解析请求
    const { name } = req.query;

    if (!name) {
      return res.status(400).json({ error: 'Name is required' });
    }

    // 使用 Cloud Logging 记录日志
    console.log(JSON.stringify({
      severity: 'INFO',
      message: 'Processing request',
      name: name,
      requestId: req.id
    }));

    // 业务逻辑
    const response = {
      message: `Hello ${name}!`,
      timestamp: new Date().toISOString()
    };

    res.status(200).json(response);
  } catch (error) {
    console.error(JSON.stringify({
      severity: 'ERROR',
      message: error.message,
      stack: error.stack
    }));

    res.status(500).json({ error: 'Internal server error' });
  }
};

// Pub/Sub 触发器函数
exports.pubsubHandler = async (message, context) => {
  try {
    // 解码 Pub/Sub 消息
    const pubsubMessage = message.data
      ? Buffer.from(message.data, 'base64').toString()
      : null;

    console.log('Received message:', pubsubMessage);

    // 解析消息
    const data = JSON.parse(pubsubMessage);

    // 异步处理消息
    await processMessage(data);

    console.log('Message processed successfully');
  } catch (error) {
    console.error('Error processing message:', error);
    throw error; // 函数将重试
  }
};

// Cloud Storage 触发器函数
exports.storageHandler = async (file, context) => {
  try {
    const { name, bucket } = file;

    console.log(JSON.stringify({
      message: 'Processing storage event',
      bucket: bucket,
      file: name,
      eventId: context.eventId,
      eventType: context.eventType
    }));

    // 检查文件类型
    if (!name.endsWith('.jpg') && !name.endsWith('.png')) {
      console.log('Skipping non-image file');
      return;
    }

    // 处理图像
    await processImage(bucket, name);

    console.log('Image processed successfully');
  } catch (error) {
    console.error('Error processing file:', error);
    throw error;
  }
};

// Cloud Scheduler (CRON) 函数
exports.cronHandler = async (req, res) => {
  try {
    console.log('Scheduled job started');

    // 运行批处理作业
    await performBatchJob();

    res.status(200).json({ message: 'Batch job completed' });
  } catch (error) {
    console.error('Error in batch job:', error);
    res.status(500).json({ error: error.message });
  }
};

// 辅助函数
async function processMessage(data) {
  // 业务逻辑
  return new Promise(resolve => {
    setTimeout(() => resolve(), 1000);
  });
}

async function processImage(bucket, filename) {
  // 使用 Cloud Vision API 或类似服务
  return true;
}

async function performBatchJob() {
  // 批处理逻辑
  return true;
}

3. Terraform 云函数配置

# cloud-functions.tf
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

variable "project_id" {
  description = "GCP 项目 ID"
}

variable "region" {
  default = "us-central1"
}

# 函数的服务账户
resource "google_service_account" "function_sa" {
  account_id   = "cloud-function-sa"
  display_name = "Cloud Function Service Account"
}

# 授予 invoker 角色
resource "google_project_iam_member" "function_invoker" {
  project = var.project_id
  role    = "roles/cloudfunctions.invoker"
  member  = "serviceAccount:${google_service_account.function_sa.email}"
}

# 授予 Cloud Logging 角色
resource "google_project_iam_member" "function_logs" {
  project = var.project_id
  role    = "roles/logging.logWriter"
  member  = "serviceAccount:${google_service_account.function_sa.email}"
}

# 源存档存储桶
resource "google_storage_bucket" "function_source" {
  name     = "${var.project_id}-function-source"
  location = var.region
}

# 上传函数代码
resource "google_storage_bucket_object" "function_zip" {
  name   = "function-${data.archive_file.function.output_md5}.zip"
  bucket = google_storage_bucket.function_source.name
  source = data.archive_file.function.output_path
}

# 归档函数代码
data "archive_file" "function" {
  type        = "zip"
  source_dir  = "${path.module}/src"
  output_path = "${path.module}/function.zip"
}

# HTTP 云函数
resource "google_cloudfunctions2_function" "http_function" {
  name        = "my-http-function"
  location    = var.region
  description = "HTTP 触发器函数"

  build_config {
    runtime           = "nodejs18"
    entry_point       = "httpHandler"
    source {
      storage_source {
        bucket = google_storage_bucket.function_source.name
        object = google_storage_bucket_object.function_zip.name
      }
    }
  }

  service_config {
    max_instance_count = 100
    available_memory_mb = 256
    timeout_seconds = 60
    service_account_email = google_service_account.function_sa.email

    environment_variables = {
      NODE_ENV = "production"
      API_KEY  = "your-api-key"
    }
  }

  labels = {
    env = "production"
  }
}

# 允许公共 HTTP 访问
resource "google_cloudfunctions2_function_iam_member" "http_public" {
  cloud_function = google_cloudfunctions2_function.http_function.name
  role           = "roles/cloudfunctions.invoker"
  member         = "allUsers"
}

# Pub/Sub 主题
resource "google_pubsub_topic" "messages" {
  name = "message-topic"
}

# Pub/Sub 云函数
resource "google_cloudfunctions2_function" "pubsub_function" {
  name        = "my-pubsub-function"
  location    = var.region
  description = "Pub/Sub 触发器函数"

  build_config {
    runtime           = "nodejs18"
    entry_point       = "pubsubHandler"
    source {
      storage_source {
        bucket = google_storage_bucket.function_source.name
        object = google_storage_bucket_object.function_zip.name
      }
    }
  }

  service_config {
    max_instance_count = 100
    available_memory_mb = 256
    timeout_seconds = 300
    service_account_email = google_service_account.function_sa.email
  }

  event_trigger {
    trigger_region = var.region
    event_type     = "google.cloud.pubsub.topic.publish"
    pubsub_topic   = google_pubsub_topic.messages.id
  }
}

# Cloud Storage 存储桶
resource "google_storage_bucket" "uploads" {
  name     = "${var.project_id}-uploads"
  location = var.region
}

# Cloud Storage 触发器函数
resource "google_cloudfunctions2_function" "storage_function" {
  name        = "my-storage-function"
  location    = var.region
  description = "Cloud Storage 触发器函数"

  build_config {
    runtime           = "nodejs18"
    entry_point       = "storageHandler"
    source {
      storage_source {
        bucket = google_storage_bucket.function_source.name
        object = google_storage_bucket_object.function_zip.name
      }
    }
  }

  service_config {
    max_instance_count = 50
    available_memory_mb = 256
    timeout_seconds = 60
    service_account_email = google_service_account.function_sa.email
  }

  event_trigger {
    trigger_region = var.region
    event_type     = "google.storage.object.finalize"
    resource       = google_storage_bucket.uploads.name
  }
}

# Cloud Scheduler 作业 (CRON)
resource "google_cloud_scheduler_job" "batch_job" {
  name             = "batch-job-scheduler"
  description      = "Scheduled batch job"
  schedule         = "0 2 * * *" # 每天凌晨 2 点
  time_zone        = "UTC"
  attempt_deadline = "320s"
  region           = var.region

  retry_config {
    retry_count = 1
  }

  http_target {
    uri        = google_cloudfunctions2_function.http_function.service_config[0].uri
    http_method = "POST"

    headers = {
      "Content-Type" = "application/json"
    }

    body = base64encode(jsonencode({
      job_type = "batch"
    }))

    oidc_token {
      service_account_email = google_service_account.function_sa.email
    }
  }
}

# Cloud Logging sink
resource "google_logging_project_sink" "function_logs" {
  name        = "cloud-function-logs"
  destination = "logging.googleapis.com/projects/${var.project_id}/logs/my-http-function"

  filter = "resource.type=\"cloud_function\" AND resource.labels.function_name=\"my-http-function\""
}

# 监控警报
resource "google_monitoring_alert_policy" "function_errors" {
  display_name = "Cloud Function Error Rate"
  combiner     = "OR"

  conditions {
    display_name = "Error rate threshold"

    condition_threshold {
      filter          = "metric.type=\"cloudfunctions.googleapis.com/function/error_count\" AND resource.type=\"cloud_function\""
      duration        = "60s"
      comparison      = "COMPARISON_GT"
      threshold_value = 10
      aggregations {
        alignment_period    = "60s"
        per_series_aligner  = "ALIGN_RATE"
      }
    }
  }
}

output "http_function_url" {
  value = google_cloudfunctions2_function.http_function.service_config[0].uri
}

最佳实践

✅ 执行

  • 使用具有最小权限的服务账户
  • 在 Secret Manager 中存储机密
  • 实施适当的错误处理
  • 使用环境变量进行配置
  • 使用 Cloud Logging 和 Cloud Monitoring 进行监控
  • 设置适当的内存和超时
  • 使用事件过滤器减少调用次数
  • 实施幂等函数

❌ 不要

  • 在代码中存储机密
  • 使用默认服务账户
  • 创建长时间运行的函数
  • 忽略错误处理
  • 未经测试就部署
  • 对敏感函数使用未经认证的访问

监控

  • Cloud Logging 用于应用日志
  • Cloud Monitoring 用于指标
  • Error Reporting 用于错误跟踪
  • Cloud Trace 用于分布式跟踪
  • Cloud Profiler 用于性能分析

资源