אתם יכולים להשתמש בתמונות מצב של ארגז החול לסוכנים באשכול Google Kubernetes Engine (GKE) כדי לשמור את המצב של סביבות ארגז החול. הגישה הזו מאפשרת ניפוי באגים עקבי, מאיצה את חזרות הפיתוח ומקלה על שחזור מהיר של הגדרות מורכבות. במדריך הזה, תפרסו ותבדקו את היכולת הזו על ידי הפעלת אפליקציית לקוח שיוצרת, משהה וממשיכה באופן פרוגרמטי סביבות ארגז חול בתוך האשכול.
מידע נוסף על יצירת תמונות מצב של Pods זמין במאמר שחזור מתמונת מצב של Pod.
עלויות
Agent Sandbox מוצע ללא תשלום נוסף ב-GKE. התמחור של GKE חל על המשאבים שאתם יוצרים.
לפני שמתחילים
-
בדף לבחירת הפרויקט במסוף Cloud de Confiance , בוחרים פרויקט ב- Cloud de Confiance או יוצרים אותו.
תפקידים שנדרשים כדי לבחור או ליצור פרויקט
- Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
-
יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד Project Creator (יצירת פרויקטים) (
roles/resourcemanager.projectCreator), שכולל את ההרשאהresourcemanager.projects.create. איך מקצים תפקידים
מפעילים את ממשקי ה-API של Artifact Registry, Kubernetes Engine ו-Cloud Build.
תפקידים שנדרשים להפעלת ממשקי API
כדי להפעיל ממשקי API, צריך את תפקיד ה-IAM 'אדמין של Service Usage' (
roles/serviceusage.serviceUsageAdmin), שכולל את ההרשאהserviceusage.services.enable. איך מקצים תפקידים-
במסוף Cloud de Confiance , מפעילים את Cloud Shell.
- מוודאים שיש את ההרשאות הנדרשות כדי להשלים את המדריך הזה.
התפקידים הנדרשים
כדי לקבל את ההרשאות שנדרשות ליצירה ולניהול של ארגזי חול, צריך לבקש מהאדמין להקצות לכם את תפקיד ה-IAM Kubernetes Engine Admin (roles/container.admin) בפרויקט.
כדי לקרוא הסבר על מתן תפקידים, ראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.
יכול להיות שאפשר לקבל את ההרשאות הנדרשות גם באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש.
מגבלות
באשכול אזורי, יכול להיות שלצמתים באזורים שונים יש מיקרו-ארכיטקטורות שונות של מעבדים. מכיוון שתמונות המצב מתעדות את מצב ה-CPU, שחזור של תמונת מצב בצומת שחסרות בו תכונות של ה-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 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: מזהה הפרויקט הנוכחי ב- Cloud de Confiance by S3NS . הגדרת המשתנה הזה עוזרת לוודא שכל המשאבים נוצרים בפרויקט הנכון. -
PROJECT_NUMBER: מספר הפרויקט הנוכחי ב- Cloud de Confiance by S3NS . -
CLUSTER_NAME: השם של אשכול GKE, לדוגמהtest-snapshot. -
LOCATION: Cloud de Confiance by S3NS האזור שבו נמצאים אשכול GKE ומאגר Artifact Registry, לדוגמה,us-central1. -
BUCKET_LOCATION: המיקום של דלי Cloud Storage, לדוגמהus. -
BUCKET_NAME: השם של קטגוריה של Cloud Storage שמשמשת לקובצי snapshot. -
CLOUDBUILD_BUCKET_NAME: השם של קטגוריית Cloud Storage שמשמשת ליומנים של Cloud Build. -
MACHINE_TYPE: סוג המכונה שבה יש להשתמש לצמתי האשכול, לדוגמהe2-standard-8. -
REPOSITORY_NAME: השם של מאגר Artifact Registry, לדוגמהagent-sandbox.
סקירה כללית של שלבי ההגדרה
כדי להפעיל ולבדוק תמונות מצב של Pod בסביבות ארגז חול של סוכנים מתוך האשכול, צריך לבצע כמה שלבי הגדרה. כדי להבין את השלבים האלה, כדאי קודם להבין את הרכיבים שמשתתפים בתהליך העבודה הכולל.
רכיבים מרכזיים
במדריך הזה משתמשים בשתי אפליקציות Python הבאות כדי לבדוק את תהליך יצירת התמונה:
- אפליקציית לקוח: סקריפט Python שפועל ב-Pod רגיל באשכול. האפליקציה הזו מנהלת את מחזור החיים של ארגז החול: היא יוצרת את ארגז החול באופן פרוגרמטי, משהה אותו כדי להפעיל צילום מצב, מפעילה מחדש את ארגז החול ומוודאת שהמצב נשמר. במדריך הזה, יוצרים חשבון שירות ב-Kubernetes בשם
agent-sandbox-client-saומעניקים לו הרשאות RBAC כדי שה-Pod של אפליקציית הלקוח יוכל לנהל משאבים בהתאמה אישית של ארגז חול ואובייקטים של הפעלת תמונת מצב באמצעות Kubernetes API. - אפליקציה בסביבת ארגז חול: סקריפט Python שמגדיל ומדפיס מונה כל שנייה. האפליקציה הזו פועלת בצורה מאובטחת בסביבת ארגז החול המבודדת כדי ליצור מצב משתנה שאפליקציית הלקוח יכולה לאמת. במדריך הזה אתם יוצרים חשבון שירות ייעודי ב-Kubernetes בשם
snapshot-saומגדירים Workload Identity כדי לתת לקבוצת ה-Pod בארגז החול הרשאה לקרוא ולכתוב אובייקטים של תמונות מצב ב-Cloud Storage בצורה מאובטחת.
תהליך ההגדרה והבדיקה
הרשימה הבאה מסכמת את השלבים שצריך לבצע כדי להגדיר את הסביבה ולהריץ את הבדיקה:
- יצירת אשכול: יצירת אשכול במצב Autopilot או אשכול רגיל עם תמונות מצב של Pod ותכונת Agent Sandbox מופעלת.
- יוצרים מאגר ב-Artifact Registry: יוצרים מאגר Docker לאחסון קובץ האימג' של קונטיינר לאפליקציית הלקוח.
- Install Agent Sandbox: התקנת רכיבי הליבה ותוספים של Agent Sandbox באשכול.
- הגדרת אחסון והרשאות: יצירת קטגוריה של Cloud Storage והגדרת הרשאות Workload Identity כדי לאפשר שמירת קובצי snapshot בצורה מאובטחת.
- הגדרת snapshots של Pod: יצירה והחלה של הגדרת אחסון ה-snapshot, מדיניות ה-snapshot ותבנית ארגז החול.
- יצירת גרסת build של אפליקציית הלקוח: יוצרים את קובץ אימג' של קונטיינר של אפליקציית הלקוח ומעבירים אותו בדחיפה למאגר Artifact Registry.
- מריצים את הבדיקה: פורסים את ה-Pod של אפליקציית הלקוח, שיוצר את ארגז החול, משהה אותו כדי לצלם תמונת מצב, מפעיל אותו מחדש ומוודא שהמצב של המונה שוחזר בהצלחה.
יצירת אשכול
יוצרים אשכול GKE חדש עם הפעלת תמונות מצב של Pod. כדי ליהנות מתאימות מלאה של התכונות, צריך לציין את ערוץ ההפצה המהירה.
טייס אוטומטי
יוצרים אשכול Autopilot עם התכונות הנדרשות:
gcloud beta container clusters create-auto ${CLUSTER_NAME} \
--enable-pod-snapshots \
--release-channel=rapid \
--location=${LOCATION}
רגילה
יוצרים אשכול רגיל עם התכונות הנדרשות:
gcloud beta container clusters create ${CLUSTER_NAME} \
--enable-pod-snapshots \
--release-channel=rapid \
--machine-type=${MACHINE_TYPE} \
--workload-pool=${PROJECT_ID}.s3ns.svc.id.goog \
--workload-metadata=GKE_METADATA \
--num-nodes=1 \
--location=${LOCATION}
יוצרים מאגר צמתים עם gVisor מופעל:
gcloud container node-pools create gvisor-pool \
--cluster ${CLUSTER_NAME} \
--num-nodes=1 \
--location=${LOCATION} \
--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"
התקנת ארגז חול של סוכן
מתקינים את רכיבי הליבה והתוספים של ארגז החול לסוכנים באשכול (בדוגמה הזו נעשה שימוש בגרסה v0.4.6):
# Install the core agent-sandbox components
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v0.4.6/manifest.yaml
# Install the extensions (e.g., Warm Pools, Claims)
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v0.4.6/extensions.yaml
הגדרת האחסון וההרשאות
מגדירים קטגוריה ב-Cloud Storage לאחסון קובצי snapshot של 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לחשבון השירות באמצעות איחוד שירותי אימות הזהות של עומסי עבודה. התפקיד הזה מאפשר לעומס העבודה בארגז החול לפרט את התוכן של הקטגוריה ולאתר תמונות מצב ספציפיות:gcloud storage buckets add-iam-policy-binding "gs://${BUCKET_NAME}" \ --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.s3ns.svc.id.goog/subject/ns/default/sa/snapshot-sa" \ --role="roles/storage.bucketViewer"משייכים את התפקיד
storage.objectUserלחשבון השירות באמצעות Workload Identity. התפקיד הזה מספק הרשאה לקרוא, לשמור ולמחוק אובייקטים בינאריים של תמונת מצב בקטגוריה:gcloud storage buckets add-iam-policy-binding "gs://${BUCKET_NAME}" \ --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.s3ns.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.s3ns-system.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. המשאבים האלה מגדירים איך האשכול מאחסן ומנהל תמונות מצב של Pod:
- PodSnapshotStorageConfig: מציין את קטגוריית Cloud Storage שמיועדת לאחסון אובייקטים בינאריים של תמונת מצב.
- PodSnapshotPolicy: מגדיר איך מפעילים צילום תמונת מצב באופן ידני, באיזו תדירות הם מקובצים ומהי מדיניות שמירת הנתונים שלהם.
- 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 הזה, האפליקציה ב-Sandbox (סקריפט Python) מדפיסה באופן רציף מונה עולה ליומני הרישום של הקונטיינר:apiVersion: extensions.agents.x-k8s.io/v1alpha1 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
בניית אפליקציית הלקוח
יוצרים את קובץ אימג' של קונטיינר של אפליקציית הלקוח ומעלים אותו ל-Artifact Registry.
יוצרים קובץ בשם
Dockerfile.client. הקובץ הזה מגדיר את סביבת זמן הריצה של Python ואת יחסי התלות של אפליקציית הלקוח:FROM python:3.13-slim WORKDIR /app RUN pip install "k8s-agent-sandbox[tracing]==0.4.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_pod_name(sandbox_id, namespace): custom_api = client.CustomObjectsApi() try: sandbox_cr = custom_api.get_namespaced_custom_object( group="agents.x-k8s.io", version="v1alpha1", namespace=namespace, plural="sandboxes", name=sandbox_id ) metadata = sandbox_cr.get("metadata", {}) annotations = metadata.get("annotations", {}) return annotations.get("agents.x-k8s.io/pod-name") except Exception as e: logging.error(f"Failed to get sandbox CR: {e}") return None def get_current_count(sandbox_id, namespace="default"): pod_name = get_current_pod_name(sandbox_id, namespace) if not pod_name: logging.error(f"Could not determine pod name for sandbox {sandbox_id}") return None return get_last_count(pod_name, 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(template="python-counter-template", 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.sandbox_id) 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.sandbox_id) 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. אם בסביבה שלכם (למשל Cloud Shell) מותקן Docker, אתם יכולים להשתמש ב-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'מחליפים את ה-placeholders של משתני הסביבה בקובץ התצורה:
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:
gcloud storage buckets create "gs://${CLOUDBUILD_BUCKET_NAME}" \ --location="${BUCKET_LOCATION}"נותנים את ההרשאות הנדרשות לחשבון השירות ב-Cloud Build.
הפקודות הבאות משתמשות בחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine (
$PROJECT_NUMBER-compute@developer.s3ns-system.iam.gserviceaccount.com), שהוא ברירת המחדל ברוב הפרויקטים. אם הפרויקט שלכם משתמש בחשבון השירות מדור קודם של Cloud Build, מחליפים את כתובת האימייל של החבר בפקודות הבאות ב-$PROJECT_NUMBER@cloudbuild.s3ns-system.iam.gserviceaccount.com.מכיוון שהוספתם קישור IAM מותנה לפרויקט בשלב מוקדם יותר במדריך הזה, אתם צריכים לכלול את הדגל
--condition=Noneכשאתם מוסיפים את הקישורים החדשים האלה. כך לא תהיה הפסקה שלgcloudכדי לבקש אישור אינטראקטיבי:gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$PROJECT_NUMBER-compute@developer.s3ns-system.iam.gserviceaccount.com" \ --role="roles/artifactregistry.writer" gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$PROJECT_NUMBER-compute@developer.s3ns-system.iam.gserviceaccount.com" \ --role="roles/logging.logWriter" gcloud storage buckets add-iam-policy-binding "gs://$CLOUDBUILD_BUCKET_NAME" \ --member="serviceAccount:$PROJECT_NUMBER-compute@developer.s3ns-system.iam.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מחילים את מניפסט ה-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).
הפלט מראה שהארגז חול שומר על המצב שלו כשהוא מושהה ומופעל מחדש. המונה מפסיק להתקדם בזמן שהארגז חול מושהה (מושהה ומוקטן לאפס), וממשיך את הספירה כשהארגז חול משוחזר. בלי השהיה, המונה היה ממשיך להתקדם במהלך תקופת ההשהיה והספירה הייתה גבוהה משמעותית.
לפנות משאבים
כדי להימנע מחיובים בחשבון Cloud de Confiance by S3NS , מוחקים את המשאבים שיצרתם:
מוחקים את אשכול GKE. הפעולה הזו מוחקת גם את מאגר הצמתים ואת כל חשבונות השירות של Kubernetes בתוכו:
gcloud beta container clusters delete ${CLUSTER_NAME} --location="${LOCATION}" --quietכדי להסיר את מאגר Docker שיצרתם עבור תמונת הבדיקה, צריך למחוק את מאגר Artifact Registry:
gcloud artifacts repositories delete ${REPOSITORY_NAME} --location="${LOCATION}" --quietמחיקת קטגוריה של Cloud Storage וכל קובצי ה-snapshot שבתוכה. הפעולה הזו מסירה באופן אוטומטי את הקישורים של Workload Identity ל-IAM ברמת הקטגוריה שחלים עליה:
gcloud storage rm --recursive "gs://${BUCKET_NAME}"מסירים את קישור ה-IAM ברמת הפרויקט לסוכן השירות של GKE:
gcloud projects remove-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:service-${PROJECT_NUMBER}@container-engine-robot.s3ns-system.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 כדי ליצור את קובץ האימג' של הקונטיינר ולהעביר אותו בדחיפה, צריך למחוק את קטגוריית היומנים ולהסיר את ההרשאות של חשבון השירות:
gcloud storage rm --recursive "gs://${CLOUDBUILD_BUCKET_NAME}" gcloud projects remove-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$PROJECT_NUMBER-compute@developer.s3ns-system.iam.gserviceaccount.com" \ --role="roles/artifactregistry.writer" gcloud projects remove-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$PROJECT_NUMBER-compute@developer.s3ns-system.iam.gserviceaccount.com" \ --role="roles/logging.logWriter"
המאמרים הבאים
- איך מבודדים את הביצוע של קוד AI: טריגר חיצוני
- איך שומרים ומשחזרים סביבות ארגז חול של סוכנים
- כדי להבין את שכבות הבידוד שמגנות על עומסי העבודה הלא מהימנים, אפשר לעיין במאמר בנושא GKE Sandbox.
- אפשר לעיין בפרויקט Agent Sandbox בקוד פתוח ב-GitHub.
- איך משתמשים ב-Kata Containers עם Agent Sandbox Kata Containers הוא לא מוצר של Cloud de Confiance . אם תתקינו את התוכנה הזו ותשתמשו בה, תהיו אחראים לניהול ולפתרון בעיות. התמיכה של Google והסכמי רמת השירות שלה לא חלים על Kata Containers.