שמירה ושחזור של ארגז חול לסוכנים בסביבות GKE באמצעות תמונות מצב של Pod

במאמר הזה מוסבר איך משתמשים בתמונות מצב של Pod ב-GKE כדי לשמור את המצב של סביבת Agent Sandbox שפועלת ב-GKE.

Agent Sandbox ב-GKE משפר את האבטחה כי הוא מספק סביבה מבודדת להרצת קוד לא מהימן, כמו קוד שנוצר על ידי מודלים גדולים של שפה (LLM). הפעלת קוד מהסוג הזה ישירות באשכול כרוכה בסיכוני אבטחה, כי קוד לא מהימן עלול לגשת לאפליקציות אחרות או לצומת האשכול הבסיסי עצמו, או להפריע להם.

תמונות מצב של Pod ב-GKE מאפשרות לשמור ולשחזר את המצב של סביבות בארגז חול. הפונקציונליות הזו שימושית מהסיבות הבאות:

  • הפעלה מהירה: הפחתת זמן ההפעלה של ארגז החול על ידי שחזור מתמונת מצב שחוממה מראש.
  • סוכנים למשימות מתמשכות: השהיית ארגז חול שההרצה שלו נמשכת זמן רב והמשך ההרצה מאוחר יותר, או העברה שלו לצומת אחר, בלי לאבד את ההתקדמות.
  • עומסי עבודה עם שמירת מצב (stateful): שומרים את ההקשר של הסוכן, כמו היסטוריית השיחות או חישובי ביניים, על ידי שמירה ושחזור של המצב של סביבת ארגז החול שלו.
  • יכולת שחזור: תיעוד של מצב ספציפי ושימוש בו כבסיס להפעלת כמה ארגזי חול חדשים עם אותו מצב מאותחל.

יש שתי דרכים להפעיל תמונת מצב:

  • טריגר ידני: אתם יוצרים משאב PodSnapshotManualTrigger כדי להפעיל את ה-snapshot.
  • טריגר של עומס עבודה: האפליקציה בארגז החול מאותתת בעצמה כשהיא מוכנה לשמירה.

במאמר הזה מוסבר איך להפעיל ידנית תמונת מצב.

לפני שמתחילים

  1. בדף לבחירת הפרויקט במסוף Google Cloud , בוחרים פרויקט ב- Google Cloud או יוצרים אותו.

    התפקידים שנדרשים כדי לבחור או ליצור פרויקט

    • בחירת פרויקט: כדי לבחור פרויקט לא נדרש תפקיד IAM ספציפי – אתם יכולים לבחור כל פרויקט שקיבלתם בו תפקיד.
    • יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד "יצירת פרויקטים" (roles/resourcemanager.projectCreator), שכולל את ההרשאה resourcemanager.projects.create. איך מקצים תפקידים?

    כניסה לדף לבחירת הפרויקט

  2. מוודאים שהחיוב מופעל בפרויקט ב- Google Cloud .

  3. מפעילים את ממשקי ה-API של Google Kubernetes Engine,‏ Cloud Storage וניהול זהויות והרשאות גישה (IAM), אם הם עדיין לא מופעלים.

    התפקידים שנדרשים כדי להפעיל ממשקי API

    כדי להפעיל ממשקי API, צריך את ההרשאה serviceusage.services.enable. אם אתם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד "בעלים" (roles/owner). אחרת, אתם יכולים לקבל את ההרשאה הזו דרך התפקיד "אדמין בממשק 'שימוש בשירות'" (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים?

    הפעלת ממשקי ה-API

  4. מפעילים את Cloud Shell במסוף Google Cloud .

    הפעלת Cloud Shell

דרישות

כדי להשתמש בתמונות מצב של פודים ב-GKE, צריך את גרסה ‎1.35.3-gke.1234000 או גרסה חדשה יותר של GKE. יש תמיכה גם במצב Autopilot וגם במצב רגיל.

כדי ליצור קובצי snapshot של Pod צריך להשתמש ב-gVisor, והם לא פועלים עם ארגזי חול של microVM.

מכיוון שתמונות מצב של Pod דורשות את GKE Sandbox, הסביבה שלכם כפופה למגבלות מסוימות. לדוגמה, אי אפשר להשתמש בסוגי מכונות E2 עם קובצי snapshot של Pod. לכן, במדריך הזה יוצרים מאגר צמתים שמורכב ממכונות N2.

רשימה מלאה של ההגבלות, כולל מידע על שימוש בסוגי מכונות שמבוססות על GPU, מופיעה במאמר מגבלות ודרישות.

הגדרה של משתני סביבה

כדי לפשט את הפקודות שאתם מריצים במסמך הזה, אתם יכולים להגדיר משתני סביבה ב-Cloud Shell. המשתנים האלה מאחסנים ערכים כמו מזהה הפרויקט ב- Google Cloud , שם קטגוריה של Cloud Storage שבה יאוחסנו קובצי ה-snapshot והמיקום של אשכול GKE.

אחרי שמגדירים את המשתנים האלה, אפשר להשתמש בהם שוב בכמה פקודות על ידי הפניה לשם המשתנה (לדוגמה, $CLUSTER_NAME) במקום להקליד מחדש או להחליף ערכים בכל פעם. כך קל יותר לעקוב אחרי התהליך ופוחת הסיכון לטעויות.

כדי להגדיר את משתני הסביבה השימושיים הבאים ב-Cloud Shell, מריצים את הפקודות הבאות:

export PROJECT_ID=$(gcloud config get project)
export CLUSTER_NAME="agent-sandbox-cluster"
export GKE_LOCATION="us-central1"
export ZONE="us-central1-a"
export AGENT_SANDBOX_VERSION="v1.0.6"
export NODE_POOL_NAME="agent-sandbox-node-pool"
export MACHINE_TYPE="n2-standard-2"
export SNAPSHOTS_BUCKET_NAME="agent-sandbox-snapshots-${PROJECT_ID}"
export SNAPSHOT_NAMESPACE="pod-snapshots-ns"
export SNAPSHOT_KSA_NAME="pod-snapshot-sa"
export SNAPSHOT_FOLDER="my-snapshots"
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")

הנה הסבר על משתני הסביבה האלה:

  • ‫PROJECT_ID: מזהה הפרויקט הנוכחי ב- Google Cloud . הפקודות במסמך הזה משתמשות במזהה הזה כדי לתת שמות למשאבים ולהעניק הרשאות IAM.
  • ‫CLUSTER_NAME: השם של אשכול GKE (לדוגמה, agent-sandbox-cluster).
  • ‫GKE_LOCATION: האזור של הקטגוריה של Cloud Storage (לדוגמה, us-central1). אם יוצרים אשכול Autopilot, גם האשכול משתמש באזור הזה. Google Cloud
  • ‫ZONE: האזור של אשכול GKE. אם יוצרים אשכול Standard, מגדירים אותו לאזור ב-GKE_LOCATION (לדוגמה, us-central1-a). כדי להפחית את העלויות, במסמך הזה יוצרים אשכול Standard אזורי.
  • ‫AGENT_SANDBOX_VERSION: גרסת הבקר של Agent Sandbox בקוד פתוח שרוצים להתקין. במסמך הזה אנחנו משתמשים בגרסה 1.0.6.
  • ‫NODE_POOL_NAME: השם של מאגר הצמתים שיריץ עומסי עבודה בארגז חול (לדוגמה, agent-sandbox-node-pool).
  • ‫MACHINE_TYPE: סוג המכונה של הצמתים במאגר הצמתים (לדוגמה, n2-standard-2). קובצי Snapshot של Pod לא תומכים בסוגי מכונות E2. אם אתם רוצים להשתמש בסוגי מכונות שמבוססים על GPU בשביל הצמתים במאגר הצמתים, קראו את המאמר מגבלות ודרישות. למידע נוסף על סדרות שונות של מכונות ועל בחירה בין אפשרויות שונות, קראו את המדריך להשוואה בין משפחות של מכונות ומשאבים.
  • ‫SNAPSHOTS_BUCKET_NAME: השם של הקטגוריה של Cloud Storage שתיצרו כדי לאחסן את קובצי ה-snapshot.
  • ‫SNAPSHOT_NAMESPACE: מרחב השמות של Kubernetes שבו נמצאים עומס העבודה של קובץ ה-snapshot וחשבון השירות.
  • ‫SNAPSHOT_KSA_NAME: השם של חשבון השירות ב-Kubernetes שעומס העבודה ישתמש בו לאימות.
  • ‫SNAPSHOT_FOLDER: הספרייה בתוך הקטגוריה של Cloud Storage שבה יאורגנו קובצי ה-snapshot.
  • ‫PROJECT_NUMBER: המזהה המספרי הייחודי של הפרויקט, שמשמש לקישורי הרשאות IAM.

סקירה כללית של שלבי ההגדרה

כדי להפעיל תמונות מצב של Pods ב-Agent Sandbox בסביבות GKE, צריך לבצע כמה שלבי הגדרה. כדי להבין את השלבים האלה, כדאי קודם להבין כמה מושגי מפתח ואז את תהליך יצירת קובץ snapshot:

מושגים מרכזיים

  • סביבה: אפליקציה בארגז חול פועלת בתוך Pod של Kubernetes בצומת של אשכול GKE.
  • זהות: ה-Pod משויך לחשבון שירות של Kubernetes ופועל במרחב שמות מיוחד שאתם יוצרים. ביחד, חשבון השירות של Kubernetes והמרחב השמות יוצרים זהות ייחודית שמשמשת כדי לתת ל-Pod גישה מאובטחת למשאבים של Google Cloud .
  • הרשאות: כדי לאפשר שמירת קובצי snapshot ב-Cloud Storage, צריך לתת לזהות של ה-Pod הרשאות IAM ספציפיות שמאפשרות לו לכתוב בקטגוריה של Cloud Storage.

תהליך יצירת תמונת המצב

  1. טריגר: הפעלה של קובץ snapshot, באופן ידני (חיצוני) או על ידי עומס העבודה בארגז החול עצמו. במאמר הזה מוסבר איך להפעיל טריגר ידני באמצעות יצירת משאב PodSnapshotManualTrigger.
  2. תיעוד: GKE מתעד את מצב ההפעלה של ה-Pod, כמו מצב הזיכרון של ה-Pod ומערכת הקבצים שלו.
  3. העלאה: באמצעות ההרשאות שניתנו לחשבון השירות של Kubernetes ב-Pod, ‏GKE מעלה את המצב שצולם כקובצי תמונת מצב לקטגוריה הייעודית של Cloud Storage.

במאמר אימות ל-Google Cloud APIs מעומסי עבודה ב-GKE מוסבר איך משתמשים ב-GKE בחשבונות שירות של Kubernetes ובתפקידי IAM כדי לגשת למשאבים ב- Google Cloud .

כדי להפעיל תמונות מצב של Pod ב-Agent Sandbox בסביבות GKE, מבצעים את ההגדרה הבאה. קודם מכינים סביבת אשכול על ידי יצירת אשכול GKE עם התכונות "איחוד זהויות של עומסי עבודה ל-GKE" ו"תמונות מצב של Pod". בשלב הבא מגדירים את כללי המדיניות של Cloud Storage ו-IAM כדי לוודא שהתמונות של המצב הנוכחי מאוחסנות בצורה מאובטחת, ושלסביבת ה-Sandbox יש את ההרשאות הנדרשות. לבסוף, יוצרים את משאבי הסנאפשוט שמציינים את מיקום האחסון ואת כללי המדיניות של ארגז החול.

בטבלה הבאה מפורטים שלבי ההגדרה שצריך לבצע, וכל שלב מוסבר בקטעים שאחריה:

נושא משימה
הגדרת אשכול 1. יוצרים אשכול GKE ומפעילים את התכונות "תמונות מצב של Pod" ו"איחוד זהויות של עומסי עבודה ל-GKE".
‫2. פורסים את Agent Sandbox.
הגדרת אחסון והרשאות 1. יוצרים את הקטגוריה של Cloud Storage ואת התיקייה המנוהלת.
‫2. יוצרים את תפקיד ה-IAM בהתאמה אישית.
‫3. יוצרים את מרחב השמות של Kubernetes ואת חשבון השירות של Kubernetes‏ (KSA).
‫4. מקשרים את התפקיד ב-IAM לחשבון השירות ב-Kubernetes.
‫5. נותנים הרשאות לבקר של קובץ ה-snapshot.
הגדרת משאבי קובץ snapshot 1. יצירת משאב של PodSnapshotStorageConfig
‫2. יצירת משאב PodSnapshotPolicy
‫3. יצירת משאבים מסוג SandboxTemplate,‏ SandboxWarmPool ו-SandboxClaim

הגדרת האשכול

אפליקציה בארגז חול פועלת בתוך Pod בצומת של אשכול GKE, ולכן צריך להגדיר סביבת אשכול. בקטע הזה מוסבר איך ליצור אשכול GKE ולפרוס את הבקר של Agent Sandbox.

יצירת אשכול GKE חדש שעומד בדרישות

יוצרים אשכול GKE חדש עם תמונות מצב של Pods. כדי להשתמש בתמונות מצב של Pod, צריך את גרסה 1.35.3-gke.1234000 או גרסה חדשה יותר של GKE. הפקודות הבאות רושמות את האשכול לערוץ ההפצה המהירה, שגרסת ברירת המחדל שלו עומדת בדרישה הזו:

טייס אוטומטי

יוצרים אשכול Autopilot עם התכונות הנדרשות:

gcloud container clusters create-auto ${CLUSTER_NAME} \
   --release-channel=rapid \
   --enable-pod-snapshots \
   --location=${GKE_LOCATION}

רגילה

יוצרים אשכול Standard עם התכונות הנדרשות. כדי להפחית את העלויות, הפקודה הבאה יוצרת אשכול אזורי שמריץ את מישור הבקרה והצמתים שלו באזור אחד:

gcloud container clusters create ${CLUSTER_NAME} \
   --release-channel=rapid \
   --enable-pod-snapshots \
   --machine-type=${MACHINE_TYPE} \
   --workload-pool=${PROJECT_ID}.svc.id.goog \
   --workload-metadata=GKE_METADATA \
   --num-nodes=1 \
   --location=${ZONE}

יוצרים מאגר צמתים שבו GKE Sandbox מופעל. ‫GKE Sandbox הוא אמצעי אבטחה לקונטיינרים שמבוסס על פרויקט gVisor בקוד פתוח, שמוסיף שכבת בידוד בין האפליקציות שפועלות לבין מערכת ההפעלה המארחת:

gcloud container node-pools create ${NODE_POOL_NAME} \
   --cluster ${CLUSTER_NAME} \
   --num-nodes=1 \
   --location=${ZONE} \
   --project=${PROJECT_ID} \
   --machine-type=${MACHINE_TYPE} \
   --sandbox type=gvisor

אחזור פרטי הכניסה

מאחזרים את פרטי הכניסה של האשכול כדי שממשק ה-CLI של kubectl יוכל להתחבר לאשכול:

טייס אוטומטי

gcloud container clusters get-credentials ${CLUSTER_NAME} \
    --location=${GKE_LOCATION}

רגילה

gcloud container clusters get-credentials ${CLUSTER_NAME} \
    --location=${ZONE}

פריסת Agent Sandbox Controller באשכול

כדי לפרוס את הבקר של Agent Sandbox ואת הרכיבים הנדרשים שלו, צריך להחיל את המניפסט של הגרסה הרשמית על האשכול. המניפסט הזה הוא קובץ תצורה שמורה ל-Kubernetes להוריד את כל הרכיבים שנדרשים כדי לפרוס ולהריץ את בקר Agent Sandbox באשכול.

כדי לפרוס את Agent Sandbox באשכול GKE, מריצים את הפקודה הבאה:

# Apply the release manifest for the controller and its CustomResourceDefinitions
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/sandbox-with-extensions.yaml

איך מתקינים את Agent Sandbox ב-GKE

אימות הבקר

אחרי שמחילים את המניפסט, בודקים ש-Pod של בקר Agent Sandbox פועל כמו שצריך במרחב השמות agent-sandbox-system. המניפסט יצר באופן אוטומטי את מרחב השמות agent-sandbox-system כשהחלתם אותו בשלב הקודם.

kubectl get pods -n agent-sandbox-system

ממתינים עד שבעמודה STATUS של ה-Pod יופיע הערך Running ובעמודה READY יופיע הערך 1/1. כשה-Pod פועל בצורה תקינה, הפלט נראה בערך כך:

NAME                                        READY   STATUS    RESTARTS   AGE
agent-sandbox-controller-7d5c9b8f6d-x2k9p   1/1     Running   0          2m

עכשיו, כשהבקר של Agent Sandbox פועל, הוא יכול ליצור ולנהל באופן אוטומטי סביבות של ארגז חול לכל משאבי Sandbox שאתם יוצרים באשכול.

הגדרת האחסון וההרשאות

בקטע הזה מוסבר איך להגדיר את האחסון וההרשאות שנדרשים לתמונות מצב של Pod. יוצרים קטגוריה של Cloud Storage ותיקייה מנוהלת כדי לאחסן את נתוני קובץ ה-snapshot. לאחר מכן, נותנים לארגז החול ולבקר של קובץ ה-snapshot את ההרשאות שנדרשות כדי לגשת לאחסון הזה.

יצירת קטגוריה של Cloud Storage

יוצרים קטגוריה לאחסון קובצי ה-snapshot. כדי שתהליך יצירת קובץ ה-snapshot יהיה מהיר וחסכוני, צריך ליצור את הקטגוריה עם ההגדרות הבאות:

  • הפעלת מרחבי שמות היררכיים: התכונה "מרחבי שמות היררכיים" מארגנת את הקטגוריה בהיררכיה של מערכת קבצים, במקום במרחב שמות שטוח. ההגדרה הזו מאפשרת קצב העברת נתונים גבוה יותר בקריאה ובכתיבה, וכתוצאה מכך מאיצה את השמירה והשחזור של קובצי snapshot.
  • השבתת המחיקה הרכה: התכונה "מחיקה רכה" מגינה על הנתונים על ידי שמירת הקבצים שנמחקו למשך פרק זמן מוגדר. עם זאת, בתהליך של יצירת קובץ snapshot נוצרים ונמחקים הרבה קבצים זמניים במהלך ההעלאה. כדי להימנע מחיובים מיותרים על אחסון הקבצים הזמניים האלה, כדאי להשבית את המחיקה הרכה.

כדי ליצור את הקטגוריה עם ההגדרות האלה, מריצים את הפקודה הבאה:

gcloud storage buckets create "gs://${SNAPSHOTS_BUCKET_NAME}" \
    --uniform-bucket-level-access \
    --enable-hierarchical-namespace \
    --soft-delete-duration=0d \
    --location="${GKE_LOCATION}"

יצירת תיקייה מנוהלת

יוצרים תיקייה מנוהלת כדי לארגן את קובצי ה-snapshot בקטגוריה. תיקיות מנוהלות מאפשרות להחיל הרשאות IAM על תיקייה ספציפית, במקום על הקטגוריה כולה. הגישה ברמת התיקייה מגבילה את הגישה של ארגז החול רק לתמונות המצב שלו, ומבודדת את תמונות המצב האלה מנתונים אחרים בקטגוריה.

כדי ליצור תיקייה מנוהלת, מריצים את הפקודה הבאה:

gcloud storage managed-folders create "gs://${SNAPSHOTS_BUCKET_NAME}/${SNAPSHOT_FOLDER}/"

הגדרת חשבון השירות ותפקידי IAM

כדי לאפשר ל-GKE לשמור תמונות מצב באופן מאובטח, חשבון השירות של Kubernetes שמשמש את ה-Pods שמריצים את עומס העבודה בארגז החול צריך הרשאה לכתוב בקטגוריה. כדי לתת את ההרשאה הזו, צריך לקשר תפקידי IAM ב- Google Cloudלחשבון השירות ב-Kubernetes שמשמש את ה-Pods. בקטע הזה מוסבר איך ליצור תפקיד IAM בהתאמה אישית, ליצור את חשבון השירות של Kubernetes ולהגדיר את ההרשאות הנדרשות.

  1. יוצרים תפקיד IAM בהתאמה אישית בשם podSnapshotGcsReadWriter, שכולל את ההרשאות שנדרשות כדי לכתוב נתוני תמונת מצב. אם התפקיד הזה כבר קיים בפרויקט, למשל מהפעלה קודמת של המסמך הזה, דלגו על השלב הזה. אחרת, מריצים את הפקודה הבאה:

    gcloud iam roles create podSnapshotGcsReadWriter \
        --project="${PROJECT_ID}" \
        --permissions="storage.objects.get,storage.objects.create,storage.objects.delete,storage.folders.create"
    

    אם התפקיד נוצר, הפלט אמור להיראות כך:

    Created role [podSnapshotGcsReadWriter].
    etag: BwZJUfjNbew=
    includedPermissions:
    - storage.folders.create
    - storage.objects.create
    - storage.objects.delete
    - storage.objects.get
    name: projects/${PROJECT_ID}/roles/podSnapshotGcsReadWriter
    stage: ALPHA
    title: podSnapshotGcsReadWriter
    

    אם הפקודה נכשלת עם שגיאת FAILED_PRECONDITION שאומרת שמזהה התפקיד סומן למחיקה, סימן שמחקתם לאחרונה תפקיד עם המזהה הזה, למשל בשלבי הניקוי של הרצה קודמת של המסמך הזה. ב-IAM אי אפשר להשתמש שוב במזהה הזה במשך עד 37 ימים. מריצים שוב את הפקודה עם מזהה תפקיד אחר, כמו podSnapshotGcsReadWriter2, ומשתמשים במזהה הזה במקום podSnapshotGcsReadWriter בשאר המסמך.

  2. יוצרים את מרחב השמות שבו יימצאו ארגז החול וחשבון השירות שלו:

    kubectl create namespace "${SNAPSHOT_NAMESPACE}"
    
  3. יוצרים את חשבון השירות של Kubernetes במרחב השמות שיצרתם. ביחד, חשבון השירות של Kubernetes ומרחב השמות יוצרים זהות ייחודית שמשמשת כדי לתת לארגז החול גישה מאובטחת למשאבים ב- Google Cloud:

    kubectl create serviceaccount "${SNAPSHOT_KSA_NAME}" \
        --namespace "${SNAPSHOT_NAMESPACE}"
    
  4. מקצים את התפקיד roles/storage.bucketViewer לכל חשבונות השירות במרחב השמות. התפקיד הזה מאפשר לחשבונות לראות את המטא-נתונים של הקטגוריה, אבל לא לקרוא או לכתוב את הנתונים עצמם:

    gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
        --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/namespace/${SNAPSHOT_NAMESPACE}" \
        --role="roles/storage.bucketViewer"
    
  5. מקצים את התפקיד podSnapshotGcsReadWriter בהתאמה אישית לחשבון השירות של Kubernetes בארגז החול. הקישור הזה מאפשר רק לחשבון הספציפי הזה לכתוב נתונים בתיקייה המנוהלת. יכול להיות שיעברו כמה דקות עד שהתפקיד החדש בהתאמה אישית יהיה זמין. אם הפקודה נכשלת כי התפקיד לא קיים, המתינו דקה והריצו שוב את הפקודה:

    gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
        --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/${SNAPSHOT_NAMESPACE}/sa/${SNAPSHOT_KSA_NAME}" \
        --role="projects/${PROJECT_ID}/roles/podSnapshotGcsReadWriter"
    
  6. מקצים לחשבון השירות ב-Kubernetes את התפקיד roles/storage.objectUser. התפקיד הזה נדרש כדי שסוכן תמונת המצב של Pod יוכל לבצע פעולות בתיקיות מנוהלות:

    gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
        --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/${SNAPSHOT_NAMESPACE}/sa/${SNAPSHOT_KSA_NAME}" \
        --role="roles/storage.objectUser"
    

מתן הרשאות לבקר של תמונת המצב

מקצים את התפקיד objectUser לבקר של תמונת המצב של מערכת GKE. ההרשאה הזו מאפשרת לבקר לנהל את מחזור החיים של קובץ ה-snapshot, למשל למחוק אובייקטים של קובץ ה-snapshot כשמוחקים משאב PodSnapshot:

gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
    --member="serviceAccount:service-${PROJECT_NUMBER}@container-engine-robot.iam.gserviceaccount.com" \
    --role="roles/storage.objectUser"

הגדרת משאבים של תמונות מצב

בקטע הזה מוסבר איך להגדיר את משאבי הסנאפשוט של Agent Sandbox בעומס העבודה ב-GKE.

הגדרת אחסון וכללים לתמונות המצב

כדי לציין איפה GKE שומר את קובצי ה-snapshot ואילו כללים חלים על תהליך ה-snapshot, צריך ליצור שני משאבים בהתאמה אישית:

  • ‫PodSnapshotStorageConfig: המשאב הזה מציין את המיקום של הקטגוריה והתיקייה ב-Cloud Storage שבהם GKE שומר את קובצי הסנאפשוט.
  • ‫PodSnapshotPolicy: המשאב הזה מגדיר אילו Pods מתאימים לתמונות מצב, על סמך התוויות שלהם ב-Kubernetes. היא גם מציינת את כללי הטריגר, למשל אם תמונות המצב הן ידניות או שהן נוצרות על ידי עומס העבודה בארגז החול. בדוגמה הזו, קובצי ה-snapshot מקובצים לפי התווית agents.x-k8s.io/sandbox-name-hash, שהבקר של Agent Sandbox מוסיף ל-Pod של כל ארגז חול. הקיבוץ הזה אומר ש-GKE משחזר כל ארגז חול רק מהתמונות שלו.

כדי להחיל את שני המשאבים בשלב אחד, מריצים את הפקודה הבאה ב-Cloud Shell. השיטה הזו עוזרת לוודא שמשתני הסביבה מוזרקים בצורה נכונה:

kubectl apply -f - <<EOF
apiVersion: podsnapshot.gke.io/v1
kind: PodSnapshotStorageConfig
metadata:
  name: cpu-pssc-gcs
spec:
  snapshotStorageConfig:
    gcs:
      bucket: "${SNAPSHOTS_BUCKET_NAME}"
      path: "${SNAPSHOT_FOLDER}"
EOF

sleep 5

kubectl apply -f - <<EOF
apiVersion: podsnapshot.gke.io/v1
kind: PodSnapshotPolicy
metadata:
  name: cpu-psp
  namespace: ${SNAPSHOT_NAMESPACE}
spec:
  storageConfigName: cpu-pssc-gcs
  selector:
    matchLabels:
      app: agent-sandbox-workload
  triggerConfig:
    type: manual
    postCheckpoint: resume
  snapshotGroupingRules:
    groupByLabelValue:
      labels:
      - agents.x-k8s.io/sandbox-name-hash
EOF

אימות ההגדרות האישיות

אחרי שמחילים את המדיניות וההגדרות של אחסון קובצי ה-snapshot, מוודאים שהמשאבים מוכנים לשימוש. בקטע הזה מוסבר איך לבדוק את הסטטוס של המשאבים האלה בהתאמה אישית.

  1. בודקים את הסטטוס של המשאב PodSnapshotStorageConfig:

    kubectl get podsnapshotstorageconfigs.podsnapshot.gke.io cpu-pssc-gcs -o yaml
    

    הפלט אמור להכיל תנאי עם type: Ready ו-status: "True":

    status:
      conditions:
      - lastTransitionTime: "2025-10-31T18:18:02Z"
        message: Valid PodSnapshotStorageConfig
        reason: StorageConfigValid
        status: "True"
        type: Ready
    
  2. בודקים את הסטטוס של המשאב PodSnapshotPolicy:

    kubectl get podsnapshotpolicies.podsnapshot.gke.io cpu-psp \
      --namespace "${SNAPSHOT_NAMESPACE}" -o yaml
    

    הפלט צריך לכלול תנאי עם type: Ready ו-status: "True". הוא גם אמור לציין שהמשאב PodSnapshotStorageConfig שאליו מפנים נמצא:

    status:
      conditions:
      - lastTransitionTime: "2025-10-31T18:19:47Z"
        message: The referenced PodSnapshotStorageConfig "cpu-pssc-gcs" was found
        reason: StorageConfigValid
        status: "True"
        type: Ready
    

יצירת התבנית של ארגז החול

אחרי שהגדרתם את כללי המדיניות וההרשאות של האחסון, אתם יכולים ליצור את המשאבים SandboxTemplate,‏ SandboxWarmPool ו-SandboxClaim. המשאב SandboxWarmPool שומר על ארגז חול (sandbox) פעיל, והמשאב SandboxClaim תובע את ארגז החול הזה מהמאגר. כדי שתהליך יצירת קובץ ה-snapshot יפעל, צריך להריץ את ארגז החול עם חשבון השירות של Kubernetes שיצרתם קודם לכן במסמך הזה. בארגז החול צריכות להיות גם התוויות שציינתם קודם במשאב PodSnapshotPolicy.

בדוגמה הזו משתמשים באפליקציית Python שמדפיסה מונה מצטבר ביומנים. המונה הזה מאפשר לכם לוודא שהמצב נשמר בהצלחה ומשוחזר מאוחר יותר.

טייס אוטומטי

אי אפשר להשתמש בתמונות מצב של Pod במכונות מסוג E2. במצב Autopilot, יכול להיות ש-GKE יבחר כברירת מחדל סוגי מכונות שלא תומכים בתמונות מצב של Pod. כדי לוודא שעומסי העבודה פועלים בחומרה תואמת, כדאי להשתמש ב-ComputeClass בהתאמה אישית כדי לתת עדיפות למשפחות מכונות תואמות.

  1. שומרים את המניפסט הבא בתור non-e2-class.yaml:

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: non-e2-class
    spec:
      priorities:
      - machineFamily: n2
      - machineFamily: c3
      activeMigration:
        optimizeRulePriority: false
      whenUnsatisfiable: DoNotScaleUp
    
  2. מחילים את המניפסט:

    kubectl apply -f non-e2-class.yaml
    
  3. כדי ליצור את המשאבים SandboxTemplate ו-SandboxWarmPool, צריך להחיל את המניפסט הבא. שימו לב שהמשאב SandboxTemplate מתייחס ל-ComputeClass שיצרתם באמצעות בורר הצמתים cloud.google.com/compute-class: non-e2-class.

    kubectl apply -f - <<EOF
    ---
    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxTemplate
    metadata:
      name: python-runtime-template
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      podTemplate:
        metadata:
          labels:
            app: agent-sandbox-workload
        spec:
          serviceAccountName: ${SNAPSHOT_KSA_NAME}
          runtimeClassName: gvisor
          nodeSelector:
            cloud.google.com/compute-class: non-e2-class
          containers:
          - name: my-container
            image: python:3.10-slim
            command: ["python3", "-c"]
            args:
              - |
                import time
                i = 0
                while True:
                  print(f"Count: {i}", flush=True)
                  i += 1
                  time.sleep(1)
    ---
    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxWarmPool
    metadata:
      name: python-sandbox-warmpool
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      replicas: 1
      sandboxTemplateRef:
        name: python-runtime-template
    EOF
    

רגילה

כדי ליצור את המשאבים SandboxTemplate ו-SandboxWarmPool, מפעילים את המניפסט הבא:

kubectl apply -f - <<EOF
---
apiVersion: extensions.agents.x-k8s.io/v1beta1
kind: SandboxTemplate
metadata:
  name: python-runtime-template
  namespace: ${SNAPSHOT_NAMESPACE}
spec:
  podTemplate:
    metadata:
      labels:
        app: agent-sandbox-workload
    spec:
      serviceAccountName: ${SNAPSHOT_KSA_NAME}
      runtimeClassName: gvisor
      containers:
      - name: my-container
        image: python:3.10-slim
        command: ["python3", "-c"]
        args:
          - |
            import time
            i = 0
            while True:
              print(f"Count: {i}", flush=True)
              i += 1
              time.sleep(1)
---
apiVersion: extensions.agents.x-k8s.io/v1beta1
kind: SandboxWarmPool
metadata:
  name: python-sandbox-warmpool
  namespace: ${SNAPSHOT_NAMESPACE}
spec:
  replicas: 1
  sandboxTemplateRef:
    name: python-runtime-template
EOF

אחרי שיוצרים את המשאבים, תובעים בעלות על ארגז חול מהמאגר החם:

  1. מחכים עד שארגז החול של המאגר החם יהיה מוכן:

    kubectl wait sandboxwarmpool python-sandbox-warmpool \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=jsonpath='{.status.readyReplicas}'=1 \
      --timeout=600s
    
  2. יוצרים משאב SandboxClaim שתובע את ארגז החול מהמאגר החם:

    kubectl apply -f - <<EOF
    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxClaim
    metadata:
      name: python-sandbox-example
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      warmPoolRef:
        name: python-sandbox-warmpool
    EOF
    
  3. מחכים עד שהתביעה מוכנה, ואז שומרים את שם ארגז החול שבו התביעה משתמשת. ה-Pod של ארגז החול נקרא באותו שם כמו ארגז החול:

    kubectl wait sandboxclaim python-sandbox-example \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=condition=Ready \
      --timeout=300s
    
    export SANDBOX_NAME=$(kubectl get sandboxclaim python-sandbox-example \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      -o jsonpath='{.status.sandbox.name}')
    echo "${SANDBOX_NAME}"
    

עכשיו ארגז החול פועל עם הזהות הנכונה ומוכן ליצירת קובץ snapshot.

יצירת תמונת מצב

בקטע הזה מוסבר איך להפעיל באופן ידני קובץ snapshot של ארגז החול שפועל. אתם יוצרים משאב טריגר שמטרגט את ה-Pod של ארגז החול, ואז מוודאים שתהליך יצירת קובץ ה-snapshot הושלם בהצלחה.

  1. בדיקת היומנים הראשוניים של המונה: לפני שמפעילים את קובץ ה-snapshot, בודקים את היומנים של ארגז החול שפועל כדי לראות את הערך הנוכחי של המונה. הצגת היומנים יוצרת בסיס להשוואה אחרי השחזור.

    kubectl logs "${SANDBOX_NAME}" --namespace "${SNAPSHOT_NAMESPACE}" --tail=5
    

    בפלט מוצגות השורות האחרונות של המונה, לדוגמה:

    Count: 15
    Count: 16
    Count: 17
    

    שימו לב לערכי ה-Count האחרונים שהודפסו.

  2. יצירת משאב PodSnapshotManualTrigger: הפעלת קובץ ה-snapshot:

    kubectl apply -f - <<EOF
    apiVersion: podsnapshot.gke.io/v1
    kind: PodSnapshotManualTrigger
    metadata:
      name: cpu-snapshot-trigger
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      targetPod: ${SANDBOX_NAME}
    EOF
    
  3. מוודאים שההפעלה הידנית הצליחה:

    kubectl get podsnapshotmanualtriggers.podsnapshot.gke.io \
      --namespace "${SNAPSHOT_NAMESPACE}"
    

    הפלט אמור להציג את הסטטוס Complete, שמציין ש-GKE הפעיל בהצלחה את קובץ ה-snapshot של ה-Pod המטורגט:

    NAME                   TARGET POD                      STATUS     AGE
    cpu-snapshot-trigger   python-sandbox-warmpool-x7k2p   Complete   XXs
    
  4. כדי לקבל פרטים נוספים על המצב שצולם, מתארים את הטריגר:

    kubectl describe podsnapshotmanualtriggers.podsnapshot.gke.io cpu-snapshot-trigger \
      --namespace "${SNAPSHOT_NAMESPACE}"
    

    הפלט מכיל קטע Snapshot Created עם השם הייחודי של קובצי תמונת המצב שמאוחסנים בקטגוריה:

    Status:
      Conditions:
        Last Transition Time:  2026-01-30T19:11:04Z
        Message:               checkpoint completed successfully
        Reason:                Complete
        Status:                True
        Type:                  Triggered
      Observed Generation:     1
      Snapshot Created:
        Name:  <UNIQUE_SNAPSHOT_NAME>
    

שחזור מתמונת מצב

אחרי שיוצרים קובץ Snapshot, אפשר להשעות את ארגז החול כדי לפנות את משאבי המחשוב שלו, ואחר כך להמשיך את ארגז החול מהמצב השמור שלו. כשמשעים ארגז חול, הבקר של Agent Sandbox מוחק את ה-Pod של ארגז החול אבל שומר את המשאב Sandbox. כשממשיכים את ארגז החול, הבקר יוצר מחדש את ה-Pod, ובקר תמונת המצב של ה-Pod משחזר באופן אוטומטי את ה-Pod מתמונת המצב האחרונה של ארגז החול הזה.

  1. מחכים עד שתמונת המצב מוכנה. ‫GKE משחזר Pod רק מ-snapshot שמוכן. אם תשעו את ארגז החול לפני שהתמונה תהיה מוכנה, ארגז החול יתחיל בלי המצב השמור כשתפעילו אותו מחדש.

    export SNAPSHOT_NAME=$(kubectl get podsnapshotmanualtriggers.podsnapshot.gke.io cpu-snapshot-trigger \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      -o jsonpath='{.status.snapshotCreated.name}')
    
    kubectl wait podsnapshots.podsnapshot.gke.io "${SNAPSHOT_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=condition=Ready \
      --timeout=600s
    
  2. כדי להשעות את ארגז החול, מגדירים את השדה operatingMode שלו לערך Suspended, ואז מחכים עד שהבקר ימחק את ה-Pod של ארגז החול:

    kubectl patch sandbox "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --type=merge \
      -p '{"spec":{"operatingMode":"Suspended"}}'
    
    kubectl wait pod "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=delete \
      --timeout=120s
    
  3. כדי להמשיך את ארגז החול, מגדירים את השדה operatingMode שלו ל-Running, ואז ממתינים עד שארגז החול יהיה מוכן:

    kubectl patch sandbox "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --type=merge \
      -p '{"spec":{"operatingMode":"Running"}}'
    
    kubectl wait sandbox "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=condition=Ready \
      --timeout=300s
    
  4. כדי לוודא שהשחזור בוצע, בודקים את היומנים. שימו לב שהמונה ממשיך מהנקודה שבה נוצר קובץ ה-snapshot:

    kubectl logs "${SANDBOX_NAME}" --namespace "${SNAPSHOT_NAMESPACE}"
    

    בפלט אמור להופיע המונה שממשיך לפעול, לדוגמה:

    Count: 18
    Count: 19
    Count: 20
    Count: 21
    

    אם המונה מתחיל מ-0, ה-Pod התחיל בלי לשחזר מתמונת המצב.

מחיקת משאבים

כדי להימנע מצבירת חיובים בחשבון Google Cloud על המשאבים שבהם השתמשתם במסמך הזה, מחקו את המשאבים שיצרתם באמצעות הפעולות הבאות:

  1. מוחקים את בקשות ה-sandbox ואת המאגרים החמים כדי להפסיק את כל ה-Pods שפועלים, ולאפשר לבקר של Agent Sandbox לסגור את הקונטיינרים בצורה תקינה.

    kubectl delete sandboxclaims --all --namespace "${SNAPSHOT_NAMESPACE}"
    kubectl delete sandboxwarmpools --all --namespace "${SNAPSHOT_NAMESPACE}"
    
  2. מוחקים את התבניות של ארגזי החול ואת הטריגרים הידניים ששימשו ליצירת ארגזי החול ולהפעלת תמונות המצב.

    # Delete the blueprints
    kubectl delete sandboxtemplates --all --namespace "${SNAPSHOT_NAMESPACE}"
    
    # Delete the snapshot initiation objects
    kubectl delete podsnapshotmanualtriggers --all --namespace "${SNAPSHOT_NAMESPACE}"
    
  3. מוחקים את כללי המדיניות של קובצי ה-Snapshot שמגדירים אילו Pods מתאימים לקובצי Snapshot במרחב השמות.

    kubectl delete podsnapshotpolicy cpu-psp --namespace "${SNAPSHOT_NAMESPACE}"
    
  4. מוחקים את הגדרת האחסון של קובץ ה-snapshot, שהיא ההגדרה הגלובלית של הקצה העורפי של אחסון קובץ ה-snapshot. מכיוון שהמשאב הזה מוגדר ברמת האשכול, אל תשתמשו בדגל של מרחב שמות.

    kubectl delete podsnapshotstorageconfig cpu-pssc-gcs
    
  5. אם יצרתם אחד ל-Autopilot, מחקו את ComputeClass.

    kubectl delete computeclass non-e2-class
    
  6. מוחקים את מרחב השמות של Kubernetes כדי להסיר באופן אוטומטי את חשבון השירות של Kubernetes ואת כל המטא-נתונים שנותרו במרחב השמות.

    kubectl delete namespace "${SNAPSHOT_NAMESPACE}"
    
  7. מוחקים את אשכול GKE כדי להסיר את התשתית הבסיסית ואת כל הצמתים שמשויכים למדריך.

    טייס אוטומטי

    gcloud container clusters delete "${CLUSTER_NAME}" \
        --location="${GKE_LOCATION}" --quiet
    

    רגילה

    gcloud container clusters delete "${CLUSTER_NAME}" \
        --location="${ZONE}" --quiet
    
  8. אם רוצים לאפס לגמרי את האחסון, מוחקים את הקטגוריה של Cloud Storage (אופציונלי) באמצעות פקודת ההסרה הרקורסיבית. הערה: אפשר לדלג על השלב הזה אם אתם מתכוונים להשתמש שוב בקטגוריה שהגדרתם בצורה נכונה לבדיקות עתידיות.

    gcloud storage rm --recursive "gs://${SNAPSHOTS_BUCKET_NAME:?Error: SNAPSHOTS_BUCKET_NAME is not set. Please re-define the environment variables you defined earlier.}"
    
  9. אם רוצים להחזיר את הפרויקט למצב נקי לחלוטין, מוחקים את תפקיד ה-IAM בהתאמה אישית (אופציונלי). תפקידי IAM נשארים גם אחרי שמוחקים את האשכול, לכן צריך למחוק אותם בנפרד.

    gcloud iam roles delete podSnapshotGcsReadWriter --project="${PROJECT_ID}"
    

המאמרים הבאים