Attivare gli snapshot della sandbox dell'agente dall'interno di un cluster

Questo tutorial mostra come eseguire il deployment e testare la funzionalità di snapshot di Agent Sandbox all'interno di un cluster Google Kubernetes Engine (GKE). Scoprirai come eseguire un'applicazione client all'interno del cluster per creare, mettere in pausa e riprendere gli ambienti sandbox a livello di programmazione.

Per saperne di più sull'acquisizione di snapshot dei pod, consulta Ripristinare da uno snapshot di un pod.

Costi

Agent Sandbox è offerto senza costi aggiuntivi in GKE. I prezzi di GKE si applicano alle risorse che crei.

Prima di iniziare

  1. Nella Google Cloud console, nella pagina di selezione del progetto, seleziona o crea un Google Cloud progetto.

    Ruoli richiesti per selezionare o creare un progetto

    • Seleziona un progetto: la selezione di un progetto non richiede un ruolo IAM specifico: puoi selezionare qualsiasi progetto su cui ti è stato concesso un ruolo.
    • Crea un progetto: per creare un progetto, devi disporre del ruolo Autore progetto (roles/resourcemanager.projectCreator), che contiene l' resourcemanager.projects.create autorizzazione. Scopri come concedere i ruoli.

    Vai al selettore di progetti

  2. Verifica che la fatturazione sia attivata per il tuo Google Cloud progetto.

  3. Abilita le API Artifact Registry e Kubernetes Engine.

    Ruoli richiesti per abilitare le API

    Per abilitare le API, devi disporre del ruolo IAM Service Usage Admin (roles/serviceusage.serviceUsageAdmin), che contiene l'autorizzazione serviceusage.services.enable. Scopri come concedere i ruoli.

    Abilita le API

  4. Nella Google Cloud console, attiva Cloud Shell.

    Attiva Cloud Shell

  5. Verifica di disporre delle autorizzazioni necessarie per completare questo tutorial.

Ruoli obbligatori

Per ottenere le autorizzazioni necessarie per creare e gestire le sandbox, chiedi all'amministratore di concederti il ruolo IAM Amministratore di Kubernetes Engine (roles/container.admin) nel progetto. Per saperne di più sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

Potresti anche riuscire a ottenere le autorizzazioni richieste tramite i ruoli personalizzati o altri ruoli predefiniti.

Limitazioni

In un cluster regionale, i nodi in zone diverse potrebbero avere microarchitetture CPU diverse. Poiché gli snapshot acquisiscono lo stato della CPU, il ripristino di uno snapshot su un nodo con funzionalità CPU mancanti non riesce (ad esempio, con l'errore OCI runtime restore failed: incompatible FeatureSet).

Per evitare questo problema, utilizza la configurazione appropriata per il tuo ambiente:

  • Produzione: per mantenere un'alta affidabilità nel cluster, non ancorare i carichi di lavoro a una zona specifica. Aiuta invece a garantire la coerenza delle funzionalità della CPU in tutte le zone specificando una piattaforma CPU minima. Per saperne di più, consulta Scegliere una piattaforma CPU minima.
  • Test: per semplificare la configurazione ed evitare errori iniziali di mancata corrispondenza della CPU, puoi utilizzare un campo nodeSelector nel manifest SandboxTemplate per ancorare il pod a una zona specifica, ad esempio us-central1-a. L'esempio in questo tutorial utilizza questa configurazione di test.

Definisci le variabili di ambiente

Per semplificare i comandi eseguiti in questo tutorial, puoi impostare le variabili di ambiente in Cloud Shell. In Cloud Shell, definisci le seguenti variabili di ambiente utili eseguendo i comandi seguenti:

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"

Di seguito è riportata una spiegazione di queste variabili di ambiente:

  • PROJECT_ID: l'ID del tuo progetto corrente. Google Cloud La definizione di questa variabile aiuta a garantire che tutte le risorse vengano create nel progetto corretto.
  • PROJECT_NUMBER: il numero del progetto corrente. Google Cloud
  • CLUSTER_NAME: il nome del cluster GKE, ad esempio test-snapshot.
  • LOCATION: la regione in cui si trovano il cluster GKE e il repository Artifact Registry, ad esempio us-central1. Google Cloud
  • BUCKET_LOCATION: la località dei bucket Cloud Storage, ad esempio us.
  • BUCKET_NAME: il nome del bucket Cloud Storage utilizzato per gli snapshot.
  • CLOUDBUILD_BUCKET_NAME: il nome del bucket Cloud Storage utilizzato per i log di Cloud Build.
  • MACHINE_TYPE: il tipo di macchina da utilizzare per i nodi del cluster, ad esempio e2-standard-8.
  • REPOSITORY_NAME: il nome del repository Artifact Registry, ad esempio agent-sandbox.

Panoramica dei passaggi di configurazione

Per abilitare e testare gli snapshot dei pod degli ambienti Agent Sandbox all'interno del cluster, devi eseguire diversi passaggi di configurazione. Per comprendere questi passaggi, è utile innanzitutto comprendere i componenti coinvolti nel flusso di lavoro complessivo.

Componenti chiave

Questo tutorial utilizza le seguenti due applicazioni Python per testare il processo di snapshot:

  • Applicazione client: uno script Python in esecuzione in un pod standard nel cluster. Questa applicazione gestisce il ciclo di vita della sandbox: crea la sandbox a livello di programmazione, la mette in pausa per attivare uno snapshot, la riprende e verifica che lo stato sia stato mantenuto. In questo tutorial, creerai un account di servizio Kubernetes denominato agent-sandbox-client-sa e gli concederai le autorizzazioni RBAC in modo che il pod dell'applicazione client possa gestire le risorse personalizzate della sandbox e gli oggetti trigger di snapshot utilizzando l'API Kubernetes.
  • Applicazione in sandbox: uno script Python che incrementa e stampa un contatore ogni secondo. Questa applicazione viene eseguita in modo sicuro all'interno dell'ambiente sandbox isolato per generare uno stato in evoluzione che l'applicazione client può verificare. In questo tutorial, creerai un account di servizio Kubernetes dedicato denominato snapshot-sa e configurerai Workload Identity per autorizzare il pod in sandbox a leggere e scrivere in modo sicuro gli oggetti snapshot in Cloud Storage.

Processo di configurazione e test

Il seguente elenco riassume i passaggi da eseguire per configurare l'ambiente ed eseguire il test:

  1. Crea un cluster: crea un cluster Autopilot o Standard con gli snapshot dei pod e la funzionalità Agent Sandbox abilitata.
  2. Crea un repository Artifact Registry: crea un repository Docker per archiviare l'immagine container della tua applicazione client .
  3. Installa Agent Sandbox: installa i componenti e le estensioni principali di agent-sandbox nel cluster.
  4. Configura l'archiviazione e le autorizzazioni: crea un bucket Cloud Storage e configura le autorizzazioni di Workload Identity per consentire il salvataggio sicuro degli snapshot.
  5. Configura gli snapshot dei pod: crea e applica la configurazione di archiviazione degli snapshot, la policy di snapshot e il modello di sandbox.
  6. Crea l'applicazione client: crea l' immagine container per l'applicazione client ed eseguine il push nel repository Artifact Registry.
  7. Esegui il test: esegui il deployment del pod dell'applicazione client, che crea la sandbox, la mette in pausa per acquisire uno snapshot, la riprende e verifica che lo stato del contatore sia stato ripristinato correttamente.

Crea un cluster

Crea un nuovo cluster GKE con gli snapshot dei pod abilitati. Per una compatibilità completa delle funzionalità, specifica il canale di rilascio rapido.

Autopilot

Crea un cluster Autopilot con le funzionalità richieste:

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

Standard

Crea un cluster standard con le funzionalità richieste:

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}

Crea un pool di nodi con gVisor abilitato:

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

Crea un repository Artifact Registry

Crea un repository Docker in Artifact Registry per archiviare l'immagine container dell'applicazione client (l'applicazione che crea e gestisce la sandbox):

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

Installa Agent Sandbox

Installa i componenti e le estensioni principali di Agent Sandbox nel cluster (utilizzando la versione v0.4.6 come esempio):

# 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

Configura l'archiviazione e le autorizzazioni

Configura un bucket Cloud Storage per l'archiviazione degli snapshot dei pod e concedi le autorizzazioni di Workload Identity richieste al account di servizio snapshot-sa e all'agente di servizio GKE. In questo modo, i carichi di lavoro in sandbox possono salvare e recuperare in modo sicuro gli oggetti snapshot:

  1. Crea un nuovo bucket Cloud Storage:

    gcloud storage buckets create "gs://${BUCKET_NAME}" \
        --uniform-bucket-level-access \
        --enable-hierarchical-namespace \
        --soft-delete-duration=0d \
        --location="${BUCKET_LOCATION}"
    
  2. Crea un account di servizio Kubernetes nello spazio dei nomi default. L'applicazione in sandbox (lo script del contatore Python) utilizza questa identità per eseguire l'autenticazione alle API esterne e accedere in modo sicuro agli oggetti snapshot archiviati in Cloud Storage:

    kubectl create serviceaccount "snapshot-sa" \
        --namespace "default"
    
  3. Associa il ruolo storage.bucketViewer al tuo account di servizio utilizzando Workload Identity. Questo ruolo consente al carico di lavoro in sandbox di elencare i contenuti del bucket e individuare snapshot specifici:

    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. Associa il ruolo storage.objectUser al tuo account di servizio utilizzando Workload Identity. Questo ruolo fornisce l'autorizzazione per leggere, salvare ed eliminare gli oggetti binari degli snapshot all'interno del 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. Concedi all'agente di servizio GKE le autorizzazioni per gestire (creare, elencare, leggere ed eliminare) gli oggetti snapshot all'interno del 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"
    

Configura gli snapshot dei pod

Crea e applica i file di configurazione per installare le risorse personalizzate di Kubernetes richieste. Queste risorse definiscono come il cluster archivia e gestisce gli snapshot dei pod:

  • PodSnapshotStorageConfig: specifica il bucket Cloud Storage designato per l'archiviazione degli oggetti binari degli snapshot.
  • PodSnapshotPolicy: definisce come vengono attivati manualmente gli snapshot, la frequenza con cui vengono raggruppati e le relative policy di conservazione.
  • SandboxTemplate: definisce il container sottostante, i selettori di nodi e i service account per l'esecuzione del carico di lavoro in sandbox isolato.
  1. Crea un file denominato test_client/snapshot_storage_config.yaml. Questa configurazione specifica il bucket Cloud Storage di destinazione in cui il cluster salva lo stato binario dello snapshot del pod:

    apiVersion: podsnapshot.gke.io/v1
    kind: PodSnapshotStorageConfig
    metadata:
      name: example-pod-snapshot-storage-config
    spec:
      snapshotStorageConfig:
        gcs:
          bucket: "$BUCKET_NAME"
    
  2. Sostituisci il segnaposto della variabile di ambiente nel file di configurazione:

    sed -i "s/\$BUCKET_NAME/$BUCKET_NAME/g" test_client/snapshot_storage_config.yaml
    
  3. Applica il manifest di configurazione dell'archiviazione:

    kubectl apply -f test_client/snapshot_storage_config.yaml
    
  4. Attendi che la configurazione dell'archiviazione sia pronta:

    kubectl wait --for=condition=Ready podsnapshotstorageconfig/example-pod-snapshot-storage-config --timeout=60s
    
  5. Crea un file denominato test_client/snapshot_policy.yaml. Questa configurazione stabilisce una regola di conservazione che conserva un massimo di due snapshot per il carico di lavoro in sandbox. Il tipo di trigger è impostato su manual: in questo modo l'applicazione client può controllare gli snapshot on demand:

    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. Applica il manifest della policy di snapshot:

    kubectl apply -f test_client/snapshot_policy.yaml
    
  7. Crea un file denominato test_client/python-counter-template.yaml. Questa configurazione definisce il pod della sandbox e gli assegna l'identità account di servizio snapshot-sa. Questa assegnazione contribuisce a garantire che la sandbox venga eseguita in modo sicuro. All'interno di questo pod, l'applicazione in sandbox (uno script Python) stampa continuamente un contatore incrementale nei log dei 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. Applica il manifest del modello di sandbox:

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

Crea l'applicazione client

Crea l'immagine container per l'applicazione client e caricala in Artifact Registry.

  1. Crea un file denominato test_client/Dockerfile.client. Questo file definisce l'ambiente di runtime Python e le dipendenze per l'applicazione client:

    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. Crea un file denominato test_client/client_test.py. Questo script gestisce il ciclo di vita della sandbox e verifica che lo stato venga ripreso correttamente dopo l'acquisizione di uno 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. Crea l'immagine container client e caricala in Artifact Registry. Se nel tuo ambiente (ad esempio Cloud Shell) è installato Docker, puoi utilizzarlo per creare l'immagine in locale. Se lavori in un ambiente senza Docker, puoi utilizzare Cloud Build per creare ed eseguire il push dell'immagine da remoto:

    Docker

    1. Configura l'autenticazione Docker per Artifact Registry:

      gcloud auth configure-docker "${LOCATION}-docker.pkg.dev"
      
    2. Crea ed esegui il push dell'immagine container client in locale:

      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. Crea un file denominato 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. Sostituisci i segnaposto variabile di ambiente nel file di configurazione:

      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. Concedi le autorizzazioni necessarie al account di servizio Cloud Build:

      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. Esegui la build utilizzando Cloud Build:

      gcloud builds submit --config test_client/cloudbuild.yaml
      

Esegui il test

Esegui il deployment dell'applicazione client per creare la sandbox, attivare uno snapshot e verificare che il contatore interno riprenda correttamente dallo stato salvato.

  1. Crea un file denominato test_client/client_sa.yaml. Questo manifest definisce il account di servizio agent-sandbox-client-sa e le relative autorizzazioni RBAC richieste per la gestione delle risorse personalizzate della 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. Applica il account di servizio client e il manifest RBAC:

    kubectl apply -f test_client/client_sa.yaml
    
  3. Crea un file denominato test_client/client_pod.yaml. Questo manifest crea il pod dell'applicazione client utilizzando l'immagine container precompilata:

    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. Sostituisci i segnaposto variabile di ambiente nel manifest:

    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. Applica il manifest del pod dell'applicazione client:

    kubectl apply -f test_client/client_pod.yaml
    
  6. Trasmetti in streaming i log dei pod per verificare il flusso di esecuzione:

    kubectl logs -f agent-sandbox-client-pod
    

Quando il test viene eseguito correttamente, l'output è simile al seguente (qui abbreviato per facilitare la lettura):

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

L'output mostra che la sandbox mantiene correttamente il suo stato quando viene sospesa e ripresa. Il contatore smette di avanzare mentre la sandbox è sospesa (messa in pausa e scalata a zero) e riprende il contatore quando la sandbox viene ripristinata. Senza la sospensione, il contatore avrebbe continuato ad avanzare durante il periodo di sospensione e il conteggio sarebbe stato notevolmente più alto.

Libera spazio

Per evitare che al tuo Google Cloud account vengano addebitati costi, elimina le risorse che hai creato:

  1. Elimina il cluster GKE. Vengono eliminati anche il pool di nodi e tutti i service account Kubernetes al suo interno:

    gcloud beta container clusters delete test-snapshot --location="${LOCATION}" --quiet
    
  2. Elimina il repository Artifact Registry per rimuovere il repository Docker creato per l'immagine di test:

    gcloud artifacts repositories delete ${REPOSITORY_NAME} --location="${LOCATION}" --quiet
    
  3. Elimina il bucket Cloud Storage e tutti gli snapshot al suo interno. Vengono rimosse automaticamente le associazioni IAM di Workload Identity a livello di bucket applicate:

    gcloud storage rm --recursive "gs://${BUCKET_NAME}"
    
  4. Rimuovi l'associazione IAM a livello di progetto per l'agente di servizio 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. Se hai utilizzato Cloud Build anziché Docker per creare ed eseguire il push dell'immagine container, elimina il bucket dei log e rimuovi le autorizzazioni del account di servizio:

    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"
    

Passaggi successivi