Memicu snapshot Sandbox Agen dari dalam cluster

Tutorial ini menunjukkan cara men-deploy dan menguji fitur snapshot Agent Sandbox dari dalam cluster Google Kubernetes Engine (GKE). Anda akan mempelajari cara menjalankan aplikasi klien di dalam cluster untuk membuat, menjeda, dan melanjutkan lingkungan sandbox secara terprogram.

Untuk mengetahui informasi selengkapnya tentang cara mengambil snapshot Pod, lihat Memulihkan dari snapshot Pod.

Biaya

Agent Sandbox ditawarkan tanpa biaya tambahan di GKE. Harga GKE berlaku untuk resource yang Anda buat.

Sebelum memulai

  1. Di Cloud de Confiance konsol, pada halaman pemilih project, pilih atau buat Cloud de Confiance project.

    Peran yang diperlukan untuk memilih atau membuat project

    • Memilih project: Memilih project tidak memerlukan peran IAM tertentu Anda dapat memilih project mana pun yang telah diberi peran.
    • Membuat project: Untuk membuat project, Anda memerlukan peran Pembuat Project (roles/resourcemanager.projectCreator), yang berisi izin resourcemanager.projects.create. Pelajari cara memberikan peran.

    Buka pemilih project

  2. Pastikan penagihan diaktifkan untuk Cloud de Confiance project Anda.

  3. Aktifkan Artifact Registry, Kubernetes Engine API.

    Peran yang diperlukan untuk mengaktifkan API

    Untuk mengaktifkan API, Anda memerlukan peran IAM Service Usage Admin (roles/serviceusage.serviceUsageAdmin), yang berisi izin serviceusage.services.enable. Pelajari cara memberikan peran.

    Aktifkan API

  4. Di konsol, aktifkan Cloud Shell. Cloud de Confiance

    Aktifkan Cloud Shell

  5. Pastikan Anda memiliki izin yang diperlukan untuk menyelesaikan tutorial ini.

Peran yang diperlukan

Untuk mendapatkan izin yang diperlukan guna membuat dan mengelola sandbox, minta administrator untuk memberi Anda peran IAM Kubernetes Engine Admin (roles/container.admin) di project Anda. Untuk mengetahui informasi selengkapnya tentang cara memberikan peran, lihat Mengelola akses ke project, folder, dan organisasi.

Anda mungkin juga bisa mendapatkan izin yang diperlukan melalui peran khusus atau peran bawaan lainnya.

Batasan

Di cluster regional, node di zona yang berbeda mungkin memiliki mikroarsitektur CPU yang berbeda. Karena snapshot mengambil status CPU, pemulihan snapshot pada node dengan fitur CPU yang tidak ada akan gagal (misalnya, dengan error OCI runtime restore failed: incompatible FeatureSet).

Untuk menghindari masalah ini, gunakan konfigurasi yang sesuai untuk lingkungan Anda:

  • Produksi: Untuk mempertahankan ketersediaan tinggi di seluruh cluster, jangan sematkan workload ke zona tertentu. Sebagai gantinya, bantu memastikan konsistensi fitur CPU di semua zona dengan menentukan platform CPU minimum. Untuk mengetahui informasi selengkapnya, lihat Memilih platform CPU minimum.
  • Pengujian: Untuk menyederhanakan penyiapan dan menghindari error ketidakcocokan CPU awal, Anda dapat menggunakan kolom nodeSelector dalam manifes SandboxTemplate untuk menyematkan Pod ke zona tertentu, seperti us-central1-a. Contoh dalam tutorial ini menggunakan konfigurasi pengujian ini.

Menentukan variabel lingkungan

Untuk menyederhanakan perintah yang Anda jalankan dalam tutorial ini, Anda dapat menetapkan variabel lingkungan di Cloud Shell. Di Cloud Shell, tentukan variabel lingkungan berguna berikut dengan menjalankan perintah berikut:

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"

Berikut penjelasan variabel lingkungan ini:

  • PROJECT_ID: IDproject Anda saat ini. Cloud de Confiance by S3NS Menentukan variabel ini membantu memastikan bahwa semua resource dibuat di project yang benar.
  • PROJECT_NUMBER: nomor project Anda saat ini Cloud de Confiance by S3NS project.
  • CLUSTER_NAME: nama cluster GKE Anda—misalnya, test-snapshot.
  • LOCATION: region tempat cluster GKE dan repositori Artifact Registry Anda berada—misalnya, us-central1. Cloud de Confiance by S3NS
  • BUCKET_LOCATION: lokasi bucket Cloud Storage Anda—misalnya, us.
  • BUCKET_NAME: nama bucket Cloud Storage yang digunakan untuk snapshot.
  • CLOUDBUILD_BUCKET_NAME: nama bucket Cloud Storage yang digunakan untuk log Cloud Build.
  • MACHINE_TYPE: jenis mesin yang akan digunakan untuk node cluster—misalnya, e2-standard-8.
  • REPOSITORY_NAME: nama repositori Artifact Registry—misalnya, agent-sandbox.

Ringkasan langkah konfigurasi

Untuk mengaktifkan dan menguji snapshot Pod lingkungan Agent Sandbox dari dalam cluster, Anda harus melakukan beberapa langkah konfigurasi. Untuk memahami langkah-langkah ini, sebaiknya pahami terlebih dahulu komponen yang terlibat dalam alur kerja keseluruhan.

Komponen utama

Tutorial ini menggunakan dua aplikasi Python berikut untuk menguji proses snapshot:

  • Aplikasi klien: skrip Python yang berjalan di Pod standar di cluster Anda. Aplikasi ini mengelola siklus proses sandbox: aplikasi ini membuat sandbox secara terprogram, menjedanya untuk memicu snapshot, melanjutkan sandbox, dan memverifikasi bahwa statusnya dipertahankan. Dalam tutorial ini, Anda akan membuat akun layanan Kubernetes bernama agent-sandbox-client-sa dan memberinya izin RBAC sehingga Pod aplikasi klien dapat mengelola resource kustom sandbox dan objek pemicu snapshot menggunakan Kubernetes API.
  • Aplikasi sandbox: skrip Python yang menambah dan mencetak penghitung setiap detik. Aplikasi ini berjalan dengan aman di dalam lingkungan sandbox terisolasi untuk menghasilkan status yang berubah yang dapat diverifikasi oleh aplikasi klien. Dalam tutorial ini, Anda akan membuat akun layanan Kubernetes khusus bernama snapshot-sa dan mengonfigurasi Workload Identity untuk mengotorisasi Pod sandbox agar dapat membaca dan menulis objek snapshot di Cloud Storage dengan aman.

Proses konfigurasi dan pengujian

Daftar berikut merangkum langkah-langkah yang perlu Anda lakukan untuk menyiapkan lingkungan dan menjalankan pengujian:

  1. Membuat cluster: buat cluster Autopilot atau Standar dengan snapshot Pod dan fitur Agent Sandbox diaktifkan.
  2. Membuat repositori Artifact Registry: buat repositori Docker untuk menyimpan image container untuk aplikasi klien Anda.
  3. Menginstal Agent Sandbox: instal komponen dan ekstensi agent-sandbox inti di cluster Anda.
  4. Mengonfigurasi penyimpanan dan izin: buat bucket Cloud Storage dan konfigurasi izin Workload Identity untuk memungkinkan snapshot disimpan dengan aman.
  5. Mengonfigurasi snapshot Pod: buat dan terapkan konfigurasi penyimpanan snapshot, kebijakan snapshot, dan template sandbox.
  6. Membangun aplikasi klien: bangun image container untuk aplikasi klien dan kirim ke repositori Artifact Registry Anda.
  7. Menjalankan pengujian: men-deploy Pod aplikasi klien, yang membuat sandbox, menjedanya untuk mengambil snapshot, melanjutkannya, dan memverifikasi bahwa status penghitung berhasil dipulihkan.

Membuat cluster

Buat cluster GKE baru dengan snapshot Pod diaktifkan. Untuk kompatibilitas fitur lengkap, tentukan saluran rilis cepat.

Autopilot

Buat cluster Autopilot dengan fitur yang diperlukan:

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

Standar

Buat cluster Standar dengan fitur yang diperlukan:

gcloud beta 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=${LOCATION}

Buat node pool dengan gVisor diaktifkan:

gcloud container node-pools create gvisor-pool \
   --cluster ${CLUSTER_NAME} \
   --num-nodes=1 \
   --location=${LOCATION} \
   --project=${PROJECT_ID} \
   --sandbox type=gvisor

Membuat repositori Artifact Registry

Buat repositori Docker di Artifact Registry untuk menyimpan image container untuk aplikasi klien Anda (aplikasi yang membuat dan mengelola sandbox):

gcloud artifacts repositories create ${REPOSITORY_NAME} \
   --repository-format=docker \
   --location=${LOCATION} \
   --description="Docker repository for Agent Sandbox"

Menginstal Agent Sandbox

Instal komponen dan ekstensi inti Agent Sandbox di cluster Anda (menggunakan versi v0.4.6 sebagai contoh):

# 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

Mengonfigurasi penyimpanan dan izin

Konfigurasi bucket Cloud Storage untuk menyimpan snapshot Pod dan berikan izin Workload Identity yang diperlukan ke akun layanan snapshot-sa dan agen layanan GKE. Hal ini memungkinkan workload sandbox Anda menyimpan dan mengambil objek snapshot dengan aman:

  1. Buat bucket Cloud Storage baru:

    gcloud storage buckets create "gs://${BUCKET_NAME}" \
        --uniform-bucket-level-access \
        --enable-hierarchical-namespace \
        --soft-delete-duration=0d \
        --location="${BUCKET_LOCATION}"
    
  2. Buat akun layanan Kubernetes di namespace default. Aplikasi sandbox Anda (skrip penghitung Python) menggunakan identitas ini untuk melakukan autentikasi ke API eksternal dan mengakses objek snapshot yang disimpan di Cloud Storage dengan aman:

    kubectl create serviceaccount "snapshot-sa" \
        --namespace "default"
    
  3. Ikat peran storage.bucketViewer ke akun layanan Anda menggunakan Workload Identity. Peran ini memungkinkan workload sandbox mencantumkan konten bucket dan menemukan snapshot tertentu:

    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"
    
  4. Ikat peran storage.objectUser ke akun layanan Anda menggunakan Workload Identity. Peran ini memberikan izin untuk membaca, menyimpan, dan menghapus objek biner snapshot dalam bucket:

    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"
    
  5. Beri agen layanan GKE izin untuk mengelola (membuat, mencantumkan, membaca, dan menghapus) objek snapshot dalam bucket:

    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"
    

Mengonfigurasi snapshot Pod

Buat dan terapkan file konfigurasi untuk menginstal resource kustom Kubernetes yang diperlukan. Resource ini menentukan cara cluster menyimpan dan mengelola snapshot Pod:

  • PodSnapshotStorageConfig: menentukan bucket Cloud Storage yang ditetapkan untuk menyimpan objek biner snapshot.
  • PodSnapshotPolicy: menentukan cara snapshot dipicu secara manual, seberapa sering dikelompokkan, dan kebijakan retensinya.
  • SandboxTemplate: menentukan container yang mendasarinya, pemilih node, dan akun layanan untuk menjalankan workload sandbox terisolasi.
  1. Buat file bernama test_client/snapshot_storage_config.yaml. Konfigurasi ini menentukan bucket Cloud Storage target tempat cluster menyimpan status snapshot Pod biner:

    apiVersion: podsnapshot.gke.io/v1
    kind: PodSnapshotStorageConfig
    metadata:
      name: example-pod-snapshot-storage-config
    spec:
      snapshotStorageConfig:
        gcs:
          bucket: "$BUCKET_NAME"
    
  2. Ganti placeholder variabel lingkungan dalam file konfigurasi:

    sed -i "s/\$BUCKET_NAME/$BUCKET_NAME/g" test_client/snapshot_storage_config.yaml
    
  3. Terapkan manifes konfigurasi penyimpanan:

    kubectl apply -f test_client/snapshot_storage_config.yaml
    
  4. Tunggu hingga konfigurasi penyimpanan siap:

    kubectl wait --for=condition=Ready podsnapshotstorageconfig/example-pod-snapshot-storage-config --timeout=60s
    
  5. Buat file bernama test_client/snapshot_policy.yaml. Konfigurasi ini menetapkan aturan retensi yang mempertahankan maksimum dua snapshot untuk workload sandbox Anda. Jenis pemicu ditetapkan ke manual: hal ini memungkinkan aplikasi klien mengontrol snapshot sesuai permintaan:

    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
    
  6. Terapkan manifes kebijakan snapshot:

    kubectl apply -f test_client/snapshot_policy.yaml
    
  7. Buat file bernama test_client/python-counter-template.yaml. Konfigurasi ini menentukan Pod sandbox, dan menetapkan identitas akun layanan snapshot-sa ke Pod tersebut. Penetapan ini membantu memastikan sandbox berjalan dengan aman. Di dalam Pod tersebut, aplikasi sandbox (skrip Python) terus mencetak penghitung yang bertambah ke log container:

    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)
    
  8. Terapkan manifes template sandbox:

    kubectl apply -f test_client/python-counter-template.yaml
    

Membangun aplikasi klien

Buat image container untuk aplikasi klien dan upload ke Artifact Registry.

  1. Buat file bernama test_client/Dockerfile.client. File ini menentukan lingkungan runtime dan dependensi Python untuk aplikasi klien:

    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"]
    
  2. Buat file bernama test_client/client_test.py. Skrip ini mengelola siklus proses sandbox dan memverifikasi bahwa status berhasil dilanjutkan setelah mengambil snapshot:

    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()
    
  3. Bangun image container klien dan upload ke Artifact Registry. Jika lingkungan Anda (seperti Cloud Shell) telah menginstal Docker, Anda dapat menggunakan Docker untuk membangun image secara lokal. Jika Anda bekerja di lingkungan tanpa Docker, Anda dapat menggunakan Cloud Build untuk membangun dan mengirim image dari jarak jauh:

    Docker

    1. Konfigurasi autentikasi Docker untuk Artifact Registry:

      gcloud auth configure-docker "${LOCATION}-docker.pkg.dev"
      
    2. Bangun dan kirim image container klien secara lokal:

      docker build -t "${LOCATION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/sandbox-client:latest" -f test_client/Dockerfile.client test_client
      docker push "${LOCATION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY_NAME}/sandbox-client:latest"
      

    Cloud Build

    1. Buat file bernama test_client/cloudbuild.yaml:

      steps:
      - name: 'gcr.io/cloud-builders/docker'
        args: ['build', '-t', '$LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/sandbox-client:latest', '-f', 'test_client/Dockerfile.client', 'test_client']
      images:
      - '$LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/sandbox-client:latest'
      
    2. Ganti placeholder variabel lingkungan dalam file konfigurasi:

      sed -i "s/\$REPOSITORY_NAME/$REPOSITORY_NAME/g" test_client/cloudbuild.yaml
      sed -i "s/\$LOCATION/$LOCATION/g" test_client/cloudbuild.yaml
      sed -i "s/\$PROJECT_ID/$PROJECT_ID/g" test_client/cloudbuild.yaml
      
    3. Beri akun layanan Cloud Build izin yang diperlukan:

      gcloud projects add-iam-policy-binding $PROJECT_ID \
         --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
         --role="roles/artifactregistry.writer"
      
      gcloud projects add-iam-policy-binding $PROJECT_ID \
         --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
         --role="roles/logging.logWriter"
      
      gcloud storage buckets add-iam-policy-binding "gs://$CLOUDBUILD_BUCKET_NAME" \
         --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
         --role="roles/storage.objectAdmin"
      
    4. Jalankan build menggunakan Cloud Build:

      gcloud builds submit --config test_client/cloudbuild.yaml
      

Menjalankan pengujian

Deploy aplikasi klien untuk membuat sandbox, memicu snapshot, dan memverifikasi bahwa penghitung internal berhasil dilanjutkan dari status yang disimpan.

  1. Buat file bernama test_client/client_sa.yaml. Manifes ini menentukan akun layanan agent-sandbox-client-sa dan izin RBAC yang diperlukan untuk mengelola resource kustom sandbox:

    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
    
  2. Terapkan akun layanan klien dan manifes RBAC:

    kubectl apply -f test_client/client_sa.yaml
    
  3. Buat file bernama test_client/client_pod.yaml. Manifes ini membuat Pod aplikasi klien menggunakan image container bawaan:

    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
    
  4. Ganti placeholder variabel lingkungan dalam manifes:

    sed -i "s/\$REPOSITORY_NAME/$REPOSITORY_NAME/g" test_client/client_pod.yaml
    sed -i "s/\$LOCATION/$LOCATION/g" test_client/client_pod.yaml
    sed -i "s/\$PROJECT_ID/$PROJECT_ID/g" test_client/client_pod.yaml
    
  5. Terapkan manifes Pod aplikasi klien:

    kubectl apply -f test_client/client_pod.yaml
    
  6. Streaming log Pod untuk memverifikasi alur eksekusi:

    kubectl logs -f agent-sandbox-client-pod
    

Jika pengujian berjalan dengan benar, output-nya akan terlihat mirip dengan ini (dipersingkat di sini agar mudah dibaca):

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).

Output menunjukkan bahwa sandbox berhasil mempertahankan statusnya saat ditangguhkan dan dilanjutkan. Penghitung berhenti bertambah saat sandbox ditangguhkan (dijeda dan diskalakan ke nol), dan melanjutkan penghitung saat sandbox dipulihkan. Tanpa penangguhan, penghitung akan terus bertambah selama periode penangguhan dan jumlahnya akan jauh lebih tinggi.

Membersihkan resource

Agar akun Anda tidak dikenai biaya, hapus resource yang Anda buat: Cloud de Confiance by S3NS

  1. Hapus cluster GKE. Tindakan ini juga akan menghapus node pool dan semua akun layanan Kubernetes di dalamnya:

    gcloud beta container clusters delete test-snapshot --location="${LOCATION}" --quiet
    
  2. Hapus repositori Artifact Registry untuk menghapus repositori Docker yang Anda buat untuk image pengujian:

    gcloud artifacts repositories delete ${REPOSITORY_NAME} --location="${LOCATION}" --quiet
    
  3. Hapus bucket Cloud Storage dan semua snapshot di dalamnya. Tindakan ini akan otomatis menghapus binding IAM Workload Identity tingkat bucket yang diterapkan padanya:

    gcloud storage rm --recursive "gs://${BUCKET_NAME}"
    
  4. Hapus binding IAM tingkat project untuk agen layanan GKE:

    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"
    
  5. Jika Anda menggunakan Cloud Build, bukan Docker, untuk membangun dan mengirim image container, hapus bucket log dan hapus izin akun layanan:

    gcloud storage rm --recursive "gs://${CLOUDBUILD_BUCKET_NAME}"
    
    gcloud projects remove-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role="roles/artifactregistry.writer"
    
    gcloud projects remove-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role="roles/logging.logWriter"
    

Langkah berikutnya