跳到正文
FunCoding

搜索

搜索文档、智能体、博客、Skill 和 MCP

Claude apps gateway:在 Google Cloud 上部署

在 Google Cloud 上部署 Claude apps gateway 的完整示例:Cloud Run 或 GKE、Cloud SQL for PostgreSQL、Secret Manager、服务账号认证 Agent Platform,含 API 启用、服务账号、镜像、数据库、gateway.yaml、密钥、部署、Terraform 参考与排障。

本页逐步演示在 Google Cloud 上运行 Claude apps gateway 的一种方式。这套配置是客户自管基础设施的工作示例,不是受支持的生产部署:先用它了解各部分如何组合,再按你自己的环境调整(与平台无关的要求见部署指南)。

示例以 Google Cloud 的 Agent Platform 作为模型上游,计算用 Cloud Run 或 GKE。Google Workspace 是示例身份提供商(IdP),但任何兼容 OpenID Connect(OIDC)的 IdP 都可以,只有 oidc 块会变(每个 IdP 的细节见 IdP 设置)。

你要构建什么

部署由这些组成:

  • 运行网关容器的 Cloud Run 服务或 GKE Deployment
  • 存放网关镜像的 Artifact Registry 仓库
  • 网关存储用的 Cloud SQL for PostgreSQL 实例,只有私有 IP
  • 存放 gateway.yaml、JWT 签名密钥、OIDC 客户端密钥和 Postgres URL 的 Secret Manager 密钥
  • 带 roles/aiplatform.user 的服务账号,在 Cloud Run 上直接附加,或在 GKE 上通过 Workload Identity 绑定
  • 你自己提供的 HTTPS 前端:Cloud Run 前面的内部 Application Load Balancer(本演练为它配置网关但不创建它),或 GKE 上类别为 gce-internal 的内部 GKE Ingress

前提

  • 启用了计费、并有权创建上述资源的 GCP 项目
  • 用 gcloud auth login 认证的 gcloud CLI,以及本地安装的 Docker
  • GKE 轨道:kubectl,以及位于下面演练所创建 VPC 上的 GKE 集群
  • 在发布所需模型的区域里对 Model Garden 里你需要的 Claude 模型的访问权限
  • 重定向 URI 为 https://<gateway-host>/oauth/callback 的 Google Workspace OAuth 2.0 web 应用客户端(见 IdP 设置)
  • 网关的 TLS 主机名,通常是指向负载均衡器的内部 DNS 名

先设置一次项目和区域:

export PROJECT_ID=<your-project>
export REGION=us-east5   # Model Garden 里发布你所需 Claude 模型的区域
gcloud config set project "$PROJECT_ID"

部署网关

下面的步骤用 gcloud 命令创建完整部署。

第 1 步:启用 API

启用演练用到的服务 API:

gcloud services enable \
  aiplatform.googleapis.com \
  artifactregistry.googleapis.com \
  sqladmin.googleapis.com \
  secretmanager.googleapis.com \
  iamcredentials.googleapis.com \
  iam.googleapis.com \
  compute.googleapis.com \
  servicenetworking.googleapis.com \
  run.googleapis.com \
  container.googleapis.com

需要哪些 API 取决于部署路径:compute 和 servicenetworking 用于私有 IP 的 Cloud SQL 路径;run 只用于 Cloud Run;container 只用于 GKE。

第 2 步:创建服务账号并授予 IAM

网关以一个专用服务账号运行,它有调用 Google Cloud Agent Platform 的权限;它用密码用户经 VPC 访问 Cloud SQL,所以不需要 Cloud SQL 的 IAM 角色:

gcloud iam service-accounts create claude-gateway --display-name="Claude apps gateway"
SA="claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member="serviceAccount:${SA}" --role="roles/aiplatform.user" --condition=None

然后在 Model Garden 里为项目启用 Claude 模型;模型发布在特定区域,所以要查看每个模型卡。

第 3 步:构建镜像并推送到 Artifact Registry

按容器镜像要求构建镜像,使用 linux-x64 glibc 二进制,并推送:

gcloud artifacts repositories create claude-gateway \
  --repository-format=docker --location="$REGION"
gcloud auth configure-docker "${REGION}-docker.pkg.dev" --quiet

# Cloud Run 要求 linux/amd64。--provenance=false 避免产生
# Cloud Run 拒绝的 buildx OCI 镜像索引。
docker build --platform=linux/amd64 --provenance=false \
  -t "${REGION}-docker.pkg.dev/${PROJECT_ID}/claude-gateway/gateway:<version>" .
docker push "${REGION}-docker.pkg.dev/${PROJECT_ID}/claude-gateway/gateway:<version>"

第 4 步:创建 Cloud SQL for PostgreSQL

通过 Private Services Access 在 VPC 上创建实例,使它没有公网 IP;这同样满足强制执行 constraints/sql.restrictPublicIp 的项目:

VPC=cc-gateway-vpc
gcloud compute networks create "$VPC" --subnet-mode=custom
gcloud compute networks subnets create cc-gateway-subnet \
  --network="$VPC" --region="$REGION" --range=10.0.0.0/24

# Private Services Access:每个 VPC 一次性设置
gcloud compute addresses create "google-managed-services-${VPC}" \
  --global --purpose=VPC_PEERING --prefix-length=16 --network="$VPC"
gcloud services vpc-peerings connect \
  --service=servicenetworking.googleapis.com \
  --ranges="google-managed-services-${VPC}" --network="$VPC"

gcloud sql instances create claude-gateway-db \
  --database-version=POSTGRES_16 --tier=db-g1-small --region="$REGION" \
  --network="projects/${PROJECT_ID}/global/networks/${VPC}" --no-assign-ip
gcloud sql databases create claude_gateway --instance=claude-gateway-db
PGPASS="$(openssl rand -hex 24)"
gcloud sql users create gateway --instance=claude-gateway-db --password="$PGPASS"

PRIVATE_IP="$(gcloud sql instances describe claude-gateway-db \
  --format='value(ipAddresses[0].ipAddress)')"
GATEWAY_POSTGRES_URL="postgres://gateway:${PGPASS}@${PRIVATE_IP}:5432/claude_gateway?sslmode=require"

Cloud Run 或 GKE 运行时必须在这个 VPC 上,或被路由进这个 VPC。

第 5 步:编写 gateway.yaml

upstreams 块以 auth: {} 指向 Google Cloud Agent Platform,所以网关经 Application Default Credentials 从运行时服务账号认证(每个字段见配置参考)。两个 listen 字段描述网关前面是什么:public_url 是外部的 https:// 源,任何非环回绑定都必须设置,网关只用这个值构造 IdP 的 redirect_uri 和它的发现文档,从不用 X-Forwarded-* 头;trusted_proxies 是前端的源范围,网关只在 TCP 对端在该列表里时才采信 X-Forwarded-For,并沿链越过受信任的跳数,使每 IP 登录速率限制和审计事件记录开发者 IP 而不是负载均衡器的。要把 trusted_proxies 设成与你的前端匹配。类别为 gce 的外部 GKE Ingress 不在列表里:它会创建公网转发规则地址,而 /login 的私有网络检查会拒绝它。

前端trusted_proxies
直接访问 Cloud Run,没有负载均衡器[169.254.0.0/16]
Cloud Run 前面的内部 Application Load Balancer169.254.0.0/16 加上你的 proxy-only 子网的 CIDR
GKE 内部 Ingress,类别 gce-internal你的 proxy-only 子网的 CIDR

下面的例子使用 Cloud Run 前面的内部负载均衡器的值:

listen:
  host: 0.0.0.0
  port: 8080
  public_url: https://claude-gateway.internal.example.com
  trusted_proxies: [169.254.0.0/16, <your-proxy-only-subnet-cidr>]

oidc:
  issuer: https://accounts.google.com
  client_id: <your-oauth-client-id>
  client_secret: ${OIDC_CLIENT_SECRET}           # GKE:${file:/secrets/oidc-client-secret}
  allowed_email_domains: [example.com]
  # Google 忽略 offline_access;下面这些产生刷新令牌:
  scopes: [openid, profile, email]
  extra_auth_params: { access_type: offline, prompt: consent }

session:
  jwt_secret: ${GATEWAY_JWT_SECRET}              # GKE:${file:/secrets/jwt-secret}

store:
  postgres_url: ${GATEWAY_POSTGRES_URL}          # GKE:${file:/secrets/postgres-url}
  # readiness_grace_seconds: 300                 # 在 Cloud SQL 故障转移期间
                                                 # 继续通过就绪探针

upstreams:
  - provider: vertex
    region: <your-region>                        # 必须与 $REGION 一致
    project_id: <your-project>
    auth: {}                                     # 经运行时服务账号的 ADC

注意:Google 的 id_token 不带 groups 声明。要在 managed.policies 里用基于组的策略并以 Google Workspace 作为 IdP,要配置 oidc.google_groups:它用带域范围委派的服务账号,通过 Admin SDK Directory API 查找每个用户的组;没有它时,改按 email_domain 匹配。

第 6 步:把密钥存进 Secret Manager

创建四个密钥,并把 roles/secretmanager.secretAccessor 授予 claude-gateway 服务账号:

密钥来源
gateway-jwt-secretopenssl rand -base64 32
gateway-oidc-client-secretGoogle Cloud Console → OAuth 客户端
gateway-postgres-urlCloud SQL 步骤里的 $GATEWAY_POSTGRES_URL
gateway-config上一步的完整 gateway.yaml

密钥如何到达容器取决于轨道:在 GKE 上,它们通过 Secret Manager CSI driver 挂载为文件,gateway.yaml 引用 ${file:/secrets/...};在 Cloud Run 上(它无法把多个密钥挂载到同一个目录),gateway.yaml 挂载为文件,另外三个注入为环境变量,所以 gateway.yaml 改为引用 ${GATEWAY_JWT_SECRET}、${OIDC_CLIENT_SECRET} 和 ${GATEWAY_POSTGRES_URL}。

第 7 步:部署

Cloud Run 轨道。 下面的命令在内部负载均衡器后面为生产部署:

gcloud run deploy claude-gateway \
  --image="${REGION}-docker.pkg.dev/${PROJECT_ID}/claude-gateway/gateway:<version>" \
  --region="$REGION" \
  --service-account="claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com" \
  --min-instances=1 \
  --max-instances=8 \
  --timeout=3600 \
  --ingress=internal \
  --network="$VPC" --subnet=cc-gateway-subnet --vpc-egress=private-ranges-only \
  --set-secrets=/etc/claude/gateway.yaml=gateway-config:latest,GATEWAY_JWT_SECRET=gateway-jwt-secret:latest,OIDC_CLIENT_SECRET=gateway-oidc-client-secret:latest,GATEWAY_POSTGRES_URL=gateway-postgres-url:latest \
  --no-invoker-iam-check

经 --network、--subnet 和 --vpc-egress=private-ranges-only 的直接 VPC 出口让服务直接到达 Cloud SQL 私有 IP。每个实例最多持有 store.max_connections 个 Postgres 连接(默认五个),所以要让最大实例数乘以 store.max_connections 低于你的 Cloud SQL 层级的连接限制(参考资产为此把 db-g1-small 层级的实例数上限设为 8)。到 Google Cloud Agent Platform 端点和 accounts.google.com 的公网出口直接走互联网而不经 VPC,所以不需要 Cloud NAT。

调用方 IAM 检查必须开放或禁用:网关运行自己的 OIDC,它的客户端不带 GCP 令牌,所以 Cloud Run 的调用方检查必须放行未认证的请求;请求到达容器后由网关的 OIDC 登录来认证,allowed_email_domains 限制哪些域名可以登录。有两个标志可放行未认证请求:--no-invoker-iam-check 禁用该检查,没有 allUsers 绑定需要管理,并且在 Domain Restricted Sharing 下也能用;--allow-unauthenticated 把 run.invoker 角色授予 allUsers,在你的组织不允许 --no-invoker-iam-check 时使用。经 --ingress 的入口限制是与调用方检查独立的另一层,保持设置它以把服务限制在你的企业网络里。

默认情况下 Cloud Run 的 *.run.app URL 解析到公网地址,而 /login 的私有网络检查会拒绝它。有两种拓扑能给开发者一个可私有解析的主机名,Cloud Run 都不会替你创建:内部 Application Load Balancer(本页 gateway.yaml 假定的拓扑)——在服务前面创建带内部 DNS 名和证书的内部 Application Load Balancer,并把 listen.public_url 设为该主机名;internal 入口设置已经放行来自内部 Application Load Balancer 的流量,internal-and-cloud-load-balancing 还会放行外部 Application Load Balancer(其公网地址会被 /login 私有网络检查拒绝),所以本页没有任何拓扑需要它;仅内部入口、没有负载均衡器——保持部署命令不变,把 listen.public_url 留作 *.run.app URL(下面参考资产里的默认值);要让 *.run.app 私有解析,你的网络团队必须已经运营着 Google API 的 Private Service Connect 端点、把 *.run.app 解析到它的 Cloud DNS 私有区域,以及到该端点的本地路由。Google 的 Cloud Run 私有网络指南涵盖两种选择都需要的基础设施;在网关用私有主机名提供服务后验证登录,在那之前,从 Cloud Run 里的日志确认容器已启动。第一次登录之前,把 OAuth 客户端的授权重定向 URI 更新为 <public_url>/oauth/callback;更改 public_url 之后要重新部署,因为网关只用该设置构造公开源,忽略 X-Forwarded-Host 和 X-Forwarded-Proto;只有设了 listen.trusted_proxies 时才采信 X-Forwarded-For 作为客户端 IP。

GKE 轨道。 集群必须在 Cloud SQL 步骤创建的 $VPC 上,pod 才能到达数据库的私有 IP:单靠 VPC 对等不行,因为 Cloud SQL 私有 IP 本身就是一个对等网络,而对等是非传递的。要在该 VPC 上创建新集群,给 gcloud container clusters create 传 --network="$VPC" --subnetwork=cc-gateway-subnet。在集群及其节点池上启用 Workload Identity,然后把 Google 服务账号绑定到 Kubernetes 服务账号,使 pod 继承它的凭据:

gcloud container clusters update <cluster> --region="$REGION" \
  --workload-pool="${PROJECT_ID}.svc.id.goog"
# 在 Standard 集群上,现有节点池也需要 GKE_METADATA;
# Autopilot 默认启用它。
gcloud container node-pools update <pool> --cluster=<cluster> \
  --region="$REGION" --workload-metadata=GKE_METADATA

kubectl create namespace claude-gateway
kubectl create serviceaccount gateway -n claude-gateway
gcloud iam service-accounts add-iam-policy-binding \
  "claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role roles/iam.workloadIdentityUser \
  --member "serviceAccount:${PROJECT_ID}.svc.id.goog[claude-gateway/gateway]"
kubectl annotate serviceaccount gateway -n claude-gateway \
  iam.gke.io/gcp-service-account="claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com"

按「Kubernetes 部署」把网关部署为标准的 Deployment 加 Service 和类别为 gce-internal 的内部 Ingress,带有:serviceAccountName: gateway;Secret Manager CSI driver 把密钥挂载在 /secrets;就绪探针指向 GET /readyz。给网关 Service 附加带调高 timeoutSec 的 BackendConfig:GKE Ingress 背后的负载均衡器后端服务默认超时 30 秒,会切断长时间的流式响应。不要在 Workload Identity 集群上应用阻止 169.254.169.254 的出口 NetworkPolicy:pod 必须能到达元数据服务器获取凭据,那里的防御靠网关内置的 SSRF 防护。网关会在启动时记录一条警告,说元数据端点可达并建议应用出口 NetworkPolicy;在 Workload Identity 下这条警告是预期的,因为 pod 需要该端点。

第 8 步:把网关 URL 推送到开发者机器

网关现在运行了,但在网关 URL 到达开发者机器之前,他们无法从 /login 到达它。把完整的托管设置片段(带 forceLoginMethod、forceLoginGatewayUrl 和选择加入的 parentSettingsBehavior: "merge")经 MDM 部署到每台设备;登录选择器里没有供开发者手动选择的网关选项。

Terraform 参考

参考部署资产把本页的 Cloud Run 轨道自动化;配置和镜像资产适用于两条轨道:

  • setup.sh:幂等的 gcloud 供应器,走完整的 Cloud Run 路径,从启用 API 一直到首次部署
  • terraform/:同样的部署写成基础设施即代码,用于全新部署:先对 Artifact Registry 仓库做有目标的 apply,再构建并推送镜像,然后做完整 apply
  • gateway.yaml.example 和用于 distroless 运行时镜像的 Dockerfile

这些资产默认把 Cloud Run 入口设为 internal,与本页的部署命令一致;该设置在服务前面有或没有内部 Application Load Balancer 时都能工作,资产同样不创建负载均衡器。资产还默认把调用方层设为 allUsers 的 run.invoker 授予,而不是 --no-invoker-iam-check,与本页演练相反;两者都行,选择取决于你组织的策略约束。这些资产作为工作示例提供,不是受支持的生产制品:要按你的环境审查并调整。

排障

网关启动和登录错误见与平台无关的排障表;下面的条目是 Google Cloud 特有的。

症状原因修复
Cloud Run 在到达容器之前返回 403 Forbidden调用方 IAM 检查仍然启用用 --no-invoker-iam-check 部署,或用 --allow-unauthenticated 把 run.invoker 角色授予 allUsers
--no-invoker-iam-check 被拒绝,提示 invoker_iam_disabled is not currently available被 constraints/run.managed.requireInvokerIam 阻止用 --allow-unauthenticated;如果经 constraints/iam.allowedPolicyMemberDomains 的 Domain Restricted Sharing 也阻止了它,就用 GKE 轨道,它在网络层暴露网关而没有 allUsers 绑定
部署时出现 Container manifest type … must support amd64/linux镜像是在非 amd64 主机上构建的,或 buildx 产生了 OCI 镜像索引用 --platform=linux/amd64 --provenance=false 构建
在 Cloud Run 上网关启动因 Postgres 连接超时错误退出服务没有接入 VPC,或 Cloud SQL 在该 VPC 上没有私有 IP用 --network 和 --subnet 部署以启用直接 VPC 出口,并用 --no-assign-ip 和指向同一个 VPC 的 --network 创建 Cloud SQL 实例
Google Cloud Agent Platform 请求返回 403 PERMISSION_DENIED运行时没有使用 claude-gateway 服务账号,或项目没有在 Model Garden 里启用该模型在 Cloud Run 上设 --service-account,或在 GKE 上绑定 Workload Identity,并在目标区域的 Model Garden 里启用每个 Claude 模型
流式响应在固定时长后被切断前端请求超时:GKE Ingress 背后的负载均衡器后端服务默认 30 秒,Cloud Run 默认 300 秒在 GKE 上附加带调高 timeoutSec 的 BackendConfig,或在 Cloud Run 上用 --timeout=3600 部署

下一步

  • 配置参考:每个 gateway.yaml 选项,包括 managed.policies 和 telemetry
  • 部署与运维:IdP 设置、健康检查、JWT 密钥轮换、升级和安全模型
  • Claude apps gateway 概览:快速开始和连接开发者