6 6
7> 在 Google Cloud 上執行 Claude 應用程式閘道的實際範例:Cloud Run 或 GKE、Cloud SQL for PostgreSQL、Secret Manager,以及對 Google Cloud 的 Agent Platform 的服務帳戶驗證。7> 在 Google Cloud 上執行 Claude 應用程式閘道的實際範例:Cloud Run 或 GKE、Cloud SQL for PostgreSQL、Secret Manager,以及對 Google Cloud 的 Agent Platform 的服務帳戶驗證。
8 8
9<Note>9> [!NOTE]
10 本頁面介紹在 Google Cloud 上執行 Claude 應用程式閘道的一種方式。此配置是客戶管理基礎設施的工作範例,而非受支援的生產部署;使用它來了解各個部分如何組合在一起,然後再根據您自己的環境進行調整。如需平台無關的需求,請參閱[部署指南](/docs/zh-TW/claude-apps-gateway-deploy)。10>
11</Note>11> 本頁面介紹在 Google Cloud 上執行 Claude 應用程式閘道的一種方式。此配置是客戶管理基礎設施的工作範例,而非受支援的生產部署;使用它來了解各個部分如何組合在一起,然後再根據您自己的環境進行調整。如需平台無關的需求,請參閱[部署指南](/docs/zh-TW/claude-apps-gateway-deploy)。
12 12
13此範例在 Google Cloud 上配置 Claude 應用程式閘道,使用 Google Cloud 的 Agent Platform 作為模型上游,並使用 Cloud Run 或 GKE 進行運算。Google Workspace 是範例身分提供者 (IdP),但任何符合 OpenID Connect (OIDC) 的 IdP 都可以使用;只有 `oidc` 區塊會改變。如需各個 IdP 的詳細資訊,請參閱[身分提供者設定](/docs/zh-TW/claude-apps-gateway-deploy#identity-provider-setup)。13此範例在 Google Cloud 上配置 Claude 應用程式閘道,使用 Google Cloud 的 Agent Platform 作為模型上游,並使用 Cloud Run 或 GKE 進行運算。Google Workspace 是範例身分提供者 (IdP),但任何符合 OpenID Connect (OIDC) 的 IdP 都可以使用;只有 `oidc` 區塊會改變。如需各個 IdP 的詳細資訊,請參閱[身分提供者設定](/docs/zh-TW/claude-apps-gateway-deploy#identity-provider-setup)。
14 14
15<h2 id="what-you’ll-build">15## 您將建立的內容
16 您將建立的內容
17</h2>
18 16
19<Frame>17
20 <img src="https://mintcdn.com/claude-code/-uq-4JE0W_JO5Er5/images/claude-gateway-gcp-architecture.svg?fit=max&auto=format&n=-uq-4JE0W_JO5Er5&q=85&s=cb705151c69128ac0da235852d5600ab" alt="Google Cloud 上 Claude 應用程式閘道的圖表:Claude Code 用戶端透過 HTTPS 連接到閘道(Cloud Run 或 GKE),閘道在 VPC 內執行,旁邊有一個私有 IP Cloud SQL 資料庫用於工作階段狀態。閘道透過 OIDC 針對 Google Workspace 簽署使用者,從 Secret Manager 讀取配置和祕密,將模型請求轉發到 Google Cloud 的 Agent Platform,並在部署時從 Artifact Registry 提取其映像。" width="760" height="400" data-path="images/claude-gateway-gcp-architecture.svg" />
21</Frame>
22 18
23部署包含:19部署包含:
24 20
29* **服務帳戶**,具有 `roles/aiplatform.user`,直接附加到 Cloud Run 或透過 GKE 上的 Workload Identity 繫結25* **服務帳戶**,具有 `roles/aiplatform.user`,直接附加到 Cloud Run 或透過 GKE 上的 Workload Identity 繫結
30* **HTTPS 前端**,由您提供:Cloud Run 前面的內部應用程式負載平衡器(本逐步解說會為其設定閘道,但不會建立),或在 GKE 上使用 `gce-internal` 類別的內部 **GKE Ingress**26* **HTTPS 前端**,由您提供:Cloud Run 前面的內部應用程式負載平衡器(本逐步解說會為其設定閘道,但不會建立),或在 GKE 上使用 `gce-internal` 類別的內部 **GKE Ingress**
31 27
32<h2 id="prerequisites">28## 先決條件
33 先決條件
34</h2>
35 29
36* 啟用計費的 GCP 專案,以及建立上述資源的權限30* 啟用計費的 GCP 專案,以及建立上述資源的權限
37* `gcloud` CLI(使用 `gcloud auth login` 驗證)和本機安裝的 Docker31* `gcloud` CLI(使用 `gcloud auth login` 驗證)和本機安裝的 Docker
48gcloud config set project "$PROJECT_ID"42gcloud config set project "$PROJECT_ID"
49```43```
50 44
51<h2 id="deploy-the-gateway">45## 部署閘道
52 部署閘道
53</h2>
54 46
55以下步驟使用 `gcloud` 命令佈建完整部署。47以下步驟使用 `gcloud` 命令佈建完整部署。
56 48
57<Steps>49**1. 啟用 API**
58 <Step title="啟用 API">
59 啟用本逐步解說使用的服務 API:
60 50
61 ```bash theme={null}51啟用本逐步解說使用的服務 API:
62 gcloud services enable \52
53```bash theme={null}
54gcloud services enable \
63 aiplatform.googleapis.com \55 aiplatform.googleapis.com \
64 artifactregistry.googleapis.com \56 artifactregistry.googleapis.com \
65 sqladmin.googleapis.com \57 sqladmin.googleapis.com \
70 servicenetworking.googleapis.com \62 servicenetworking.googleapis.com \
71 run.googleapis.com \63 run.googleapis.com \
72 container.googleapis.com64 container.googleapis.com
73 ```65```
74 66
75 您需要的 API 取決於部署路徑:67您需要的 API 取決於部署路徑:
76 68
77 * `compute` 和 `servicenetworking`:私有 IP Cloud SQL 路徑所需69* `compute` 和 `servicenetworking`:私有 IP Cloud SQL 路徑所需
78 * `run`:僅限 Cloud Run70* `run`:僅限 Cloud Run
79 * `container`:僅限 GKE71* `container`:僅限 GKE
80 </Step>
81 72
82 <Step title="建立服務帳戶並授予 IAM">73**2. 建立服務帳戶並授予 IAM**
83 閘道以專用服務帳戶身份執行,具有呼叫 Google Cloud 的 Agent Platform 的權限。它透過 VPC 使用密碼使用者連接到 Cloud SQL,因此不需要 Cloud SQL IAM 角色:
84 74
85 ```bash theme={null}75閘道以專用服務帳戶身份執行,具有呼叫 Google Cloud 的 Agent Platform 的權限。它透過 VPC 使用密碼使用者連接到 Cloud SQL,因此不需要 Cloud SQL IAM 角色:
86 gcloud iam service-accounts create claude-gateway --display-name="Claude apps gateway"
87 SA="claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com"
88 76
89 gcloud projects add-iam-policy-binding "$PROJECT_ID" \77```bash theme={null}
78gcloud iam service-accounts create claude-gateway --display-name="Claude apps gateway"
79SA="claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com"
80
81gcloud projects add-iam-policy-binding "$PROJECT_ID" \
90 --member="serviceAccount:${SA}" --role="roles/aiplatform.user" --condition=None82 --member="serviceAccount:${SA}" --role="roles/aiplatform.user" --condition=None
91 ```83```
92 84
93 然後在 Model Garden 中為專案啟用 Claude 模型;模型發佈到特定區域,因此請檢查每個模型卡。85然後在 Model Garden 中為專案啟用 Claude 模型;模型發佈到特定區域,因此請檢查每個模型卡。
94 </Step>
95 86
96 <Step title="建置映像並推送到 Artifact Registry">87**3. 建置映像並推送到 Artifact Registry**
97 根據[容器映像需求](/docs/zh-TW/claude-apps-gateway-deploy#container-image)建置映像,使用 `linux-x64` glibc 二進位檔,並推送它:
98 88
99 ```bash theme={null}89根據[容器映像需求](/docs/zh-TW/claude-apps-gateway-deploy#container-image)建置映像,使用 `linux-x64` glibc 二進位檔,並推送它:
100 gcloud artifacts repositories create claude-gateway \90
91```bash theme={null}
92gcloud artifacts repositories create claude-gateway \
101 --repository-format=docker --location="$REGION"93 --repository-format=docker --location="$REGION"
102 gcloud auth configure-docker "${REGION}-docker.pkg.dev" --quiet94gcloud auth configure-docker "${REGION}-docker.pkg.dev" --quiet
103 95
104 # Cloud Run 需要 linux/amd64。--provenance=false 避免 buildx OCI96# Cloud Run 需要 linux/amd64。--provenance=false 避免 buildx OCI
105 # 映像索引,Cloud Run 會拒絕。97# 映像索引,Cloud Run 會拒絕。
106 docker build --platform=linux/amd64 --provenance=false \98docker build --platform=linux/amd64 --provenance=false \
107 -t "${REGION}-docker.pkg.dev/${PROJECT_ID}/claude-gateway/gateway:<version>" .99 -t "${REGION}-docker.pkg.dev/${PROJECT_ID}/claude-gateway/gateway:<version>" .
108 docker push "${REGION}-docker.pkg.dev/${PROJECT_ID}/claude-gateway/gateway:<version>"100docker push "${REGION}-docker.pkg.dev/${PROJECT_ID}/claude-gateway/gateway:<version>"
109 ```101```
110 </Step>
111 102
112 <Step title="佈建 Cloud SQL for PostgreSQL">103**4. 佈建 Cloud SQL for PostgreSQL**
113 透過 Private Services Access 在 VPC 上建立執行個體,使其沒有公用 IP;這也滿足強制執行 `constraints/sql.restrictPublicIp` 的專案:
114 104
115 ```bash theme={null}105透過 Private Services Access 在 VPC 上建立執行個體,使其沒有公用 IP;這也滿足強制執行 `constraints/sql.restrictPublicIp` 的專案:
116 VPC=cc-gateway-vpc106
117 gcloud compute networks create "$VPC" --subnet-mode=custom107```bash theme={null}
118 gcloud compute networks subnets create cc-gateway-subnet \108VPC=cc-gateway-vpc
109gcloud compute networks create "$VPC" --subnet-mode=custom
110gcloud compute networks subnets create cc-gateway-subnet \
119 --network="$VPC" --region="$REGION" --range=10.0.0.0/24111 --network="$VPC" --region="$REGION" --range=10.0.0.0/24
120 112
121 # Private Services Access:每個 VPC 一次113# Private Services Access:每個 VPC 一次
122 gcloud compute addresses create "google-managed-services-${VPC}" \114gcloud compute addresses create "google-managed-services-${VPC}" \
123 --global --purpose=VPC_PEERING --prefix-length=16 --network="$VPC"115 --global --purpose=VPC_PEERING --prefix-length=16 --network="$VPC"
124 gcloud services vpc-peerings connect \116gcloud services vpc-peerings connect \
125 --service=servicenetworking.googleapis.com \117 --service=servicenetworking.googleapis.com \
126 --ranges="google-managed-services-${VPC}" --network="$VPC"118 --ranges="google-managed-services-${VPC}" --network="$VPC"
127 119
128 gcloud sql instances create claude-gateway-db \120gcloud sql instances create claude-gateway-db \
129 --database-version=POSTGRES_16 --tier=db-g1-small --region="$REGION" \121 --database-version=POSTGRES_16 --tier=db-g1-small --region="$REGION" \
130 --network="projects/${PROJECT_ID}/global/networks/${VPC}" --no-assign-ip122 --network="projects/${PROJECT_ID}/global/networks/${VPC}" --no-assign-ip
131 gcloud sql databases create claude_gateway --instance=claude-gateway-db123gcloud sql databases create claude_gateway --instance=claude-gateway-db
132 PGPASS="$(openssl rand -hex 24)"124PGPASS="$(openssl rand -hex 24)"
133 gcloud sql users create gateway --instance=claude-gateway-db --password="$PGPASS"125gcloud sql users create gateway --instance=claude-gateway-db --password="$PGPASS"
134 126
135 PRIVATE_IP="$(gcloud sql instances describe claude-gateway-db \127PRIVATE_IP="$(gcloud sql instances describe claude-gateway-db \
136 --format='value(ipAddresses[0].ipAddress)')"128 --format='value(ipAddresses[0].ipAddress)')"
137 GATEWAY_POSTGRES_URL="postgres://gateway:${PGPASS}@${PRIVATE_IP}:5432/claude_gateway?sslmode=require"129GATEWAY_POSTGRES_URL="postgres://gateway:${PGPASS}@${PRIVATE_IP}:5432/claude_gateway?sslmode=require"
138 ```130```
139 131
140 Cloud Run 或 GKE 執行階段必須在此 VPC 上或路由到此 VPC。132Cloud Run 或 GKE 執行階段必須在此 VPC 上或路由到此 VPC。
141 </Step>
142 133
143 <Step title="撰寫 gateway.yaml">134**5. 撰寫 gateway.yaml**
144 `upstreams` 區塊使用 `auth: {}` 指向 Google Cloud 的 Agent Platform,因此閘道透過執行階段服務帳戶的應用程式預設認證進行驗證。請參閱[設定參考](/docs/zh-TW/claude-apps-gateway-config)以了解每個欄位。
145 135
146 兩個 `listen` 欄位描述什麼在閘道前面:136`upstreams` 區塊使用 `auth: {}` 指向 Google Cloud 的 Agent Platform,因此閘道透過執行階段服務帳戶的應用程式預設認證進行驗證。請參閱[設定參考](/docs/zh-TW/claude-apps-gateway-config)以了解每個欄位。
147 137
148 * `public_url`:外部 `https://` 來源,任何非迴圈繫結都需要;請參閱 [`listen` 參考](/docs/zh-TW/claude-apps-gateway-config#listen)。閘道僅從此值建置 IdP `redirect_uri` 和其探索文件,絕不從 `X-Forwarded-*` 標頭建置。138兩個 `listen` 欄位描述什麼在閘道前面:
149 * `trusted_proxies`:前端的來源範圍。閘道僅在 TCP 對等在此清單中時才接受 `X-Forwarded-For`,然後走過受信任的躍點鏈,因此每個 IP 登入速率限制和稽核事件會記錄開發人員 IP 而不是負載平衡器的。
150 139
151 設定 `trusted_proxies` 以符合您的前端。`gce` 類別的外部 GKE Ingress 未列出:它佈建公用轉送規則位址,`/login` [私人網路檢查](/docs/zh-TW/claude-apps-gateway#prerequisites)會拒絕。140* `public_url`:外部 `https://` 來源,任何非迴圈繫結都需要;請參閱 [`listen` 參考](/docs/zh-TW/claude-apps-gateway-config#listen)。閘道僅從此值建置 IdP `redirect_uri` 和其探索文件,絕不從 `X-Forwarded-*` 標頭建置。
141* `trusted_proxies`:前端的來源範圍。閘道僅在 TCP 對等在此清單中時才接受 `X-Forwarded-For`,然後走過受信任的躍點鏈,因此每個 IP 登入速率限制和稽核事件會記錄開發人員 IP 而不是負載平衡器的。
152 142
153 | 前端 | `trusted_proxies` |143設定 `trusted_proxies` 以符合您的前端。`gce` 類別的外部 GKE Ingress 未列出:它佈建公用轉送規則位址,`/login` [私人網路檢查](/docs/zh-TW/claude-apps-gateway#prerequisites)會拒絕。
154 | - | - |
155 | 直接到達的 Cloud Run,無負載平衡器 | `[169.254.0.0/16]` |
156 | Cloud Run 前面的內部應用程式負載平衡器 | `169.254.0.0/16` 加上您的僅代理子網路 CIDR |
157 | GKE 內部 Ingress,類別 `gce-internal` | 您的僅代理子網路 CIDR |
158 144
159 下面的範例使用內部負載平衡器在 Cloud Run 前面的值。145| 前端 | `trusted_proxies` |
146| - | - |
147| 直接到達的 Cloud Run,無負載平衡器 | `[169.254.0.0/16]` |
148| Cloud Run 前面的內部應用程式負載平衡器 | `169.254.0.0/16` 加上您的僅代理子網路 CIDR |
149| GKE 內部 Ingress,類別 `gce-internal` | 您的僅代理子網路 CIDR |
160 150
161 ```yaml gateway.yaml theme={null}151下面的範例使用內部負載平衡器在 Cloud Run 前面的值。
162 listen:152
153```yaml gateway.yaml theme={null}
154listen:
163 host: 0.0.0.0155 host: 0.0.0.0
164 port: 8080156 port: 8080
165 public_url: https://claude-gateway.internal.example.com157 public_url: https://claude-gateway.internal.example.com
166 trusted_proxies: [169.254.0.0/16, <your-proxy-only-subnet-cidr>]158 trusted_proxies: [169.254.0.0/16, <your-proxy-only-subnet-cidr>]
167 159
168 oidc:160oidc:
169 issuer: https://accounts.google.com161 issuer: https://accounts.google.com
170 client_id: <your-oauth-client-id>162 client_id: <your-oauth-client-id>
171 client_secret: ${OIDC_CLIENT_SECRET} # GKE: ${file:/secrets/oidc-client-secret}163 client_secret: ${OIDC_CLIENT_SECRET} # GKE: ${file:/secrets/oidc-client-secret}
174 scopes: [openid, profile, email]166 scopes: [openid, profile, email]
175 extra_auth_params: { access_type: offline, prompt: consent }167 extra_auth_params: { access_type: offline, prompt: consent }
176 168
177 session:169session:
178 jwt_secret: ${GATEWAY_JWT_SECRET} # GKE: ${file:/secrets/jwt-secret}170 jwt_secret: ${GATEWAY_JWT_SECRET} # GKE: ${file:/secrets/jwt-secret}
179 171
180 store:172store:
181 postgres_url: ${GATEWAY_POSTGRES_URL} # GKE: ${file:/secrets/postgres-url}173 postgres_url: ${GATEWAY_POSTGRES_URL} # GKE: ${file:/secrets/postgres-url}
182 # readiness_grace_seconds: 300 # 在 Cloud SQL 容錯移轉期間174 # readiness_grace_seconds: 300 # 在 Cloud SQL 容錯移轉期間
183 # 保持通過就緒探針175# 保持通過就緒探針
184 176
185 upstreams:177upstreams:
186 - provider: vertex178 - provider: vertex
187 region: <your-region> # 必須符合 $REGION179 region: <your-region> # 必須符合 $REGION
188 project_id: <your-project>180 project_id: <your-project>
189 auth: {} # 透過執行階段服務帳戶的 ADC181 auth: {} # 透過執行階段服務帳戶的 ADC
190 ```182```
183
184> [!NOTE]
185>
186> Google id\_tokens 不包含 `groups` 宣告。若要在 [`managed.policies`](/docs/zh-TW/claude-apps-gateway-config#managed) 中使用基於群組的原則,並以 Google Workspace 作為 IdP,請設定 [`oidc.google_groups`](/docs/zh-TW/claude-apps-gateway-config#oidc),它使用具有網域範圍委派的服務帳戶透過 Admin SDK Directory API 查詢每個使用者的群組。沒有它,改為符合 `email_domain`。
191 187
192 <Note>188**6. 在 Secret Manager 中儲存祕密**
193 Google id\_tokens 不包含 `groups` 宣告。若要在 [`managed.policies`](/docs/zh-TW/claude-apps-gateway-config#managed) 中使用基於群組的原則,並以 Google Workspace 作為 IdP,請設定 [`oidc.google_groups`](/docs/zh-TW/claude-apps-gateway-config#oidc),它使用具有網域範圍委派的服務帳戶透過 Admin SDK Directory API 查詢每個使用者的群組。沒有它,改為符合 `email_domain`。
194 </Note>
195 </Step>
196 189
197 <Step title="在 Secret Manager 中儲存祕密">190建立四個祕密並授予 `roles/secretmanager.secretAccessor` 給 `claude-gateway` 服務帳戶:
198 建立四個祕密並授予 `roles/secretmanager.secretAccessor` 給 `claude-gateway` 服務帳戶:
199 191
200 | 祕密 | 來源 |192| 祕密 | 來源 |
201 | - | - |193| - | - |
202 | `gateway-jwt-secret` | `openssl rand -base64 32` |194| `gateway-jwt-secret` | `openssl rand -base64 32` |
203 | `gateway-oidc-client-secret` | Google Cloud Console → OAuth 用戶端 |195| `gateway-oidc-client-secret` | Google Cloud Console → OAuth 用戶端 |
204 | `gateway-postgres-url` | Cloud SQL 步驟中的 `$GATEWAY_POSTGRES_URL` |196| `gateway-postgres-url` | Cloud SQL 步驟中的 `$GATEWAY_POSTGRES_URL` |
205 | `gateway-config` | 前一步驟中的完整 `gateway.yaml` |197| `gateway-config` | 前一步驟中的完整 `gateway.yaml` |
206 198
207 祕密到達容器的方式因軌道而異:199祕密到達容器的方式因軌道而異:
208 200
209 * 在 GKE 上,它們透過 Secret Manager CSI 驅動程式掛載為檔案,`gateway.yaml` 參考 `${file:/secrets/...}`。201* 在 GKE 上,它們透過 Secret Manager CSI 驅動程式掛載為檔案,`gateway.yaml` 參考 `${file:/secrets/...}`。
210 * 在 Cloud Run 上,無法將多個祕密掛載到一個目錄,`gateway.yaml` 掛載為檔案,其他三個注入為環境變數,因此 `gateway.yaml` 改為參考 `${GATEWAY_JWT_SECRET}`、`${OIDC_CLIENT_SECRET}` 和 `${GATEWAY_POSTGRES_URL}`。202* 在 Cloud Run 上,無法將多個祕密掛載到一個目錄,`gateway.yaml` 掛載為檔案,其他三個注入為環境變數,因此 `gateway.yaml` 改為參考 `${GATEWAY_JWT_SECRET}`、`${OIDC_CLIENT_SECRET}` 和 `${GATEWAY_POSTGRES_URL}`。
211 </Step>
212 203
213 <Step title="部署">204**7. 部署**
214 <Tabs>
215 <Tab title="Cloud Run">
216 下面的命令在內部負載平衡器後面部署用於生產。
217 205
218 ```bash theme={null}206**Cloud Run**
219 gcloud run deploy claude-gateway \207
208下面的命令在內部負載平衡器後面部署用於生產。
209
210```bash theme={null}
211gcloud run deploy claude-gateway \
220 --image="${REGION}-docker.pkg.dev/${PROJECT_ID}/claude-gateway/gateway:<version>" \212 --image="${REGION}-docker.pkg.dev/${PROJECT_ID}/claude-gateway/gateway:<version>" \
221 --region="$REGION" \213 --region="$REGION" \
222 --service-account="claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com" \214 --service-account="claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com" \
227 --network="$VPC" --subnet=cc-gateway-subnet --vpc-egress=private-ranges-only \219 --network="$VPC" --subnet=cc-gateway-subnet --vpc-egress=private-ranges-only \
228 --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 \220 --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 \
229 --no-invoker-iam-check221 --no-invoker-iam-check
230 ```222```
223
224直接 VPC 出口,透過 `--network`、`--subnet` 和 `--vpc-egress=private-ranges-only`,讓服務直接到達 Cloud SQL 私有 IP。每個執行個體最多持有 [`store.max_connections`](/docs/zh-TW/claude-apps-gateway-config#store) 個 Postgres 連線,預設為五個,因此保持最大執行個體數 × `store.max_connections` 低於您的 Cloud SQL 層級的連線限制;[參考資產](#terraform-reference)因此將 `db-g1-small` 層級的執行個體上限設為 8。公用出口到 Google Cloud 的 Agent Platform 端點和 `accounts.google.com` 直接進入網際網路,而不是透過 VPC,因此不需要 Cloud NAT。
231 225
232 直接 VPC 出口,透過 `--network`、`--subnet` 和 `--vpc-egress=private-ranges-only`,讓服務直接到達 Cloud SQL 私有 IP。每個執行個體最多持有 [`store.max_connections`](/docs/zh-TW/claude-apps-gateway-config#store) 個 Postgres 連線,預設為五個,因此保持最大執行個體數 × `store.max_connections` 低於您的 Cloud SQL 層級的連線限制;[參考資產](#terraform-reference)因此將 `db-g1-small` 層級的執行個體上限設為 8。公用出口到 Google Cloud 的 Agent Platform 端點和 `accounts.google.com` 直接進入網際網路,而不是透過 VPC,因此不需要 Cloud NAT。226調用者 IAM 檢查必須開啟或停用。閘道執行自己的 OIDC,其用戶端不攜帶 GCP 權杖,因此 Cloud Run 的調用者檢查必須允許未驗證的請求。閘道的 OIDC 登入在請求到達容器後驗證請求,使用 `allowed_email_domains` 限制哪些網域可以登入。
233 227
234 調用者 IAM 檢查必須開啟或停用。閘道執行自己的 OIDC,其用戶端不攜帶 GCP 權杖,因此 Cloud Run 的調用者檢查必須允許未驗證的請求。閘道的 OIDC 登入在請求到達容器後驗證請求,使用 `allowed_email_domains` 限制哪些網域可以登入。228兩個旗標允許未驗證的請求:
235 229
236 兩個旗標允許未驗證的請求:230* `--no-invoker-iam-check`:停用檢查,無需管理 `allUsers` 繫結,並在網域限制共用下工作
231* `--allow-unauthenticated`:授予 `allUsers` `run.invoker` 角色;如果您的組織不允許 `--no-invoker-iam-check`,請使用它
237 232
238 * `--no-invoker-iam-check`:停用檢查,無需管理 `allUsers` 繫結,並在網域限制共用下工作233透過 `--ingress` 的入口限制是與調用者檢查分開的獨立層;保持設定以將服務限制在您的公司網路。
239 * `--allow-unauthenticated`:授予 `allUsers` `run.invoker` 角色;如果您的組織不允許 `--no-invoker-iam-check`,請使用它
240 234
241 透過 `--ingress` 的入口限制是與調用者檢查分開的獨立層;保持設定以將服務限制在您的公司網路。235預設情況下,Cloud Run `*.run.app` URL 解析為公用位址,`/login` [私人網路檢查](/docs/zh-TW/claude-apps-gateway#prerequisites)會拒絕。兩個拓撲為開發人員提供私人可解析的主機名稱,Cloud Run 都不為您佈建:
242 236
243 預設情況下,Cloud Run `*.run.app` URL 解析為公用位址,`/login` [私人網路檢查](/docs/zh-TW/claude-apps-gateway#prerequisites)會拒絕。兩個拓撲為開發人員提供私人可解析的主機名稱,Cloud Run 都不為您佈建:237* **內部應用程式負載平衡器**,此頁面的 `gateway.yaml` 假設的拓撲:在服務前面佈建內部應用程式負載平衡器,具有內部 DNS 名稱和憑證,並將 `listen.public_url` 設定為該主機名稱。`internal` 入口設定已允許來自內部應用程式負載平衡器的流量;`internal-and-cloud-load-balancing` 另外允許外部應用程式負載平衡器,其公用位址 `/login` 私人網路檢查會拒絕,因此此頁面上的拓撲都不需要它。
238* **僅限內部入口,無負載平衡器**:保持部署命令原樣,將 `listen.public_url` 保留為 `*.run.app` URL,下面[參考資產](#terraform-reference)中的預設值。為了讓 `*.run.app` 私人解析,您的網路團隊必須已經為 Google API 運作 Private Service Connect 端點、解析 `*.run.app` 到它的 Cloud DNS 私人區域,以及到該端點的內部部署路由。
244 239
245 * **內部應用程式負載平衡器**,此頁面的 `gateway.yaml` 假設的拓撲:在服務前面佈建內部應用程式負載平衡器,具有內部 DNS 名稱和憑證,並將 `listen.public_url` 設定為該主機名稱。`internal` 入口設定已允許來自內部應用程式負載平衡器的流量;`internal-and-cloud-load-balancing` 另外允許外部應用程式負載平衡器,其公用位址 `/login` 私人網路檢查會拒絕,因此此頁面上的拓撲都不需要它。240Google 的 [Cloud Run 私人網路指南](https://cloud.google.com/run/docs/securing/private-networking)涵蓋兩個選項都需要的基礎結構。一旦閘道在私人主機名稱上提供服務,請驗證登入;在此之前,從 Cloud Run 中的日誌確認容器已啟動。
246 * **僅限內部入口,無負載平衡器**:保持部署命令原樣,將 `listen.public_url` 保留為 `*.run.app` URL,下面[參考資產](#terraform-reference)中的預設值。為了讓 `*.run.app` 私人解析,您的網路團隊必須已經為 Google API 運作 Private Service Connect 端點、解析 `*.run.app` 到它的 Cloud DNS 私人區域,以及到該端點的內部部署路由。
247 241
248 Google 的 [Cloud Run 私人網路指南](https://cloud.google.com/run/docs/securing/private-networking)涵蓋兩個選項都需要的基礎結構。一旦閘道在私人主機名稱上提供服務,請驗證登入;在此之前,從 Cloud Run 中的日誌確認容器已啟動。242在第一次登入前,將 OAuth 用戶端的授權重新導向 URI 更新為 `<public_url>/oauth/callback`。變更 `public_url` 後重新部署,因為閘道僅從該設定建置其公用來源,並忽略 `X-Forwarded-Host` 和 `X-Forwarded-Proto`。`X-Forwarded-For` 僅在設定 `listen.trusted_proxies` 時才被接受用於用戶端 IP。
249 243
250 在第一次登入前,將 OAuth 用戶端的授權重新導向 URI 更新為 `<public_url>/oauth/callback`。變更 `public_url` 後重新部署,因為閘道僅從該設定建置其公用來源,並忽略 `X-Forwarded-Host` 和 `X-Forwarded-Proto`。`X-Forwarded-For` 僅在設定 `listen.trusted_proxies` 時才被接受用於用戶端 IP。244**GKE**
251 </Tab>
252 245
253 <Tab title="GKE">246叢集必須在 Cloud SQL 步驟中建立的 `$VPC` 上,以便 Pod 可以到達資料庫的私有 IP;VPC 對等單獨不起作用,因為 Cloud SQL 私有 IP 本身是對等網路,對等是非傳遞的。若要在該 VPC 上建立新叢集,請將 `--network="$VPC" --subnetwork=cc-gateway-subnet` 傳遞給 `gcloud container clusters create`。
254 叢集必須在 Cloud SQL 步驟中建立的 `$VPC` 上,以便 Pod 可以到達資料庫的私有 IP;VPC 對等單獨不起作用,因為 Cloud SQL 私有 IP 本身是對等網路,對等是非傳遞的。若要在該 VPC 上建立新叢集,請將 `--network="$VPC" --subnetwork=cc-gateway-subnet` 傳遞給 `gcloud container clusters create`。
255 247
256 在叢集及其節點池上啟用 Workload Identity,然後將 Google 服務帳戶繫結到 Kubernetes 服務帳戶,以便 Pod 繼承其認證:248在叢集及其節點池上啟用 Workload Identity,然後將 Google 服務帳戶繫結到 Kubernetes 服務帳戶,以便 Pod 繼承其認證:
257 249
258 ```bash theme={null}250```bash theme={null}
259 gcloud container clusters update <cluster> --region="$REGION" \251gcloud container clusters update <cluster> --region="$REGION" \
260 --workload-pool="${PROJECT_ID}.svc.id.goog"252 --workload-pool="${PROJECT_ID}.svc.id.goog"
261 # 在標準叢集上,現有節點池也需要 GKE_METADATA;253# 在標準叢集上,現有節點池也需要 GKE_METADATA;
262 # Autopilot 預設啟用此功能。254# Autopilot 預設啟用此功能。
263 gcloud container node-pools update <pool> --cluster=<cluster> \255gcloud container node-pools update <pool> --cluster=<cluster> \
264 --region="$REGION" --workload-metadata=GKE_METADATA256 --region="$REGION" --workload-metadata=GKE_METADATA
265 257
266 kubectl create namespace claude-gateway258kubectl create namespace claude-gateway
267 kubectl create serviceaccount gateway -n claude-gateway259kubectl create serviceaccount gateway -n claude-gateway
268 260
269 gcloud iam service-accounts add-iam-policy-binding \261gcloud iam service-accounts add-iam-policy-binding \
270 "claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com" \262 "claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com" \
271 --role roles/iam.workloadIdentityUser \263 --role roles/iam.workloadIdentityUser \
272 --member "serviceAccount:${PROJECT_ID}.svc.id.goog[claude-gateway/gateway]"264 --member "serviceAccount:${PROJECT_ID}.svc.id.goog[claude-gateway/gateway]"
273 265
274 kubectl annotate serviceaccount gateway -n claude-gateway \266kubectl annotate serviceaccount gateway -n claude-gateway \
275 iam.gke.io/gcp-service-account="claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com"267 iam.gke.io/gcp-service-account="claude-gateway@${PROJECT_ID}.iam.gserviceaccount.com"
276 ```268```
269
270將閘道部署為標準 Deployment 加上 Service 和內部 Ingress,類別 `gce-internal`,如 [Kubernetes 部署](/docs/zh-TW/claude-apps-gateway-deploy#kubernetes)中所述,具有:
277 271
278 將閘道部署為標準 Deployment 加上 Service 和內部 Ingress,類別 `gce-internal`,如 [Kubernetes 部署](/docs/zh-TW/claude-apps-gateway-deploy#kubernetes)中所述,具有:272* `serviceAccountName: gateway`
273* Secret Manager CSI 驅動程式在 `/secrets` 掛載祕密
274* 就緒探針指向 `GET /readyz`
279 275
280 * `serviceAccountName: gateway`276將具有提高 `timeoutSec` 的 BackendConfig 附加到閘道 Service:GKE Ingress 後面的負載平衡器後端服務預設為 30 秒超時,這會切斷長串流回應。
281 * Secret Manager CSI 驅動程式在 `/secrets` 掛載祕密
282 * 就緒探針指向 `GET /readyz`
283 277
284 將具有提高 `timeoutSec` 的 BackendConfig 附加到閘道 Service:GKE Ingress 後面的負載平衡器後端服務預設為 30 秒超時,這會切斷長串流回應。278不要在 Workload Identity 叢集上應用阻止 `169.254.169.254` 的出口 NetworkPolicy;Pod 必須到達中繼資料伺服器以取得認證。閘道的內建 [SSRF 防護](/docs/zh-TW/claude-apps-gateway-deploy#threat-model-summary)是那裡的防禦。
285 279
286 不要在 Workload Identity 叢集上應用阻止 `169.254.169.254` 的出口 NetworkPolicy;Pod 必須到達中繼資料伺服器以取得認證。閘道的內建 [SSRF 防護](/docs/zh-TW/claude-apps-gateway-deploy#threat-model-summary)是那裡的防禦。280閘道記錄啟動警告,中繼資料端點可到達,並建議應用出口 NetworkPolicy。在 Workload Identity 下,該警告是預期的,因為 Pod 需要端點。
287 281
288 閘道記錄啟動警告,中繼資料端點可到達,並建議應用出口 NetworkPolicy。在 Workload Identity 下,該警告是預期的,因為 Pod 需要端點。282**8. 將閘道 URL 推送到開發人員機器**
289 </Tab>
290 </Tabs>
291 </Step>
292 283
293 <Step title="將閘道 URL 推送到開發人員機器">284閘道現在正在執行,但開發人員無法從 `/login` 到達它,直到閘道 URL 在他們的機器上。透過 MDM 將完整的[受管設定片段](/docs/zh-TW/claude-apps-gateway#set-the-gateway-url)部署到每個裝置,具有 `forceLoginMethod`、`forceLoginGatewayUrl` 和 `parentSettingsBehavior: "merge"` 選擇加入。登入選擇器中沒有閘道選項供開發人員手動選擇。
294 閘道現在正在執行,但開發人員無法從 `/login` 到達它,直到閘道 URL 在他們的機器上。透過 MDM 將完整的[受管設定片段](/docs/zh-TW/claude-apps-gateway#set-the-gateway-url)部署到每個裝置,具有 `forceLoginMethod`、`forceLoginGatewayUrl` 和 `parentSettingsBehavior: "merge"` 選擇加入。登入選擇器中沒有閘道選項供開發人員手動選擇。
295 </Step>
296</Steps>
297 285
298<h2 id="terraform-reference">286## Terraform 參考
299 Terraform 參考
300</h2>
301 287
302[參考部署資產](https://github.com/anthropics/claude-code/tree/main/examples/gateway/gcp)自動化本頁面上的 Cloud Run 路徑;配置和映像資產適用於兩個路徑:288[參考部署資產](https://github.com/anthropics/claude-code/tree/main/examples/gateway/gcp)自動化本頁面上的 Cloud Run 路徑;配置和映像資產適用於兩個路徑:
303 289
309 295
310資產作為工作範例提供,而非受支援的生產工件;檢查並根據您的環境調整它們。296資產作為工作範例提供,而非受支援的生產工件;檢查並根據您的環境調整它們。
311 297
312<h2 id="troubleshooting">298## 疑難排解
313 疑難排解
314</h2>
315 299
316如需閘道啟動和登入錯誤,請參閱平台無關的[疑難排解表](/docs/zh-TW/claude-apps-gateway-deploy#troubleshooting)。下面的項目特定於 Google Cloud。300如需閘道啟動和登入錯誤,請參閱平台無關的[疑難排解表](/docs/zh-TW/claude-apps-gateway-deploy#troubleshooting)。下面的項目特定於 Google Cloud。
317 301
324| Google Cloud 的 Agent Platform 請求返回 `403 PERMISSION_DENIED` | 執行時未使用 `claude-gateway` 服務帳戶,或模型未在 Model Garden 中為專案啟用 | 在 Cloud Run 上設定 `--service-account` 或在 GKE 上繫結 Workload Identity,並在 Model Garden 中為目標區域啟用每個 Claude 模型 |308| Google Cloud 的 Agent Platform 請求返回 `403 PERMISSION_DENIED` | 執行時未使用 `claude-gateway` 服務帳戶,或模型未在 Model Garden 中為專案啟用 | 在 Cloud Run 上設定 `--service-account` 或在 GKE 上繫結 Workload Identity,並在 Model Garden 中為目標區域啟用每個 Claude 模型 |
325| 串流回應在固定持續時間後切斷 | 前端請求超時:GKE Ingress 後面的負載平衡器後端服務預設為 30 秒,Cloud Run 預設為 300 秒 | 在 GKE 上附加具有提高 `timeoutSec` 的 BackendConfig,或在 Cloud Run 上使用 `--timeout=3600` 部署 |309| 串流回應在固定持續時間後切斷 | 前端請求超時:GKE Ingress 後面的負載平衡器後端服務預設為 30 秒,Cloud Run 預設為 300 秒 | 在 GKE 上附加具有提高 `timeoutSec` 的 BackendConfig,或在 Cloud Run 上使用 `--timeout=3600` 部署 |
326 310
327<h2 id="next-steps">311## 後續步驟
328 後續步驟
329</h2>
330 312
331* [配置參考](/docs/zh-TW/claude-apps-gateway-config):每個 `gateway.yaml` 選項,包括 `managed.policies` 和 `telemetry`313* [配置參考](/docs/zh-TW/claude-apps-gateway-config):每個 `gateway.yaml` 選項,包括 `managed.policies` 和 `telemetry`
332* [部署和操作](/docs/zh-TW/claude-apps-gateway-deploy):IdP 設定、健康檢查、JWT 祕密輪換、升級和安全模型314* [部署和操作](/docs/zh-TW/claude-apps-gateway-deploy):IdP 設定、健康檢查、JWT 祕密輪換、升級和安全模型