מדריך קלוד קוד בעברית

תיעוד 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 משתנה. ראו הגדרת ספק זהות לפרטים לפי ספק.

#מה תבנו

תרשים של שער האפליקציות של קלוד בגוגל קלאוד: לקוחות Claude Code מתחברים ב-HTTPS אל השער (Cloud Run או GKE), שרץ בתוך VPC לצד מסד נתונים Cloud SQL עם IP פרטי עבור מצב הסשן. השער מחבר משתמשים באמצעות OIDC מול Google Workspace, קורא הגדרות וסודות מ-Secret Manager, מעביר בקשות מודל אל Agent Platform של גוגל קלאוד, ומושך את התמונה שלו מ-Artifact Registry בזמן הפריסה.

הפריסה כוללת:

  • שירות 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 Run
  • container: רק 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 Run169.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-secretopenssl rand -base64 32
gateway-oidc-client-secretGoogle 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 לשם המארח הזה. הגדרת ה-ingress internal כבר מאפשרת תעבורה ממאזני עומסים פנימיים מסוג 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

#הצעדים הבאים