Agent Sandbox-Snapshots aus einem Cluster heraus auslösen

Verwenden Sie Agent Sandbox-Snapshots in einem Google Kubernetes Engine-Cluster (GKE), um den Status Ihrer Sandbox-Umgebungen beizubehalten. Dieser Ansatz ermöglicht ein konsistentes Debugging, beschleunigt die Entwicklungsiteration und erleichtert die schnelle Wiederherstellung komplexer Setups. In dieser Anleitung stellen Sie diese Funktion bereit und testen sie, indem Sie eine Clientanwendung ausführen, die programmatisch Sandbox-Umgebungen im Cluster erstellt, pausiert und fortsetzt.

Weitere Informationen zum Erstellen von Snapshots von Pods finden Sie unter Aus einem Pod-Snapshot wiederherstellen.

Kosten

Die Agent-Sandbox wird in GKE ohne zusätzliche Kosten angeboten. Die GKE-Preise gelten für die von Ihnen erstellten Ressourcen.

Hinweis

  1. Wählen Sie in der Google Cloud Console auf der Seite für die Projektauswahl ein Google Cloud -Projekt aus oder erstellen Sie eines.

    Rollen, die zum Auswählen oder Erstellen eines Projekts erforderlich sind

    • Projekt auswählen: Für die Auswahl eines Projekts ist keine bestimmte IAM-Rolle erforderlich. Sie können jedes Projekt auswählen, für das Ihnen eine Rolle zugewiesen wurde.
    • Projekt erstellen: Zum Erstellen eines Projekts benötigen Sie die Rolle „Projektersteller“ (roles/resourcemanager.projectCreator), die die Berechtigung resourcemanager.projects.create enthält. Weitere Informationen zum Zuweisen von Rollen

    Zur Projektauswahl

  2. Prüfen Sie, ob die Abrechnung für Ihr Google Cloud Projekt aktiviert ist.

  3. Aktivieren Sie die Artifact Registry API, die Kubernetes Engine API und die Cloud Build API.

    Rollen, die zum Aktivieren von APIs erforderlich sind

    Zum Aktivieren von APIs benötigen Sie die Berechtigung serviceusage.services.enable. Wenn Sie das Projekt erstellt haben, haben Sie diese Berechtigung wahrscheinlich bereits über die Rolle „Inhaber“ (roles/owner). Andernfalls können Sie diese Berechtigung über die Rolle „Service Usage-Administrator“ (roles/serviceusage.serviceUsageAdmin) erhalten. Informationen zum Zuweisen von Rollen

    APIs aktivieren

  4. Aktivieren Sie Cloud Shell in der Google Cloud Console.

    Cloud Shell aktivieren

  5. Prüfen Sie, ob Sie die Berechtigungen haben, die für dieses Tutorial erforderlich sind.

Erforderliche Rollen

Bitten Sie Ihren Administrator, Ihnen die IAM-Rolle Kubernetes Engine-Administrator (roles/container.admin) für Ihr Projekt zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Erstellen und Verwalten von Sandboxes benötigen. Weitere Informationen zum Zuweisen von Rollen finden Sie unter Zugriff auf Projekte, Ordner und Organisationen verwalten.

Sie können die erforderlichen Berechtigungen auch über benutzerdefinierte Rollen oder andere vordefinierte Rollen erhalten.

Beschränkungen

In einem regionalen Cluster können Knoten in verschiedenen Zonen unterschiedliche CPU-Mikroarchitekturen haben. Da in Snapshots der CPU-Status erfasst wird, schlägt das Wiederherstellen eines Snapshots auf einem Knoten mit fehlenden CPU-Funktionen fehl (z. B. mit dem Fehler OCI runtime restore failed: incompatible FeatureSet).

Um dieses Problem zu vermeiden, verwenden Sie die entsprechende Konfiguration für Ihre Umgebung:

  • Produktion: Um die Hochverfügbarkeit in Ihrem Cluster aufrechtzuerhalten, sollten Sie Arbeitslasten nicht an eine bestimmte Zone anpinnen. Stattdessen können Sie eine Mindest-CPU-Plattform angeben, um die Konsistenz der CPU-Funktionen in allen Zonen zu gewährleisten. Weitere Informationen finden Sie unter Mindest-CPU-Plattform auswählen.
  • Testen: Um die Einrichtung zu vereinfachen und anfängliche CPU-Fehler zu vermeiden, können Sie in Ihrem SandboxTemplate-Manifest das Feld nodeSelector verwenden, um den Pod an eine bestimmte Zone wie us-central1-a anzuhängen. Im Beispiel in dieser Anleitung wird diese Testkonfiguration verwendet.

Umgebungsvariablen definieren

Um die Befehle, die Sie in dieser Anleitung ausführen, zu vereinfachen, können Sie Umgebungsvariablen in Cloud Shell festlegen. Definieren Sie in Cloud Shell die folgenden nützlichen Umgebungsvariablen, indem Sie die folgenden Befehle ausführen:

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"

Hier finden Sie eine Erläuterung dieser Umgebungsvariablen:

  • PROJECT_ID: die ID Ihres aktuellen Google Cloud -Projekts. Durch das Definieren dieser Variablen wird sichergestellt, dass alle Ressourcen im richtigen Projekt erstellt werden.
  • PROJECT_NUMBER: Die Projektnummer Ihres aktuellen Google Cloud Projekts.
  • CLUSTER_NAME: der Name Ihres GKE-Cluster, z. B. test-snapshot.
  • LOCATION: die Google Cloud Region, in der sich Ihr GKE-Cluster und das Artifact Registry-Repository befinden, z. B. us-central1.
  • BUCKET_LOCATION: Der Speicherort Ihrer Cloud Storage-Buckets, z. B. us.
  • BUCKET_NAME: Der Name des Cloud Storage-Bucket, der für Snapshots verwendet wird.
  • CLOUDBUILD_BUCKET_NAME: Der Name des Cloud Storage-Bucket, der für Cloud Build-Logs verwendet wird.
  • MACHINE_TYPE: Der Maschinentyp, der für die Clusterknoten verwendet werden soll, z. B. e2-standard-8.
  • REPOSITORY_NAME: Der Name des Artifact Registry-Repositorys, z. B. agent-sandbox.

Übersicht über die Konfigurationsschritte

Wenn Sie Pod-Snapshots von Agent Sandbox-Umgebungen in Ihrem Cluster aktivieren und testen möchten, müssen Sie mehrere Konfigurationsschritte ausführen. Um diese Schritte nachzuvollziehen, ist es hilfreich, zuerst die Komponenten zu verstehen, die am gesamten Workflow beteiligt sind.

Schlüsselkomponenten

In dieser Anleitung werden die folgenden beiden Python-Anwendungen verwendet, um den Snapshot-Prozess zu testen:

  • Clientanwendung: Ein Python-Script, das in einem Standard-Pod in Ihrem Cluster ausgeführt wird. Diese Anwendung verwaltet den Sandbox-Lebenszyklus: Sie erstellt die Sandbox programmatisch, pausiert sie, um einen Snapshot auszulösen, setzt die Sandbox fort und prüft, ob der Status beibehalten wurde. In dieser Anleitung erstellen Sie ein Kubernetes-Dienstkonto mit dem Namen agent-sandbox-client-sa und erteilen ihm RBAC-Berechtigungen, damit der Clientanwendungs-Pod Sandbox-Ressourcen und Snapshot-Triggerobjekte mit der Kubernetes API verwalten kann.
  • Sandbox-Anwendung: Ein Python-Script, das einen Zähler jede Sekunde erhöht und ausgibt. Diese Anwendung wird sicher in der isolierten Sandbox-Umgebung ausgeführt, um einen sich ändernden Status zu generieren, den die Clientanwendung überprüfen kann. In dieser Anleitung erstellen Sie ein dediziertes Kubernetes-Dienstkonto namens snapshot-sa und konfigurieren Workload Identity, um den Sandbox-Pod zu autorisieren, Snapshot-Objekte in Cloud Storage sicher zu lesen und zu schreiben.

Konfigurations- und Testprozess

In der folgenden Liste sind die Schritte zusammengefasst, die Sie ausführen müssen, um Ihre Umgebung einzurichten und den Test auszuführen:

  1. Cluster erstellen: Erstellen Sie einen Autopilot- oder Standard-Cluster mit aktivierten Pod-Snapshots und der Agent Sandbox-Funktion.
  2. Artifact Registry-Repository erstellen: Erstellen Sie ein Docker-Repository zum Speichern des Container-Images für Ihre Clientanwendung.
  3. Agent-Sandbox installieren: Installieren Sie die wichtigsten Agent-Sandbox-Komponenten und ‑Erweiterungen in Ihrem Cluster.
  4. Speicher und Berechtigungen konfigurieren: Erstellen Sie einen Cloud Storage-Bucket und konfigurieren Sie Workload Identity-Berechtigungen, damit Snapshots sicher gespeichert werden können.
  5. Pod-Snapshots konfigurieren: Erstellen und Anwenden der Snapshot-Speicherkonfiguration, der Snapshot-Richtlinie und der Sandbox-Vorlage.
  6. Clientanwendung erstellen: Erstellen Sie das Container-Image für die Clientanwendung und übertragen Sie es per Push in Ihr Artifact Registry-Repository.
  7. Test ausführen: Stellen Sie den Pod der Clientanwendung bereit. Dadurch wird die Sandbox erstellt, pausiert, um einen Snapshot zu erstellen, fortgesetzt und es wird geprüft, ob der Status des Zählers erfolgreich wiederhergestellt wurde.

Cluster erstellen

Einen neuen GKE-Cluster mit aktivierten Pod-Snapshots erstellen Geben Sie den Rapid Release Channel an, um die volle Kompatibilität mit allen Funktionen zu gewährleisten.

Autopilot

Erstellen Sie einen Autopilot-Cluster mit den erforderlichen Funktionen:

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

Standard

Erstellen Sie einen Standardcluster mit den erforderlichen Funktionen:

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}

So erstellen Sie einen Knotenpool mit aktiviertem gVisor:

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

Artifact Registry-Repository erstellen

Erstellen Sie in Artifact Registry ein Docker-Repository zum Speichern des Container-Images für Ihre Clientanwendung (die Anwendung, die die Sandbox erstellt und verwaltet):

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

Agent Sandbox installieren

Installieren Sie die Agent Sandbox-Kernkomponenten und -Erweiterungen in Ihrem Cluster (am Beispiel von Version 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

Speicher und Berechtigungen konfigurieren

Konfigurieren Sie einen Cloud Storage-Bucket zum Speichern von Pod-Snapshots und gewähren Sie dem snapshot-sa-Dienstkonto und dem GKE-Dienst-Agent die erforderlichen Workload Identity-Berechtigungen. So können Ihre Sandbox-Arbeitslasten Snapshot-Objekte sicher speichern und abrufen:

  1. Erstellen Sie einen neuen Cloud Storage-Bucket:

    gcloud storage buckets create "gs://${BUCKET_NAME}" \
        --uniform-bucket-level-access \
        --enable-hierarchical-namespace \
        --soft-delete-duration=0d \
        --location="${BUCKET_LOCATION}"
    
  2. Erstellen Sie ein Kubernetes-Dienstkonto im Namespace default. Ihre Sandbox-Anwendung (das Python-Zählerskript) verwendet diese Identität, um sich bei externen APIs zu authentifizieren und sicher auf Snapshot-Objekte zuzugreifen, die in Cloud Storage gespeichert sind:

    kubectl create serviceaccount "snapshot-sa" \
        --namespace "default"
    
  3. Binden Sie die Rolle storage.bucketViewer mithilfe von Workload Identity an Ihr Dienstkonto. Mit dieser Rolle kann die Sandbox-Arbeitslast den Inhalt des Buckets auflisten und bestimmte Snapshots finden:

    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. Binden Sie die Rolle storage.objectUser mithilfe von Workload Identity an Ihr Dienstkonto. Diese Rolle gewährt die Berechtigung, binäre Snapshot-Objekte im Bucket zu lesen, zu speichern und zu löschen:

    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. Gewähren Sie dem GKE-Dienstkonto Berechtigungen zum Verwalten (Erstellen, Auflisten, Lesen und Löschen) von Snapshot-Objekten im 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"
    

Pod-Snapshots konfigurieren

Erstellen Sie die Konfigurationsdateien und wenden Sie sie an, um die erforderlichen benutzerdefinierten Kubernetes-Ressourcen zu installieren. Diese Ressourcen definieren, wie der Cluster Pod-Snapshots speichert und verwaltet:

  • PodSnapshotStorageConfig: gibt den Cloud Storage-Bucket an, der zum Speichern von Binärobjekten für Snapshots vorgesehen ist.
  • PodSnapshotPolicy: Definiert, wie Snapshots manuell ausgelöst werden, wie oft sie gruppiert werden und welche Aufbewahrungsrichtlinien für sie gelten.
  • SandboxTemplate: Definiert den zugrunde liegenden Container, die Knotenselektoren und die Dienstkonten für die Ausführung der isolierten Sandbox-Arbeitslast.
  1. Erstellen Sie ein neues Verzeichnis für die Testclientdateien:

    mkdir test_client
    
  2. Wechseln Sie zum neuen Verzeichnis:

    cd test_client
    
  3. Erstellen Sie eine Datei mit dem Namen snapshot_storage_config.yaml. Mit dieser Konfiguration wird der Ziel-Cloud Storage-Bucket angegeben, in dem der Cluster den binären Pod-Snapshot-Zustand speichert:

    apiVersion: podsnapshot.gke.io/v1
    kind: PodSnapshotStorageConfig
    metadata:
      name: example-pod-snapshot-storage-config
    spec:
      snapshotStorageConfig:
        gcs:
          bucket: "$BUCKET_NAME"
    
  4. Ersetzen Sie den Platzhalter für die Umgebungsvariable in der Konfigurationsdatei:

    sed -i "s/\$BUCKET_NAME/$BUCKET_NAME/g" snapshot_storage_config.yaml
    
  5. Wenden Sie das Manifest für die Speicherkonfiguration an:

    kubectl apply -f snapshot_storage_config.yaml
    
  6. Warten Sie, bis die Speicherkonfiguration bereit ist:

    kubectl wait --for=condition=Ready podsnapshotstorageconfig/example-pod-snapshot-storage-config --timeout=60s
    
  7. Erstellen Sie eine Datei mit dem Namen snapshot_policy.yaml. Mit dieser Konfiguration wird eine Aufbewahrungsregel festgelegt, mit der maximal zwei Snapshots für Ihre Sandbox-Arbeitslast beibehalten werden. Der Triggertyp ist auf manual festgelegt. Dadurch kann die Clientanwendung Snapshots bei Bedarf steuern:

    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
    
  8. Wenden Sie das Snapshot-Richtlinienmanifest an:

    kubectl apply -f snapshot_policy.yaml
    
  9. Erstellen Sie eine Datei mit dem Namen python-counter-template.yaml. Diese Konfiguration definiert den Sandbox-Pod und weist ihm die Dienstkontoidentität snapshot-sa zu. Dadurch wird sichergestellt, dass die Sandbox sicher ausgeführt wird. In diesem Pod gibt die Sandbox-Anwendung (ein Python-Script) kontinuierlich einen inkrementierenden Zähler in die Containerlogs aus:

    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)
    
  10. Wenden Sie das Sandbox-Vorlagenmanifest an:

    kubectl apply -f python-counter-template.yaml
    

Clientanwendung erstellen

Erstellen Sie das Container-Image für die Clientanwendung und laden Sie es in Artifact Registry hoch.

  1. Erstellen Sie eine Datei mit dem Namen Dockerfile.client. In dieser Datei werden die Python-Laufzeitumgebung und die Abhängigkeiten für die Clientanwendung definiert:

    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. Erstellen Sie eine Datei mit dem Namen client_test.py. Dieses Skript verwaltet den Sandbox-Lebenszyklus und prüft, ob der Status nach dem Erstellen eines Snapshots erfolgreich fortgesetzt wird:

    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. Erstellen Sie das Client-Container-Image und laden Sie es in Artifact Registry hoch. Wenn in Ihrer Umgebung (z. B. Cloud Shell) Docker installiert ist, können Sie Docker verwenden, um das Image lokal zu erstellen. Wenn Sie in einer Umgebung ohne Docker arbeiten, können Sie Cloud Build verwenden, um das Image remote zu erstellen und zu übertragen:

    Docker

    1. Konfigurieren Sie die Docker-Authentifizierung für Artifact Registry:

      gcloud auth configure-docker "${LOCATION}-docker.pkg.dev"
      
    2. Erstellen Sie das Client-Container-Image lokal und übertragen Sie es per Push:

      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

    1. Erstellen Sie eine Datei mit dem Namen 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'
      
    2. Ersetzen Sie die Platzhalter für Umgebungsvariablen in der Konfigurationsdatei:

      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
      
    3. Erstellen Sie den Cloud Storage-Bucket für Cloud Build-Logs:

      gcloud storage buckets create "gs://${CLOUDBUILD_BUCKET_NAME}" \
          --location="${BUCKET_LOCATION}"
      
    4. Erforderliche Berechtigungen für das Cloud Build-Dienstkonto gewähren

      In den folgenden Befehlen wird das Compute Engine-Standarddienstkonto ($PROJECT_NUMBER-compute@developer.gserviceaccount.com) verwendet, das für die meisten Projekte die Standardeinstellung ist. Wenn in Ihrem Projekt das Legacy-Dienstkonto von Cloud Build verwendet wird, ersetzen Sie die E-Mail-Adresse des Mitglieds in den folgenden Befehlen durch $PROJECT_NUMBER@cloudbuild.gserviceaccount.com.

      Da Sie Ihrem Projekt zuvor in dieser Anleitung eine bedingte IAM-Bindung hinzugefügt haben, sollten Sie beim Hinzufügen dieser neuen Bindungen das Flag --condition=None angeben. So wird verhindert, dass gcloud pausiert, um eine interaktive Bestätigung anzufordern:

      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"
      
    5. Führen Sie den Build mit Cloud Build aus:

      gcloud builds submit --config cloudbuild.yaml
      

Testen

Stellen Sie die Clientanwendung bereit, um die Sandbox zu erstellen, einen Snapshot auszulösen und zu prüfen, ob der interne Zähler erfolgreich aus seinem gespeicherten Status fortgesetzt wird.

  1. Erstellen Sie eine Datei mit dem Namen client_sa.yaml. Dieses Manifest definiert das agent-sandbox-client-sa-Dienstkonto und die erforderlichen RBAC-Berechtigungen zum Verwalten benutzerdefinierter Sandbox-Ressourcen:

    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. Wenden Sie das Dienstkonto und das RBAC-Manifest an:

    kubectl apply -f client_sa.yaml
    
  3. Erstellen Sie eine Datei mit dem Namen client_pod.yaml. Mit diesem Manifest wird der Pod für die Clientanwendung mit dem vorgefertigten Container-Image erstellt:

    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. Ersetzen Sie die Platzhalter für Umgebungsvariablen im Manifest:

    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
    
  5. Wenden Sie das Pod-Manifest der Clientanwendung an:

    kubectl apply -f client_pod.yaml
    
  6. Streamen Sie die Pod-Logs, um den Ausführungsablauf zu prüfen:

    kubectl logs -f agent-sandbox-client-pod
    

Wenn der Test korrekt ausgeführt wird, sieht die Ausgabe in etwa so aus (hier zur besseren Lesbarkeit gekürzt):

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

Die Ausgabe zeigt, dass der Status der Sandbox beim Anhalten und Fortsetzen erhalten bleibt. Der Zähler wird angehalten, wenn die Sandbox pausiert und auf null skaliert wird. Er wird fortgesetzt, wenn die Sandbox wiederhergestellt wird. Ohne die Sperrung wäre der Zähler während des Sperrzeitraums weiter hochgezählt worden und die Anzahl wäre deutlich höher.

Ressourcen bereinigen

Damit Ihrem Google Cloud -Konto keine Gebühren in Rechnung gestellt werden, sollten Sie die von Ihnen erstellten Ressourcen löschen:

  1. Löschen Sie den GKE-Cluster. Dadurch werden auch der Knotenpool und alle darin enthaltenen Kubernetes-Dienstkonten gelöscht:

    gcloud beta container clusters delete ${CLUSTER_NAME} --location="${LOCATION}" --quiet
    
  2. Löschen Sie das Artifact Registry-Repository, um das Docker-Repository zu entfernen, das Sie für das Test-Image erstellt haben:

    gcloud artifacts repositories delete ${REPOSITORY_NAME} --location="${LOCATION}" --quiet
    
  3. Löschen Sie den Cloud Storage-Bucket und alle darin enthaltenen Snapshots. Dadurch werden die auf Bucket-Ebene angewendeten Workload Identity-IAM-Bindungen automatisch entfernt:

    gcloud storage rm --recursive "gs://${BUCKET_NAME}"
    
  4. Entfernen Sie die IAM-Bindung auf Projektebene für den GKE-Dienst-Agent:

    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. Wenn Sie Cloud Build anstelle von Docker zum Erstellen und Übertragen des Container-Images verwendet haben, löschen Sie den Logs-Bucket und entfernen Sie die Dienstkontoberechtigungen:

    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"
    

Nächste Schritte