GCPCloudRun gcp-cloud-run

Google Cloud Run是一个无服务器平台,允许开发者部署容器化应用,自动管理扩展和流量,适用于多种应用场景,如微服务、Web应用、数据处理等。

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

name: gcp-cloud-run description: 在Google Cloud Run上部署容器化应用程序,实现自动扩展、流量管理和服务网格集成。适用于基于容器的无服务器计算。

GCP Cloud Run

概览

Google Cloud Run允许在不管理基础设施的情况下大规模部署容器化应用程序。运行无状态HTTP容器,自动扩展从零到数千个实例,仅支付消耗的计算时间。

何时使用

  • 微服务和API
  • Web应用程序和后端
  • 批处理作业
  • 长运行后台工作
  • CI/CD流水线集成
  • 数据处理流水线
  • WebSocket应用程序
  • 多语言服务

实施示例

1. 使用gcloud CLI进行Cloud Run部署

# 构建容器镜像
gcloud builds submit --tag gcr.io/MY_PROJECT_ID/my-app:latest

# 部署到Cloud Run
gcloud run deploy my-app \
  --image gcr.io/MY_PROJECT_ID/my-app:latest \
  --platform managed \
  --region us-central1 \
  --memory 512Mi \
  --cpu 1 \
  --timeout 3600 \
  --max-instances 100 \
  --min-instances 1 \
  --no-allow-unauthenticated \
  --set-env-vars NODE_ENV=production,DATABASE_URL=postgresql://...

# 允许公开访问
gcloud run services add-iam-policy-binding my-app \
  --platform managed \
  --region us-central1 \
  --member=allUsers \
  --role=roles/run.invoker

# 获取服务URL
gcloud run services describe my-app \
  --platform managed \
  --region us-central1 \
  --format 'value(status.url)'

# 查看日志
gcloud run services logs read my-app --limit 50

# 使用新镜像更新服务
gcloud run deploy my-app \
  --image gcr.io/MY_PROJECT_ID/my-app:v2 \
  --platform managed \
  --region us-central1 \
  --update-env-vars VERSION=2

2. 容器化应用程序(Node.js)

# Dockerfile
FROM node:18-alpine

WORKDIR /app

# 复制包文件
COPY package*.json ./

# 安装依赖
RUN npm ci --only=production

# 复制应用程序代码
COPY . .

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node healthcheck.js

# 暴露端口(Cloud Run默认使用8080)
EXPOSE 8080

# 运行应用程序
CMD ["node", "server.js"]
// server.js
const express = require('express');
const app = express();

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

app.use(express.json());

// 健康检查端点
app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

// 存活探针
app.get('/live', (req, res) => {
  res.status(200).send('alive');
});

// 就绪探针
app.get('/ready', (req, res) => {
  res.status(200).send('ready');
});

// API端点
app.get('/api/data', async (req, res) => {
  try {
    const data = await fetchData();
    res.json(data);
  } catch (error) {
    console.error('Error fetching data:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// 优雅关闭
let isShuttingDown = false;

process.on('SIGTERM', () => {
  console.log('SIGTERM信号接收:关闭HTTP服务器');
  isShuttingDown = true;

  server.close(() => {
    console.log('HTTP服务器已关闭');
    process.exit(0);
  });

  // 强制关闭后30秒
  setTimeout(() => {
    console.error('由于超时强制关闭');
    process.exit(1);
  }, 30000);
});

const server = app.listen(PORT, () => {
  console.log(`服务器正在监听端口${PORT}`);
});

async function fetchData() {
  return { items: [] };
}

3. Terraform Cloud Run配置

# cloud-run.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"
}

variable "image" {
  description = "容器镜像URI"
}

# Cloud Run的服务账户
resource "google_service_account" "cloud_run_sa" {
  account_id   = "cloud-run-sa"
  display_name = "Cloud Run服务账户"
}

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

# Cloud SQL客户端角色(如果使用Cloud SQL)
resource "google_project_iam_member" "cloud_sql_client" {
  project = var.project_id
  role    = "roles/cloudsql.client"
  member  = "serviceAccount:${google_service_account.cloud_run_sa.email}"
}

# Cloud Run服务
resource "google_cloud_run_service" "app" {
  name     = "my-app"
  location = var.region

  template {
    spec {
      service_account_name = google_service_account.cloud_run_sa.email

      containers {
        image = var.image

        resources {
          limits = {
            cpu    = "1"
            memory = "512Mi"
          }
        }

        env {
          name  = "NODE_ENV"
          value = "production"
        }

        env {
          name  = "PORT"
          value = "8080"
        }

        ports {
          container_port = 8080
        }

        # 启动探针
        startup_probe {
          http_get {
            path = "/ready"
            port = 8080
          }
          failure_threshold = 3
          period_seconds    = 10
        }

        # 存活探针
        liveness_probe {
          http_get {
            path = "/live"
            port = 8080
          }
          failure_threshold     = 3
          period_seconds        = 10
          initial_delay_seconds = 10
        }
      }

      timeout_seconds       = 3600
      service_account_name  = google_service_account.cloud_run_sa.email
    }

    metadata {
      annotations = {
        "autoscaling.knative.dev/maxScale" = "100"
        "autoscaling.knative.dev/minScale" = "1"
      }
    }
  }

  traffic {
    percent         = 100
    latest_revision = true
  }

  depends_on = [google_project_iam_member.cloud_run_logs]
}

# 允许公开访问
resource "google_cloud_run_service_iam_binding" "public" {
  service  = google_cloud_run_service.app.name
  location = google_cloud_run_service.app.location
  role     = "roles/run.invoker"
  members = [
    "allUsers"
  ]
}

# Cloud Load Balancer用于全球访问
resource "google_compute_backend_service" "app" {
  name            = "my-app-backend"
  protocol        = "HTTPS"
  security_policy = google_compute_security_policy.app.id

  backend {
    group = google_compute_network_endpoint_group.app.id
  }

  health_checks = [google_compute_health_check.app.id]

  log_config {
    enable      = true
    sample_rate = 1.0
  }
}

# 网络端点组用于Cloud Run
resource "google_compute_network_endpoint_group" "app" {
  name                  = "my-app-neg"
  network_endpoint_type = "SERVERLESS"
  cloud_run_config {
    service = google_cloud_run_service.app.name
  }
  location = var.region
}

# 健康检查
resource "google_compute_health_check" "app" {
  name = "my-app-health-check"

  https_health_check {
    port         = "8080"
    request_path = "/health"
  }
}

# Cloud Armor安全策略
resource "google_compute_security_policy" "app" {
  name = "my-app-policy"

  rules {
    action   = "deny(403)"
    priority = "100"
    match {
      versioned_expr = "CEL_V1"
      expression     = "origin.country_code in ['CN', 'RU']"
    }
  }

  rules {
    action   = "rate_based_ban"
    priority = "200"
    match {
      versioned_expr = "CEL_V1"
      expression     = "true"
    }
    rate_limit_options {
      conform_action = "allow"
      exceed_action  = "deny(429)"
      enforce_on_key = "IP"
      ban_duration_sec = 600
      rate_limit_threshold {
        count        = 100
        interval_sec = 60
      }
      ban_threshold_rule {
        count        = 1000
        interval_sec = 60
      }
    }
  }

  rules {
    action   = "allow"
    priority = "65535"
    match {
      versioned_expr = "CEL_V1"
      expression     = "true"
    }
  }
}

# 全球地址
resource "google_compute_global_address" "app" {
  name = "my-app-address"
}

# HTTPS重定向
resource "google_compute_url_map" "https_redirect" {
  name = "my-app-https-redirect"

  default_url_redirect {
    https_redirect         = true
    redirect_response_code = "301"
    strip_query            = false
  }
}

# HTTPS目标代理
resource "google_compute_target_https_proxy" "app" {
  name            = "my-app-proxy"
  url_map         = google_compute_url_map.app.id
  ssl_certificates = [google_compute_managed_ssl_certificate.app.id]
}

# 管理SSL证书
resource "google_compute_managed_ssl_certificate" "app" {
  name = "my-app-cert"

  managed {
    domains = ["example.com"]
  }
}

# URL映射
resource "google_compute_url_map" "app" {
  name            = "my-app-url-map"
  default_service = google_compute_backend_service.app.id
}

# 转发规则
resource "google_compute_global_forwarding_rule" "app" {
  name                  = "my-app-forwarding-rule"
  ip_protocol           = "TCP"
  load_balancing_scheme = "EXTERNAL"
  port_range            = "443"
  target                = google_compute_target_https_proxy.app.id
  address               = google_compute_global_address.app.address
}

# 监控警报
resource "google_monitoring_alert_policy" "cloud_run_errors" {
  display_name = "Cloud Run高错误率"
  combiner     = "OR"

  conditions {
    display_name = "错误率阈值"

    condition_threshold {
      filter          = "metric.type=\"run.googleapis.com/request_count\" AND resource.label.service_name=\"my-app\" AND metric.label.response_code_class=\"5xx\""
      duration        = "60s"
      comparison      = "COMPARISON_GT"
      threshold_value = 10
      aggregations {
        alignment_period    = "60s"
        per_series_aligner  = "ALIGN_RATE"
      }
    }
  }

  notification_channels = []
}

# Cloud Run作业批量处理
resource "google_cloud_run_v2_job" "batch" {
  name     = "batch-processor"
  location = var.region

  template {
    containers {
      image = var.image
      env {
        name  = "JOB_TYPE"
        value = "batch"
      }
    }
    timeout       = "3600s"
    service_account = google_service_account.cloud_run_sa.email
  }
}

# Cloud Scheduler触发作业
resource "google_cloud_scheduler_job" "batch_trigger" {
  name             = "batch-processor-trigger"
  schedule         = "0 2 * * *"
  time_zone        = "UTC"
  attempt_deadline = "320s"
  region           = var.region

  http_target {
    http_method = "POST"
    uri         = "https://${var.region}-run.googleapis.com/apis/run.googleapis.com/v1/projects/${var.project_id}/locations/${var.region}/jobs/batch-processor:run"

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

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

output "cloud_run_url" {
  value = google_cloud_run_service.app.status[0].url
}

output "load_balancer_ip" {
  value = google_compute_global_address.app.address
}

4. Docker构建和推送

# 本地构建镜像
docker build -t my-app:latest .

# 标记为容器注册表
docker tag my-app:latest gcr.io/MY_PROJECT_ID/my-app:latest

# 推送到容器注册表
docker push gcr.io/MY_PROJECT_ID/my-app:latest

# 或使用Cloud Build
gcloud builds submit \
  --tag gcr.io/MY_PROJECT_ID/my-app:latest \
  --source-dir . \
  --no-cache

最佳实践

✅ DO

  • 使用容器健康检查
  • 设置适当的CPU和内存
  • 实施优雅关闭
  • 使用最小权限的服务账户
  • 使用Cloud Logging进行监控
  • 启用Cloud Armor进行保护
  • 使用版本管理进行蓝绿部署
  • 实施启动和存活探针

❌ DON’T

  • 在代码中存储秘密
  • 使用默认服务账户
  • 创建有状态应用程序
  • 忽略健康检查
  • 未经测试即部署
  • 使用过多的资源限制
  • 在容器文件系统中存储文件

监控

  • Cloud Logging用于应用程序日志
  • Cloud Monitoring用于指标
  • Error Reporting用于错误跟踪
  • Cloud Trace用于分布式跟踪
  • 版本指标和分析

资源