תיעוד 115
פריסת שער האפליקציות של קלוד בגוגל קלאוד
דוגמה מעשית להרצת שער האפליקציות של קלוד בגוגל קלאוד: Cloud Run או GKE, Cloud SQL for PostgreSQL, Secret Manager, ואימות חשבון שירות אל Agent Platform של גוגל קלאוד.
[!NOTE]
הדף הזה מלווה דרך אחת להריץ את שער האפליקציות של קלוד בגוגל קלאוד. התצורה היא דוגמה עובדת לתשתית שמנוהלת על ידי הלקוח, והיא אינה פריסת ייצור נתמכת. השתמשו בה כדי לראות איך החלקים מתחברים לפני שתתאימו אותה לסביבה שלכם. לדרישות שאינן תלויות בפלטפורמה, ראו את מדריך הפריסה.
הדוגמה הזו מקימה את שער האפליקציות של קלוד בגוגל קלאוד, עם Agent Platform של גוגל קלאוד כמקור המודל במעלה הזרם, באמצעות Cloud Run או GKE למחשוב. Google Workspace הוא ספק הזהות (IdP) בדוגמה. כל ספק זהות תואם OpenID Connect (OIDC) עובד, ורק בלוק oidc משתנה. ראו הגדרת ספק זהות לפרטים לפי ספק.
#מה תבנו
הפריסה כוללת:
- שירות Cloud Run או Deployment של GKE שמריץ את קונטיינר השער
- מאגר Artifact Registry לתמונת השער
- מופע Cloud SQL for PostgreSQL, כתובת IP פרטית בלבד, עבור ה-store של השער
- סודות Secret Manager עבור
gateway.yaml, מפתח החתימה של JWT, סוד הלקוח של OIDC, וכתובת ה-URL של Postgres - חשבון שירות עם
roles/aiplatform.user, מצורף ישירות ב-Cloud Run או מקושר דרך Workload Identity ב-GKE - חזית HTTPS שאתם מספקים: מאזן עומסים פנימי מסוג Application Load Balancer לפני Cloud Run, שהמדריך הזה מגדיר את השער עבורו ואינו יוצר אותו, או GKE Ingress פנימי ממחלקה
gce-internalב-GKE
#דרישות מקדימות
- פרויקט GCP עם חיוב מופעל, והרשאה ליצור את המשאבים שלמעלה
- ה-CLI של
gcloud, מאומת עםgcloud auth login, ו-Docker מותקן מקומית - למסלול GKE:
kubectl, ואשכול GKE על ה-VPC שנוצר במדריך שבהמשך - גישה למודלים של קלוד שאתם צריכים ב-Model Garden, באזור שמפרסם אותם
- לקוח יישום אינטרנט OAuth 2.0 של Google Workspace עם URI להפניה
https://<gateway-host>/oauth/callback. ראו הגדרת ספק זהות - שם מארח TLS עבור השער, בדרך כלל שם DNS פנימי שמצביע אל מאזן העומסים
הגדירו את הפרויקט והאזור פעם אחת:
export PROJECT_ID=<your-project>
export REGION=us-east5 # a region where the Claude models you need are published in Model Garden
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: נדרשים למסלול Cloud SQL עם כתובת IP פרטיתrun: רק Cloud Runcontainer: רק GKE
2. יצירת חשבון השירות והענקת הרשאות IAM
השער רץ כחשבון שירות ייעודי עם הרשאה לקרוא ל-Agent Platform של Google Cloud. הוא מגיע ל-Cloud SQL דרך ה-VPC עם משתמש סיסמה, ולכן אין צורך בתפקיד IAM של Cloud SQL:
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לאחר מכן הפעל את מודלי Claude עבור הפרויקט ב-Model Garden. המודלים מתפרסמים לאזורים ספציפיים, לכן בדוק כל כרטיס מודל.
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 requires linux/amd64. --provenance=false avoids a buildx OCI
# image index that Cloud Run rejects.
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 עבור PostgreSQL
צור את המופע על VPC באמצעות Private Services Access כך שלא תהיה לו כתובת 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: one-time per 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 הזה, או מנותבת אליו.
5. כתיבת gateway.yaml
בלוק upstreams מצביע על Agent Platform של Google Cloud עם auth: {}, כך שהשער מאמת באמצעות Application Default Credentials מחשבון השירות של סביבת הריצה. ראה את הפניית ההגדרות עבור כל שדה.
שני שדות listen מתארים מה עומד בחזית השער:
public_url: מקורhttps://החיצוני, נדרש לכל bind שאינו loopback. ראה את הפנייתlisten. השער בונה אתredirect_uriשל ה-IdP ואת מסמך הגילוי שלו רק מהערך הזה, אף פעם לא מכותרותX-Forwarded-*.trusted_proxies: טווחי המקור של החזית. השער מכבד אתX-Forwarded-Forרק כאשר עמית ה-TCP נמצא ברשימה הזו, ואז עובר לאורך השרשרת מעבר לקפיצות המהימנות, כך שמגבלות קצב הכניסה לפי IP ואירועי הביקורת רושמים את כתובות ה-IP של המפתחים במקום את אלה של מאזן העומסים.
הגדר את trusted_proxies כך שיתאים לחזית שלך. Ingress חיצוני של GKE ממחלקה gce אינו מופיע ברשימה: הוא מקצה כתובת של כלל העברה ציבורי, שבדיקת הרשת הפרטית של /login דוחה.
| חזית | trusted_proxies |
|---|---|
| Cloud Run שאליו מגיעים ישירות, בלי מאזן עומסים | [169.254.0.0/16] |
| Internal Application Load Balancer בחזית Cloud Run | 169.254.0.0/16 בתוספת ה-CIDR של תת-הרשת proxy-only שלך |
Ingress פנימי של GKE, מחלקה gce-internal | ה-CIDR של תת-הרשת proxy-only שלך |
הדוגמה הבאה משתמשת בערכים של מאזן עומסים פנימי בחזית 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 ignores offline_access; these yield refresh tokens:
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 # keep passing the readiness probe
# through a Cloud SQL failover
upstreams:
- provider: vertex
region: <your-region> # must match $REGION
project_id: <your-project>
auth: {} # ADC via the runtime service account[!NOTE]
אסימוני Google id_tokens אינם נושאים טענת
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-secret | openssl rand -base64 32 |
gateway-oidc-client-secret | Google Cloud Console → OAuth client |
gateway-postgres-url | $GATEWAY_POSTGRES_URL משלב Cloud SQL |
gateway-config | הקובץ gateway.yaml המלא מהשלב הקודם |
האופן שבו הסודות מגיעים לקונטיינר שונה לפי המסלול:
- ב-GKE הם מורכבים כקבצים באמצעות מנהל ההתקן Secret Manager CSI, ו-
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יציאה ישירה ל-VPC, באמצעות --network, --subnet ו---vpc-egress=private-ranges-only, מאפשרת לשירות להגיע לכתובת ה-IP הפרטית של Cloud SQL ישירות. יציאה ציבורית לנקודות הקצה של Agent Platform של Google Cloud ול-accounts.google.com יוצאת ישירות לאינטרנט ולא דרך ה-VPC, ולכן אין צורך ב-Cloud NAT.
[!NOTE]
כל מופע מחזיק עד
store.max_connectionsחיבורי Postgres, חמישה כברירת מחדל. השתמש ב-התאמת גודל מאגר החיבורים כדי לבדוק את--max-instances=8מול החיבורים שנשארו במסד הנתונים עבור השער, וכלול את המופעים הנוספים שעדכון מתגלגל מפעיל.
בדיקת ה-IAM של ה-invoker חייבת להיות פתוחה או מושבתת. השער מריץ OIDC משלו והלקוחות שלו אינם נושאים אסימון GCP, ולכן בדיקת ה-invoker של Cloud Run חייבת לאפשר בקשות לא מאומתות. כניסת ה-OIDC של השער מאמתת את הבקשה ברגע שהיא מגיעה לקונטיינר, ו-allowed_email_domains קובע אילו דומיינים רשאים להיכנס.
שני דגלים מאפשרים בקשות לא מאומתות:
--no-invoker-iam-check: משבית את הבדיקה בלי קישורallUsersלניהול, ועובד תחת Domain Restricted Sharing--allow-unauthenticated: מעניק ל-allUsersאת התפקידrun.invoker. השתמש בו אם הארגון שלך אינו מאפשר--no-invoker-iam-check
הגבלת Ingress באמצעות --ingress היא שכבה נפרדת ועצמאית מבדיקת ה-invoker. השאר אותה מוגדרת כדי להגביל את השירות לרשת הארגונית שלך.
כברירת מחדל כתובת ה-URL *.run.app של Cloud Run נפתרת לכתובת ציבורית, שבדיקת הרשת הפרטית של /login דוחה. שתי טופולוגיות נותנות למפתחים שם מארח שניתן לפתור באופן פרטי, ו-Cloud Run אינו מקצה אף אחת מהן עבורך:
- Internal Application Load Balancer, הטופולוגיה ש-
gateway.yamlבדף זה מניח: הקם Internal Application Load Balancer בחזית השירות עם שם DNS פנימי ותעודה, והגדר אתlisten.public_urlלשם המארח הזה. הגדרת ה-ingressinternalכבר מאפשרת תעבורה ממאזני עומסים פנימיים מסוג Application.internal-and-cloud-load-balancingמאפשר בנוסף מאזני עומסים חיצוניים מסוג Application, שכתובותיהם הציבוריות נדחות על ידי בדיקת הרשת הפרטית של/login, ולכן אין טופולוגיה בדף זה שזקוקה לו. - Ingress פנימי בלבד בלי מאזן עומסים: השאר את פקודת הפריסה כפי שהיא והשאר את
listen.public_urlככתובת*.run.app, ברירת המחדל בנכסי הייחוס בהמשך. כדי ש-*.run.appייפתר באופן פרטי, צוות הרשת שלך חייב כבר להפעיל נקודת קצה של Private Service Connect עבור ממשקי Google API, אזור Cloud DNS פרטי שפותר את*.run.appאליה, וניתוב מהאתר המקומי אל נקודת הקצה הזו.
מדריך הרשת הפרטית של Google ל-Cloud Run מכסה את התשתית ששתי האפשרויות צריכות. אמת את הכניסה לאחר שהשער משרת על שם מארח פרטי. עד אז, אשר שהקונטיינר עלה מהיומנים שלו ב-Cloud Run.
עדכן את כתובת ה-URI המורשית להפניה מחדש של לקוח ה-OAuth אל <public_url>/oauth/callback לפני הכניסה הראשונה. פרוס מחדש לאחר שינוי public_url, כי השער בונה את המקור הציבורי שלו רק מההגדרה הזו ומתעלם מ-X-Forwarded-Host ומ-X-Forwarded-Proto. X-Forwarded-For מכובד עבור כתובות IP של לקוחות רק כאשר listen.trusted_proxies מוגדר.
GKE
האשכול חייב להיות על ה-$VPC שנוצר בשלב Cloud SQL כדי ש-pods יוכלו להגיע לכתובת ה-IP הפרטית של מסד הנתונים. peering של VPC לבדו אינו עובד, כי כתובת IP פרטית של Cloud SQL היא בעצמה רשת peered ו-peering אינו טרנזיטיבי. כדי ליצור אשכול חדש על ה-VPC הזה, העבר --network="$VPC" --subnetwork=cc-gateway-subnet אל gcloud container clusters create.
הפעל Workload Identity על האשכול ועל מאגרי הצמתים שלו, ואז קשר את חשבון השירות של Google לחשבון השירות של Kubernetes כדי שה-pods יירשו את האישורים שלו:
gcloud container clusters update <cluster> --region="$REGION" \
--workload-pool="${PROJECT_ID}.svc.id.goog"
# On a Standard cluster, existing node pools also need GKE_METADATA;
# Autopilot enables this by default.
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"פרוס את השער כ-Deployment רגיל בתוספת Service ו-Ingress פנימי, מחלקה gce-internal, כמתואר ב-פריסת Kubernetes, עם:
serviceAccountName: gateway- מנהל ההתקן Secret Manager CSI שמרכיב סודות ב-
/secrets - בדיקת המוכנות שמופנית אל
GET /readyz
צרף BackendConfig עם timeoutSec מוגדל ל-Service של השער: שירות ה-backend של מאזן העומסים מאחורי Ingress של GKE מוגדר כברירת מחדל לזמן קצוב של 30 שניות, שמנתק תגובות הזרמה ארוכות.
אל תחיל NetworkPolicy של יציאה שחוסמת את 169.254.169.254 על אשכול Workload Identity. ה-pod חייב להגיע לשרת המטא-נתונים עבור אישורים. מגן ה-SSRF המובנה של השער הוא ההגנה שם.
השער רושם אזהרת אתחול שהנקודת קצה של המטא-נתונים נגישה ומציע להחיל NetworkPolicy של יציאה. תחת Workload Identity האזהרה הזו צפויה, כי ה-pod זקוק לנקודת הקצה.
8. דחיפת כתובת ה-URL של השער אל מכונות המפתחים
השער פועל כעת, אבל מפתחים אינם יכולים להגיע אליו מ-/login עד שכתובת ה-URL של השער נמצאת על המכונות שלהם. פרוס את קטע ההגדרות המנוהלות המלא, עם forceLoginMethod, forceLoginGatewayUrl וההצטרפות parentSettingsBehavior: "merge", אל כל מכשיר באמצעות MDM. אין אפשרות שער בבורר הכניסה שמפתח יכול לבחור ידנית.
#ייחוס Terraform
נכסי פריסת הייחוס ממכנים את מסלול Cloud Run בדף זה. נכסי ההגדרה והתמונה חלים על שני המסלולים:
setup.sh: מקצהgcloudאידמפוטנטי שעובר את מסלול Cloud Run המלא, מהפעלת ממשקי API ועד הפריסה הראשונהterraform/: אותה פריסה כתשתית כקוד, לפריסת greenfield: apply ממוקד ליצירת מאגר Artifact Registry, ואז בנייה ודחיפה של התמונה, ואז apply מלאgateway.yaml.exampleו-Dockerfileעבור תמונת הריצה distroless
הארטיפקטים מגדירים כברירת מחדל את ה-ingress של Cloud Run ל-internal, בהתאם לפקודת הפריסה בדף זה. ההגדרה הזו עובדת עם Internal Application Load Balancer בחזית השירות או בלעדיו, והארטיפקטים גם אינם יוצרים את מאזן העומסים. הארטיפקטים גם מגדירים כברירת מחדל את שכבת ה-invoker להענקת run.invoker ל-allUsers ולא ל---no-invoker-iam-check, ההפך מהמדריך בדף זה. שתי האפשרויות עובדות, והבחירה תלויה במגבלות המדיניות של הארגון שלך.
הנכסים מסופקים כדוגמאות עובדות, ולא כארטיפקט ייצור נתמך. סקור והתאם אותם לסביבה שלך.
#פתרון בעיות
לשגיאות אתחול וכניסה של השער, ראו את טבלת פתרון הבעיות שאינה תלויה בפלטפורמה. הרשומות למטה ספציפיות ל-Google Cloud.
| תסמין | סיבה | תיקון |
|---|---|---|
Cloud Run מחזיר 403 Forbidden לפני שהבקשה מגיעה לקונטיינר | בדיקת ה-IAM של ה-invoker עדיין מופעלת | פריסה עם --no-invoker-iam-check, או הענקת התפקיד run.invoker ל-allUsers עם --allow-unauthenticated |
--no-invoker-iam-check נדחה עם invoker_iam_disabled is not currently available | חסום על ידי constraints/run.managed.requireInvokerIam | השתמשו ב---allow-unauthenticated. אם גם Domain Restricted Sharing דרך constraints/iam.allowedPolicyMemberDomains חוסם זאת, השתמשו במסלול GKE, שחושף את השער בשכבת הרשת בלי קישור allUsers. |
Container manifest type … must support amd64/linux בזמן הפריסה | התמונה נבנתה על מארח שאינו amd64, או ש-buildx פלט אינדקס תמונת OCI | בנו עם --platform=linux/amd64 --provenance=false |
| אתחול השער יוצא עם שגיאת timeout של חיבור Postgres ב-Cloud Run | השירות אינו מחובר ל-VPC, או של-Cloud SQL אין IP פרטי באותו VPC | פריסה עם --network ו---subnet עבור Direct VPC egress, ויצירת מופע Cloud SQL עם --no-assign-ip ו---network שמצביע לאותו VPC |
בקשות Agent Platform של Google Cloud מחזירות 403 PERMISSION_DENIED | סביבת הריצה אינה משתמשת בחשבון השירות claude-gateway, או שהמודל אינו מופעל ב-Model Garden עבור הפרויקט | הגדירו --service-account ב-Cloud Run או קשרו Workload Identity ב-GKE, והפעילו כל מודל Claude ב-Model Garden עבור אזור היעד |
| תשובות זורמות נקטעות אחרי משך קבוע | timeout של בקשת חזית: שירות ה-backend של מאזן העומסים מאחורי GKE Ingress ברירת המחדל היא 30 שניות, וב-Cloud Run 300 שניות | צרפו BackendConfig עם timeoutSec מוגבר ב-GKE, או פרסו עם --timeout=3600 ב-Cloud Run |
#הצעדים הבאים
- הפניית תצורה: כל אפשרות של
gateway.yaml, כוללmanaged.policiesו-telemetry - פריסה ותפעול: הגדרת IdP, בדיקות תקינות, רוטציית סוד JWT, שדרוגים, ומודל האבטחה
- מצב בדיקת עומס: בדיקת עומס של שער בלי קריאה לספק מודל
- סקירת שער אפליקציות Claude: התחלה מהירה וחיבור מפתחים