כדי לשמור את המצב של סביבות ארגז החול, אתם יכולים להשתמש בתמונות מצב של Agent Sandbox ב-Google Kubernetes Engine (GKE) בתוך אשכול. הגישה הזו מאפשרת ניפוי באגים עקבי, מאיצה את החזרה על הפיתוח ומאפשרת שחזור מהיר של הגדרות מורכבות. במדריך הזה תפרסו ותבדקו את היכולת הזו על ידי הפעלת אפליקציית לקוח שיוצרת, משהה וממשיכה באופן פרוגרמטי סביבות של ארגז חול בתוך האשכול.
למידע נוסף על צילום קובצי snapshot של Pods, ראו שחזור מקובץ snapshot של Pod.
עלויות
Agent Sandbox ב-GKE היא תוכנה בקוד פתוח שאפשר להשתמש בה ללא עלות נוספת. התמחור של GKE חל על המשאבים שאתם יוצרים, כולל משאבי המחשוב שמשמשים את הבקר של Agent Sandbox.
לפני שמתחילים
-
בדף לבחירת הפרויקט במסוף Google Cloud , בוחרים פרויקט ב- Google Cloud או יוצרים אותו.
התפקידים שנדרשים כדי לבחור או ליצור פרויקט
- בחירת פרויקט: כדי לבחור פרויקט לא נדרש תפקיד IAM ספציפי – אתם יכולים לבחור כל פרויקט שקיבלתם בו תפקיד.
-
יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד "יצירת פרויקטים" (
roles/resourcemanager.projectCreator), שכולל את ההרשאהresourcemanager.projects.create. איך מקצים תפקידים?
מפעילים את ממשקי ה-API של Artifact Registry, Kubernetes Engine ו-Cloud Build, אם הם עדיין לא מופעלים.
התפקידים שנדרשים כדי להפעיל ממשקי API
כדי להפעיל ממשקי API, צריך את ההרשאה
serviceusage.services.enable. אם אתם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד "בעלים" (roles/owner). אחרת, אתם יכולים לקבל את ההרשאה הזו דרך התפקיד "אדמין בממשק 'שימוש בשירות'" (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים?-
מפעילים את Cloud Shell במסוף Google Cloud .
- מוודאים שיש את ההרשאות הנדרשות כדי להשלים את המדריך.
התפקידים הנדרשים
כדי לקבל את ההרשאות שנדרשות ליצירה ולניהול של ארגזי חול, צריך לבקש מהאדמין להקצות לכם ב-IAM את התפקיד אדמין של Kubernetes Engine (roles/container.admin) בפרויקט.
כדי לקרוא הסבר על מתן תפקידים, ראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.
יכול להיות שאפשר לקבל את ההרשאות הנדרשות גם באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש.
מגבלות
כדי ליצור קובצי snapshot של Pod צריך להשתמש ב-gVisor, והם לא פועלים עם ארגזי חול של microVM.
באשכול אזורי, לצמתים באזורים שונים יכולות להיות מיקרו-ארכיטקטורות שונות של מעבדים. מכיוון שתמונות המצב מתעדות את מצב המעבד (CPU), שחזור של תמונת מצב בצומת שחסרות בו תכונות של המעבד ייכשל (לדוגמה, עם השגיאה OCI runtime restore failed: incompatible FeatureSet).
כדי להימנע מהבעיה הזו, צריך להשתמש בהגדרה שמתאימה לסביבה:
- ייצור: כדי לשמור על זמינות גבוהה באשכול, אל תצמידו עומסי עבודה לאזור ספציפי. במקום זאת, כדי להבטיח עקביות בתכונות של המעבד בכל האזורים, צריך לציין פלטפורמת CPU מינימלית. מידע נוסף זמין במאמר בחירת פלטפורמת CPU מינימלית.
- בדיקה: כדי לפשט את ההגדרה ולמנוע שגיאות ראשוניות של חוסר התאמה במעבד (CPU), אתם יכולים להשתמש בשדה
nodeSelectorבמניפסט שלSandboxTemplateכדי להצמיד את ה-Pod לאזור ספציפי, כמוus-central1-a. בדוגמה שבמדריך הזה נעשה שימוש בהגדרת הבדיקה הזו.
הגדרה של משתני סביבה
כדי לפשט את הפקודות שמריצים במדריך הזה, אפשר להגדיר משתני סביבה ב-Cloud Shell. ב-Cloud Shell, מריצים את הפקודות הבאות כדי להגדיר את משתני הסביבה השימושיים הבאים:
export PROJECT_ID=$(gcloud config get project)
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
export CLUSTER_NAME="test-snapshot"
export LOCATION="us-central1"
export ZONE="us-central1-a"
export BUCKET_LOCATION="us"
export MACHINE_TYPE="n2-standard-2"
export REPOSITORY_NAME="agent-sandbox"
export BUCKET_NAME="${PROJECT_ID}_snapshots"
export CLOUDBUILD_BUCKET_NAME="${PROJECT_ID}_cloudbuild"
הנה הסבר על משתני הסביבה האלה:
-
PROJECT_ID: מזהה הפרויקט הנוכחי ב- Google Cloud . הפקודות במסמך הזה משתמשות במזהה הזה כדי לתת שמות למשאבים ולהעניק הרשאות IAM. -
PROJECT_NUMBER: מספר הפרויקט הנוכחי ב- Google Cloud . -
CLUSTER_NAME: השם של אשכול GKE, לדוגמהtest-snapshot. -
LOCATION: האזור של Google Cloud למאגר Artifact Registry (לדוגמה,us-central1). אם יוצרים אשכול Autopilot, האשכול משתמש גם באזור הזה. -
ZONE: האזור של האשכול. אם יוצרים אשכול Standard, צריך להגדיר אותו לאזור ב-LOCATION(לדוגמה,us-central1-a). תבנית ארגז החול שתיצרו בהמשך המדריך מריצה ארגזי חול ב-us-central1-a. אם אתם משתמשים באזור אחר, שנו את האזור גם בתבנית. -
BUCKET_LOCATION: המיקום של הקטגוריות ב-Cloud Storage, לדוגמהus. -
BUCKET_NAME: השם של הקטגוריה של Cloud Storage שמשמשת לשמירת קובצי snapshot, לדוגמהPROJECT_ID_snapshots. שמות הקטגוריות חייבים להיות ייחודיים באופן גלובלי. -
CLOUDBUILD_BUCKET_NAME: השם של הקטגוריה של Cloud Storage שמשמשת ליומנים של Cloud Build. הערך הזה הוא שם הקטגוריה שמוגדר כברירת מחדל ב-Cloud Build, אז אל תשנו אותו. -
MACHINE_TYPE: סוג המכונה שבה משתמשים לצומתי האשכול ולמאגר הצמתים של gVisor, לדוגמהn2-standard-2. אי אפשר להשתמש בתמונות מצב של Pod במכונות מסוג E2. -
REPOSITORY_NAME: השם של מאגר Artifact Registry – לדוגמה,agent-sandbox.
סקירה כללית של שלבי ההגדרה
כדי להפעיל ולבדוק את תמונות המצב של Pod ב-Agent Sandbox בסביבות GKE מתוך האשכול, צריך לבצע כמה שלבי הגדרה. כדי להבין את השלבים האלה, כדאי קודם להבין את הרכיבים שמעורבים בתהליך העבודה הכולל.
הרכיבים העיקריים
במדריך הזה משתמשים בשתי האפליקציות הבאות ב-Python כדי לבדוק את תהליך יצירת קובץ ה-snapshot:
- אפליקציית לקוח: סקריפט Python שפועל ב-Pod רגיל באשכול. האפליקציה הזו מנהלת את מחזור החיים של ארגז החול: היא יוצרת את ארגז החול באופן פרוגרמטי, משהה אותו כדי להפעיל תמונת מצב, מפעילה מחדש את ארגז החול ומוודאת שהמצב נשמר. במדריך הזה תיצרו חשבון שירות ב-Kubernetes בשם
agent-sandbox-client-saותתנו לו הרשאות RBAC, כדי ש-Pod של אפליקציית הלקוח יוכל לנהל משאבים בהתאמה אישית של ארגז החול ואובייקטים של טריגרים של תמונות מצב באמצעות Kubernetes API. - אפליקציה בארגז חול: סקריפט Python שמגדיל ומדפיס מונה בכל שנייה. האפליקציה הזו פועלת באופן מאובטח בסביבת ארגז החול המבודדת כדי ליצור מצב משתנה שאפליקציית הלקוח יכולה לאמת. במדריך הזה תיצרו חשבון שירות ייעודי של Kubernetes בשם
snapshot-saותגדירו את Workload Identity כדי לאשר ל-Pod בארגז החול לקרוא ולכתוב באופן מאובטח אובייקטים של תמונות מצב ב-Cloud Storage.
תהליך ההגדרה והבדיקה
ברשימה הבאה מפורטים השלבים שצריך לבצע כדי להגדיר את הסביבה ולהריץ את הבדיקה:
- יצירת אשכול: יוצרים אשכול Autopilot או אשכול Standard עם תמונות מצב של Pods.
- יצירת מאגר ב-Artifact Registry: יוצרים מאגר Docker כדי לאחסן את קובץ האימג' של הקונטיינר של אפליקציית הלקוח.
- התקנת Agent Sandbox: מתקינים את רכיבי הליבה והתוספים של Agent Sandbox באשכול.
- הגדרת אחסון והרשאות: יוצרים קטגוריה ב-Cloud Storage ומגדירים הרשאות של Workload Identity כדי לאפשר שמירה מאובטחת של קובצי snapshot.
- הגדרת קובצי snapshot של Pod: יוצרים ומחילים את הגדרת האחסון של קובצי ה-snapshot, את מדיניות קובצי ה-snapshot, את תבנית ארגז החול ואת המאגר החם.
- פיתוח גרסת build של אפליקציית הלקוח: פיתוח גרסת build של קובץ האימג' של הקונטיינר לאפליקציית הלקוח והעברה שלו בדחיפה למאגר Artifact Registry.
- מריצים את הבדיקה: פורסים את Pod של אפליקציית הלקוח, שיוצר את ארגז החול, משהה אותו כדי ליצור קובץ snapshot, ממשיך אותו ומאמת שהמצב של המונה שוחזר בהצלחה.
יצירת אשכול
יוצרים אשכול GKE חדש עם תמונות מצב של Pods. כדי ליהנות מתאימות מלאה של התכונות, צריך לציין את ערוץ ההפצה המהירה.
טייס אוטומטי
יוצרים אשכול Autopilot עם התכונות הנדרשות:
gcloud container clusters create-auto ${CLUSTER_NAME} \
--enable-pod-snapshots \
--release-channel=rapid \
--location=${LOCATION}
רגילה
יוצרים אשכול Standard עם התכונות הנדרשות. כדי להפחית את העלויות, הפקודה הבאה יוצרת אשכול אזורי שמריץ את מישור הבקרה והצמתים שלו באזור אחד:
gcloud container clusters create ${CLUSTER_NAME} \
--enable-pod-snapshots \
--release-channel=rapid \
--machine-type=${MACHINE_TYPE} \
--workload-pool=${PROJECT_ID}.svc.id.goog \
--workload-metadata=GKE_METADATA \
--num-nodes=1 \
--location=${ZONE}
יוצרים מאגר צמתים שבו gVisor מופעל:
gcloud container node-pools create gvisor-pool \
--cluster ${CLUSTER_NAME} \
--machine-type=${MACHINE_TYPE} \
--num-nodes=1 \
--location=${ZONE} \
--project=${PROJECT_ID} \
--sandbox type=gvisor
יצירת מאגר ב-Artifact Registry
יוצרים מאגר Docker ב-Artifact Registry כדי לאחסן את קובץ האימג' של הקונטיינר של אפליקציית הלקוח (האפליקציה שיוצרת את ארגז החול ומנהלת אותו):
gcloud artifacts repositories create ${REPOSITORY_NAME} \
--repository-format=docker \
--location=${LOCATION} \
--description="Docker repository for Agent Sandbox"
התקנת Agent Sandbox
מתקינים באשכול את רכיבי הליבה והתוספים של Agent Sandbox. במדריך הזה אנחנו משתמשים בגרסה 1.0.6:
# Install the core agent-sandbox components and the extensions (e.g., Warm Pools, Claims)
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v1.0.6/sandbox-with-extensions.yaml
איך מתקינים את Agent Sandbox ב-GKE
הגדרת האחסון וההרשאות
מגדירים קטגוריה של Cloud Storage לאחסון תמונות מצב של Pod, ונותנים את ההרשאות הנדרשות של Workload Identity לחשבון השירות snapshot-sa ולסוכן השירות של GKE. כך עומסי העבודה בארגז החול יכולים לשמור ולאחזר אובייקטים של קובצי snapshot בצורה מאובטחת:
יוצרים קטגוריה חדשה ב-Cloud Storage:
gcloud storage buckets create "gs://${BUCKET_NAME}" \ --uniform-bucket-level-access \ --enable-hierarchical-namespace \ --soft-delete-duration=0d \ --location="${BUCKET_LOCATION}"יוצרים חשבון שירות של Kubernetes במרחב השמות
default. האפליקציה בארגז החול (סקריפט המונה של Python) משתמשת בזהות הזו כדי לאמת את ממשקי ה-API החיצוניים ולגשת באופן מאובטח לאובייקטים של תמונות המצב שמאוחסנים ב-Cloud Storage:kubectl create serviceaccount "snapshot-sa" \ --namespace "default"מקשרים את התפקיד
storage.bucketViewerלחשבון השירות באמצעות Workload Identity. התפקיד הזה מאפשר לעומס העבודה בארגז החול להציג את תוכן הקטגוריה ולאתר קובצי snapshot ספציפיים:gcloud storage buckets add-iam-policy-binding "gs://${BUCKET_NAME}" \ --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/default/sa/snapshot-sa" \ --role="roles/storage.bucketViewer"מקשרים את התפקיד
storage.objectUserלחשבון השירות באמצעות Workload Identity. התפקיד הזה נותן הרשאה לקרוא, לשמור ולמחוק אובייקטים בינאריים של קובצי snapshot בקטגוריה:gcloud storage buckets add-iam-policy-binding "gs://${BUCKET_NAME}" \ --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/default/sa/snapshot-sa" \ --role="roles/storage.objectUser"נותנים לסוכן השירות של GKE הרשאות לנהל (ליצור, להציג ברשימה, לקרוא ולמחוק) אובייקטים של קובצי snapshot בתוך הקטגוריה:
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:service-${PROJECT_NUMBER}@container-engine-robot.iam.gserviceaccount.com" \ --role="roles/storage.objectUser" \ --condition="expression=resource.name.startsWith(\"projects/_/buckets/${BUCKET_NAME}\"),title=restrict_to_bucket,description=Restricts access to one bucket only"
הגדרת תמונות מצב של Pod
יוצרים את קובצי התצורה ומוסיפים אותם כדי להתקין את המשאבים הנדרשים בהתאמה אישית של Kubernetes. המשאבים האלה מגדירים איך האשכול מאחסן ומנהל את קובצי ה-snapshot של ה-Pod:
-
PodSnapshotStorageConfig: מציין את הקטגוריה של Cloud Storage שמיועדת לאחסון אובייקטים בינאריים של קובצי snapshot. -
PodSnapshotPolicy: מגדיר איך מפעילים תמונות מצב באופן ידני, באיזו תדירות הן מקובצות ואת מדיניות שמירת הנתונים שלהן. -
SandboxTemplate: מגדיר את הקונטיינר הבסיסי, את בוררי הצמתים ואת חשבונות השירות להרצת עומס העבודה המבודד בארגז החול. -
SandboxWarmPool: שומרת על ארגז חול שחומם מראש, שנוצר מהמשאבSandboxTemplate, מוכן לתביעה על ידי אפליקציית הלקוח.
יוצרים ספרייה חדשה לקובצי לקוח הבדיקה:
mkdir test_clientעוברים לספרייה החדשה:
cd test_clientיוצרים קובץ בשם
snapshot_storage_config.yaml. ההגדרה הזו מציינת את קטגוריית היעד של Cloud Storage שבה האשכול שומר את המצב של קובץ ה-snapshot הבינארי של ה-Pod:apiVersion: podsnapshot.gke.io/v1 kind: PodSnapshotStorageConfig metadata: name: example-pod-snapshot-storage-config spec: snapshotStorageConfig: gcs: bucket: "$BUCKET_NAME"מחליפים את הפלייסהולדר של משתנה הסביבה בקובץ התצורה:
sed -i "s/\$BUCKET_NAME/${BUCKET_NAME}/g" snapshot_storage_config.yamlמחילים את המניפסט של הגדרת האחסון:
kubectl apply -f snapshot_storage_config.yamlמחכים עד שהגדרת האחסון תהיה מוכנה:
kubectl wait --for=condition=Ready podsnapshotstorageconfig/example-pod-snapshot-storage-config --timeout=60sיוצרים קובץ בשם
snapshot_policy.yaml. ההגדרה הזו קובעת כלל שמירה ששומר עד שתי תמונות מצב של עומס העבודה בארגז החול. סוג הטריגר מוגדר כ-manual: ההגדרה הזו מאפשרת לאפליקציית הלקוח לשלוט בתמונות המצב לפי דרישה:apiVersion: podsnapshot.gke.io/v1 kind: PodSnapshotPolicy metadata: name: example-pod-snapshot-policy namespace: default spec: storageConfigName: example-pod-snapshot-storage-config selector: matchLabels: app: agent-sandbox-workload triggerConfig: type: manual postCheckpoint: resume snapshotGroupingRules: groupByLabelValue: labels: ["agents.x-k8s.io/sandbox-name-hash", "tenant-id", "user-id"] groupRetentionPolicy: maxSnapshotCountPerGroup: 2מחילים את המניפסט של מדיניות תמונת המצב:
kubectl apply -f snapshot_policy.yamlיוצרים קובץ בשם
python-counter-template.yaml. ההגדרה הזו מגדירה את ה-Pod של ארגז החול ומקצה לו את הזהות של חשבון השירותsnapshot-sa. ההקצאה הזו עוזרת לוודא שארגז החול פועל בצורה מאובטחת. בתוך ה-Pod, האפליקציה בארגז החול (סקריפט Python) מדפיסה באופן רציף מונה הולך וגדל ביומני הקונטיינר:apiVersion: extensions.agents.x-k8s.io/v1beta1 kind: SandboxTemplate metadata: name: python-counter-template namespace: default spec: podTemplate: metadata: labels: app: agent-sandbox-workload spec: serviceAccountName: snapshot-sa runtimeClassName: gvisor nodeSelector: topology.kubernetes.io/zone: us-central1-a # Pin to a zone to avoid CPU mismatch during restore containers: - name: python-counter image: python:3.13-slim command: ["python3", "-c"] args: - | import time i = 0 while True: print(f"Count: {i}", flush=True) i += 1 time.sleep(1)מחילים את המניפסט של תבנית ארגז החול:
kubectl apply -f python-counter-template.yamlיוצרים קובץ בשם
python-counter-pool.yaml. ההגדרה הזו יוצרת מאגר חם ששומר על ארגז חול אחד שחומם מראש, שנוצר מהתבניתpython-counter-template, ומוכן לשימוש של אפליקציית הלקוח:apiVersion: extensions.agents.x-k8s.io/v1beta1 kind: SandboxWarmPool metadata: name: python-counter-pool namespace: default spec: replicas: 1 sandboxTemplateRef: name: python-counter-templateמחילים את המניפסט של המאגר החם:
kubectl apply -f python-counter-pool.yaml
פיתוח אפליקציית הלקוח
יוצרים את קובץ האימג' של הקונטיינר לאפליקציית הלקוח ומעלים אותו ל-Artifact Registry.
יוצרים קובץ בשם
Dockerfile.client. הקובץ הזה מגדיר את סביבת זמן הריצה של Python ואת יחסי התלות של אפליקציית הלקוח:FROM python:3.13-slim WORKDIR /app RUN pip install "k8s-agent-sandbox[tracing]==1.0.6" # Copy test script COPY client_test.py /app/client_test.py CMD ["python", "/app/client_test.py"]יוצרים קובץ בשם
client_test.py. הסקריפט הזה מנהל את מחזור החיים של ארגז החול ומוודא שהמצב ממשיך לפעול אחרי שנוצרת תמונת מצב:import time import logging import re from kubernetes import config, client from k8s_agent_sandbox.gke_extensions.snapshots import PodSnapshotSandboxClient logging.basicConfig(level=logging.INFO) def get_last_count(pod_name, namespace): v1 = client.CoreV1Api() try: logs = v1.read_namespaced_pod_log(name=pod_name, namespace=namespace) counts = re.findall(r"Count: (\d+)", logs) if counts: return int(counts[-1]) return None except Exception as e: logging.error(f"Failed to read logs for pod {pod_name}: {e}") return None def get_current_count(sandbox): # The sandbox's Pod has the same name as the Sandbox resource. pod_name = sandbox.get_pod_name() if not pod_name: logging.error(f"Could not determine pod name for sandbox {sandbox.sandbox_id}") return None return get_last_count(pod_name, sandbox.namespace) def suspend_sandbox(sandbox): logging.info("Pausing sandbox (using snapshots)...") try: suspend_resp = sandbox.suspend(snapshot_before_suspend=True) if suspend_resp.success: logging.info("Sandbox paused successfully.") if suspend_resp.snapshot_response: logging.info(f"Snapshot created: {suspend_resp.snapshot_response.snapshot_uid}") return suspend_resp else: logging.error(f"Failed to pause: {suspend_resp.error_reason}") exit(1) except Exception as e: logging.error(f"Failed to pause sandbox: {e}") exit(1) def resume_sandbox(sandbox): logging.info("Resuming sandbox (using snapshots)...") try: resume_resp = sandbox.resume() if resume_resp.success: logging.info("Sandbox resumed successfully.") if resume_resp.restored_from_snapshot: logging.info(f"Restored from snapshot: {resume_resp.snapshot_uid}") return resume_resp else: logging.error(f"Failed to resume: {resume_resp.error_reason}") exit(1) except Exception as e: logging.error(f"Failed to resume sandbox: {e}") exit(1) def verify_continuity(count_before, count_after): if count_before is not None and count_after is not None: logging.info(f"Verification: Count before={count_before}, Count after={count_after}") if count_after >= count_before: logging.info("SUCCESS: Sandbox resumed from where it left off (or later).") else: logging.error("FAIL: Sandbox counter reset or went backwards!") else: logging.warning("Could not verify counter continuity.") def main(): try: config.load_incluster_config() except config.ConfigException: config.load_kube_config() client_reg = PodSnapshotSandboxClient() logging.info("Creating sandbox...") sandbox = client_reg.create_sandbox(warmpool="python-counter-pool", namespace="default") logging.info(f"Sandbox created with ID: {sandbox.sandbox_id}") logging.info("Waiting for sandbox to run...") time.sleep(10) count_before = get_current_count(sandbox) logging.info(f"Count before suspend: {count_before}") suspend_sandbox(sandbox) logging.info("Waiting 10 seconds...") time.sleep(10) resume_sandbox(sandbox) logging.info("Waiting for sandbox to be ready again...") time.sleep(10) count_after = get_current_count(sandbox) logging.info(f"Count after resume: {count_after}") verify_continuity(count_before, count_after) logging.info("Snapshot test completed successfully.") if __name__ == "__main__": main()יוצרים את קובץ האימג' של קונטיינר הלקוח ומעלים אותו ל-Artifact Registry. אם Docker מותקן בסביבה שלכם (כמו Cloud Shell), אתם יכולים להשתמש ב-Docker כדי ליצור את קובץ האימג' באופן מקומי. אם אתם עובדים בסביבה בלי Docker, אתם יכולים להשתמש ב-Cloud Build כדי ליצור את קובץ האימג' ולהעביר אותו בדחיפה מרחוק:
Docker
מגדירים את האימות של Docker ל-Artifact Registry:
gcloud auth configure-docker "${LOCATION}-docker.pkg.dev"יוצרים את קובץ האימג' של קונטיינר הלקוח ודוחפים אותו באופן מקומי:
docker build -t "${LOCATION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/sandbox-client:latest" -f Dockerfile.client . docker push "${LOCATION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/sandbox-client:latest"
Cloud Build
יוצרים קובץ בשם
cloudbuild.yaml:steps: - name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', '$LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/sandbox-client:latest', '-f', 'Dockerfile.client', '.'] images: - '$LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/sandbox-client:latest'מחליפים את הפלייסהולדרים של משתני הסביבה בקובץ התצורה:
sed -i "s/\$REPOSITORY_NAME/${REPOSITORY_NAME}/g" cloudbuild.yaml sed -i "s/\$LOCATION/${LOCATION}/g" cloudbuild.yaml sed -i "s/\$PROJECT_ID/${PROJECT_ID}/g" cloudbuild.yamlיוצרים את הקטגוריה של Cloud Storage ליומנים של Cloud Build. אם כבר השתמשתם ב-Cloud Build בפרויקט, יכול להיות שהקטגוריה הזו כבר קיימת, והפקודה תיכשל עם הודעת שגיאה שאומרת שהקטגוריה כבר בבעלותכם. אפשר להתעלם מהשגיאה הזו:
gcloud storage buckets create "gs://${CLOUDBUILD_BUCKET_NAME}" \ --location="${BUCKET_LOCATION}"נותנים את ההרשאות הנדרשות לחשבון השירות של Cloud Build.
בפקודות הבאות נעשה שימוש בחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine (
$PROJECT_NUMBER-compute@developer.gserviceaccount.com), שהוא ברירת המחדל ברוב הפרויקטים. אם בפרויקט שלכם משתמשים בחשבון השירות הקודם של Cloud Build, החליפו את כתובת האימייל של החבר בפקודות הבאות ב-$PROJECT_NUMBER@cloudbuild.gserviceaccount.com.בשלב מוקדם יותר במדריך הוספתם לפרויקט קישור מותנה של IAM, ולכן צריך לכלול את הדגל
--condition=Noneכשמוסיפים את הקישורים החדשים האלה. כך מונעים מ-gcloudלהשהות את הפעולה כדי לבקש אישור אינטראקטיבי:gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \ --role="roles/artifactregistry.writer" \ --condition=None gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \ --role="roles/logging.logWriter" \ --condition=None gcloud storage buckets add-iam-policy-binding "gs://${CLOUDBUILD_BUCKET_NAME}" \ --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \ --role="roles/storage.objectAdmin"מריצים את ה-build באמצעות Cloud Build:
gcloud builds submit --config cloudbuild.yaml
הרצת הבדיקה
פורסים את אפליקציית הלקוח כדי ליצור את ארגז החול, מפעילים קובץ snapshot ומוודאים שהמונה הפנימי ממשיך לפעול מהמצב השמור שלו.
יוצרים קובץ בשם
client_sa.yaml. המניפסט הזה מגדיר את חשבון השירותagent-sandbox-client-saואת הרשאות ה-RBAC שנדרשות לו כדי לנהל משאבים בהתאמה אישית של ארגז החול:apiVersion: v1 kind: ServiceAccount metadata: name: agent-sandbox-client-sa namespace: default --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: agent-sandbox-client-role namespace: default rules: - apiGroups: ["agents.x-k8s.io"] resources: ["sandboxes"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - apiGroups: ["extensions.agents.x-k8s.io"] resources: ["sandboxclaims"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - apiGroups: ["podsnapshot.gke.io"] resources: ["podsnapshotmanualtriggers", "podsnapshots"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - apiGroups: [""] resources: ["pods", "pods/log"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: agent-sandbox-client-rolebinding namespace: default subjects: - kind: ServiceAccount name: agent-sandbox-client-sa namespace: default roleRef: kind: Role name: agent-sandbox-client-role apiGroup: rbac.authorization.k8s.ioמחילים את חשבון השירות של הלקוח ואת המניפסט של RBAC:
kubectl apply -f client_sa.yamlיוצרים קובץ בשם
client_pod.yaml. המניפסט הזה יוצר את Pod של אפליקציית הלקוח באמצעות קובץ האימג' של הקונטיינר שנוצר מראש:apiVersion: v1 kind: Pod metadata: name: agent-sandbox-client-pod namespace: default spec: serviceAccountName: agent-sandbox-client-sa containers: - name: client image: $LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/sandbox-client:latest imagePullPolicy: Always restartPolicy: Neverמחליפים את הפלייסהולדרים של משתני הסביבה במניפסט:
sed -i "s/\$REPOSITORY_NAME/${REPOSITORY_NAME}/g" client_pod.yaml sed -i "s/\$LOCATION/${LOCATION}/g" client_pod.yaml sed -i "s/\$PROJECT_ID/${PROJECT_ID}/g" client_pod.yamlמחכים עד שארגז החול של המאגר החם יהיה מוכן:
kubectl wait sandboxwarmpool python-counter-pool \ --for=jsonpath='{.status.readyReplicas}'=1 \ --timeout=600sבשלב הבא, אפליקציית הלקוח יוצרת משאב
SandboxClaim. אם האפליקציה יוצרת את ה-claim לפני שארגז החול של המאגר מוכן, יכול להיות שהבקר ייצור ארגז חול חדש בשביל ה-claim במקום להקצות את ארגז החול מהמאגר. באשכול Autopilot, יכול להיות שיעברו כמה דקות עד שארגז החול יהיה מוכן, כי יכול להיות ש-GKE יצטרך ליצור בשבילו צומת.מחילים את המניפסט של Pod של אפליקציית הלקוח:
kubectl apply -f client_pod.yamlמעבירים בסטרימינג את היומנים של Pod כדי לאמת את תהליך הביצוע:
kubectl logs -f agent-sandbox-client-pod
כשהבדיקה פועלת כמו שצריך, הפלט אמור להיראות כך (הפלט קוצר כדי שיהיה קל יותר לקרוא אותו):
2026-04-21 23:02:39,030 - INFO - Creating sandbox...
...
2026-04-21 23:02:51,755 - INFO - Count before suspend: 23
2026-04-21 23:02:51,755 - INFO - Pausing sandbox (using snapshots)...
...
2026-04-21 23:03:07,115 - INFO - Resuming sandbox (using snapshots)...
...
2026-04-21 23:03:21,329 - INFO - Count after resume: 38
2026-04-21 23:03:21,329 - INFO - Verification: Count before=23, Count after=38
2026-04-21 23:03:21,329 - INFO - SUCCESS: Sandbox resumed from where it left off (or later).
הפלט מראה שארגז החול שומר על המצב שלו כשהוא מושהה ומופעל מחדש. המונה מפסיק להתקדם בזמן שהארגז מושעה, כי הבקר של Agent Sandbox מוחק את ה-Pod של הארגז. כשהארגז החול ממשיך, הבקר יוצר מחדש את ה-Pod, שמשחזר מתמונת המצב, והמונה ממשיך. אם לא היינו משעים את הספירה, המונה היה ממשיך להתקדם במהלך תקופת ההשעיה והספירה הייתה גבוהה משמעותית.
מחיקת משאבים
כדי להימנע מצבירת חיובים בחשבון Google Cloud , מוחקים את המשאבים שיצרתם:
מוחקים את אשכול GKE. הפעולה הזו גם מוחקת את מאגר הצמתים ואת כל חשבונות השירות של Kubernetes שבתוכו:
טייס אוטומטי
gcloud container clusters delete ${CLUSTER_NAME} \ --location="${LOCATION}" --quietרגילה
gcloud container clusters delete ${CLUSTER_NAME} \ --location="${ZONE}" --quietמוחקים את המאגר ב-Artifact Registry כדי להסיר את מאגר Docker שיצרתם בשביל קובץ האימג' לבדיקה:
gcloud artifacts repositories delete ${REPOSITORY_NAME} --location="${LOCATION}" --quietמוחקים את הקטגוריה של Cloud Storage ואת כל קובצי ה-snapshot שבתוכה. הפעולה הזו מסירה באופן אוטומטי את קישורי ה-IAM של Workload Identity ברמת הקטגוריה שחלים עליה:
gcloud storage rm --recursive "gs://${BUCKET_NAME}"מסירים את הקישור של סוכן השירות של GKE ל-IAM ברמת הפרויקט:
gcloud projects remove-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:service-${PROJECT_NUMBER}@container-engine-robot.iam.gserviceaccount.com" \ --role="roles/storage.objectUser" \ --condition="expression=resource.name.startsWith(\"projects/_/buckets/${BUCKET_NAME}\"),title=restrict_to_bucket,description=Restricts access to one bucket only"אם השתמשתם ב-Cloud Build במקום ב-Docker כדי ליצור את קובץ האימג' של הקונטיינר ולהעביר אותו בדחיפה, אתם צריכים לנקות את המשאבים של Cloud Build. מוחקים רק את המשאבים שיצרתם בשביל המדריך הזה, כי יכול להיות שעומסי עבודה אחרים בפרויקט תלויים במשאבים שהיו קיימים לפני כן:
אם הקטגוריה של Cloud Build לא הייתה קיימת לפני שהתחלתם את המדריך, מחקו אותה:
gcloud storage rm --recursive "gs://${CLOUDBUILD_BUCKET_NAME}"אם לחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine לא היו התפקידים
roles/artifactregistry.writerו-roles/logging.logWriterלפני שהתחלתם את המדריך, הסירו אותם:gcloud projects remove-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \ --role="roles/artifactregistry.writer" \ --condition=None gcloud projects remove-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \ --role="roles/logging.logWriter" \ --condition=None
המאמרים הבאים
- איך מבודדים הרצת קוד של AI באמצעות Agent Sandbox ב-GKE
- איך שומרים ומשחזרים את Agent Sandbox בסביבות GKE
- כדי להבין את שכבות הבידוד שמגינות על עומסי עבודה לא מהימנים, קראו את המאמר GKE Sandbox.
- פרויקט Agent Sandbox בקוד פתוח ב-GitHub.
- איך משתמשים ב-Kata Containers בקוד פתוח עם Agent Sandbox ב-GKE Kata Containers הוא לא מוצר של Google Cloud . אם אתם מתקינים את התוכנה הזו ומשתמשים בה, אתם אחראים לניהול ולפתרון בעיות. התמיכה והסכמי ה-SLA של Google לא חלים על Kata Containers.