Gérer le stockage Agent Sandbox

Ce document fournit des implémentations de référence pour gérer le stockage des bacs à sable d'agents en fonction des besoins liés au cycle de vie des données de vos agents.

En fonction des besoins du cycle de vie des données de vos agents, choisissez l'une des configurations suivantes :

Pour en savoir plus sur le choix d'une solution de stockage, consultez Choisir un stockage pour les charges de travail agentiques d'IA.

Le document suivant utilise la StorageClass dynamic-rwo pour la sélection automatisée du type de disque afin de provisionner des disques compatibles avec les types de machines des nœuds sur lesquels les pods Agent Sandbox sont planifiés. Pour vous assurer que GKE provisionne des volumes Hyperdisk Balanced pour le stockage de vos agents, vous devez planifier vos bacs à sable d'agents sur les nœuds des familles de machines compatibles, telles que N4. Sinon, GKE revient à pd-balanced.

Ce document implémente le mode d'accès aux données Private Isolated Workspace à l'aide de l'accès ReadWriteOnce (RWO). Dans ce mode, un agent démarre avec un répertoire de stockage isolé et privé auquel il a seul accès en lecture et en écriture.

Sauf indication contraire, les implémentations de référence de ce document utilisent la création directe de bac à sable, qui s'applique aux agents qui tolèrent une latence de démarrage de plusieurs secondes. Pour obtenir une latence de démarrage inférieure à une seconde pour les espaces de travail avec état ou de restauration à un moment donné, vous devez utiliser les pools de préchauffage GKE Agent Sandbox. Pour associer le stockage à un pod de pool de préchauffage revendiqué, vous devez utiliser des scripts personnalisés et un DaemonSet privilégié. Pour obtenir une implémentation de référence, consultez cet exemple GitHub.

Autres modes d'accès

Pour prendre en charge d'autres modes d'accès, vous pouvez modifier les définitions de volume et d'instantané dans les configurations :

  • Espace de travail collaboratif : remplacez accessModes par ReadWriteMany et utilisez une StorageClass compatible RWX, telle que Filestore Multishares (Enterprise) (enterprise-multishare-rwx).
  • Espace de travail pour la création de branches d'exploration : installez le dossier de modèle en lecture seule et fournissez un bloc-notes modifiable distinct. Pour le modèle de base, vous devez utiliser un stockage compatible avec plusieurs associations en lecture seule, comme Hyperdisk ML avec le mode d'accès ReadOnlyMany (ROX) ou Filestore Multishares avec le mode d'accès RWX.

Avant de commencer

Activez Agent Sandbox dans votre cluster.

Configurer un espace de travail avec état

Utilisez ce modèle pour conserver le dernier état des fichiers d'un agent. Cela est utile lorsque votre agent doit conserver l'état lorsque la session de l'agent est suspendue ou terminée (le bac à sable de l'agent est supprimé) et restaurer les données à partir du dernier état lorsque la session de l'agent est activée (le bac à sable de l'agent est recréé).

L'implémentation de référence de cette section utilise la création directe de bac à sable et s'applique aux agents qui tolèrent une latence de démarrage de plusieurs secondes.

Cette approche utilise des ressources PersistentVolumeClaim (PVC) GKE standards pour associer un bac à sable à un PVC préexistant contenant les données d'un utilisateur.

Le modèle d'espace de travail avec état suit cette séquence d'événements :

  1. Provisionnement : l'administrateur ou l'orchestrateur provisionne manuellement un PVC privé pour chaque session d'agent à l'aide d'un identifiant déterministe (par exemple, pvc-agent-1).
  2. Référencer : dans la ressource Sandbox, vous utilisez le champ persistentVolumeClaim dans le bloc volumes pour spécifier le claimName exact du volume existant.
  3. Latence : lorsque le bac à sable est créé, GKE doit associer dynamiquement le disque Compute Engine à la VM du nœud, ce qui entraîne un délai standard de plusieurs secondes.
  4. Persistance : lorsque la session se termine (suppression du bac à sable), GKE détache le disque, mais ne détruit pas le PVC, ce qui permet de s'assurer que le dernier état est conservé pour la prochaine session.

Pour configurer un espace de travail avec état qui conserve les données entre les sessions, suivez les étapes décrites dans les sous-sections suivantes.

Provisionner un espace de travail persistant (PVC)

Créez un PersistentVolumeClaim (PVC) privé qui utilise un identifiant déterministe, tel que pvc-agent-1.

  1. Enregistrez le manifeste suivant sous le nom pvc-agent-1.yaml :

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: pvc-agent-1 # Derived directly from the deterministic assignment ID
      namespace: default
    spec:
      accessModes:
        - ReadWriteOnce
      storageClassName: dynamic-rwo # Selects disk type compatible with the node machine family
      resources:
        requests:
          storage: 10Gi
    
  2. Appliquez le fichier manifeste :

    kubectl apply -f pvc-agent-1.yaml
    

Comme la classe de stockage utilise la liaison de volume dynamique, le disque n'est pas encore associé à un nœud. Il reste à l'état Pending jusqu'à ce qu'un pod le demandant soit planifié.

Déployer Agent Sandbox

Déployez la ressource personnalisée Sandbox en faisant référence au PVC déterministe.

  1. Enregistrez le manifeste suivant sous le nom sandbox-agent-1.yaml :

    apiVersion: agents.x-k8s.io/v1alpha1
    kind: Sandbox
    metadata:
      name: sandbox-agent-1 # Traceable sandbox name
      namespace: default
    spec:
      replicas: 1
      podTemplate:
        spec:
          runtimeClassName: gvisor # Required
          automountServiceAccountToken: false # Required
          securityContext:
            runAsNonRoot: true # Required
            runAsUser: 1000
            fsGroup: 1000 # Grant group access to the volume
          nodeSelector:
            sandbox.gke.io/runtime: gvisor # Required
          tolerations:
          - key: "sandbox.gke.io/runtime"
            value: "gvisor"
            effect: "NoSchedule" # Required
          containers:
          - name: agent
            image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0
            ports:
            - containerPort: 8888
            volumeMounts:
            - name: workspace-disk
              mountPath: /workspace # Mounts the private disk into the container
            resources:
              limits:
                cpu: "500m"
                memory: "1Gi" # Required
            securityContext:
              capabilities:
                drop: ["ALL"] # Required
          volumes:
          - name: workspace-disk
            persistentVolumeClaim:
              claimName: pvc-agent-1 # Binds this specific Sandbox to Agent 1's PVC
          restartPolicy: OnFailure
    
  2. Appliquez le fichier manifeste :

    kubectl apply -f sandbox-agent-1.yaml
    

GKE vérifie la capacité du nœud et associe le disque, ce qui prend quelques secondes. Le conteneur s'initialise dans un noyau gVisor de l'espace utilisateur.

Écrire des données à partir de l'agent

Simulez un agent d'IA actif qui exécute des modifications de fichiers dans son espace de travail en écrivant un fichier texte sur le disque monté.

# Set the active Pod name
POD_NAME=sandbox-agent-1

# Write a state file to the persistent directory
kubectl exec $POD_NAME -- sh -c "echo 'Workspace State Saved - Agent 1' > /workspace/modified_data.txt"

# Confirm the file exists on the disk
kubectl exec $POD_NAME -- cat /workspace/modified_data.txt

Mettre fin à la session de l'agent

Pour simuler la réduction ou l'arrêt de la session lorsque l'agent est inactif, supprimez la ressource Sandbox, mais conservez le stockage sous-jacent.

kubectl delete sandbox sandbox-agent-1

GKE démonte et dissocie le disque. Le PVC pvc-agent-1 est conservé, ce qui préserve les données.

Réactiver la session de l'agent

Pour réactiver la session, redéployez une ressource Sandbox qui référence le même PVC.

kubectl apply -f sandbox-agent-1.yaml

Le disque est réassocié (ce qui entraîne le délai d'association) et le conteneur démarre.

Vérifier la conservation des données

Inspectez le conteneur sandbox que vous venez de créer pour vérifier que les données de la session précédente ont été conservées.

# Set the active Pod name of the new session
NEW_POD_NAME=sandbox-agent-1

# Read the file from the newly booted sandbox
kubectl exec -it $NEW_POD_NAME -- cat /workspace/modified_data.txt

Le résultat doit afficher Workspace State Saved - Agent 1.

Effectuer un nettoyage des ressources

Supprimez le bac à sable de l'agent et la revendication de volume persistant associée :

kubectl delete sandbox sandbox-agent-1
kubectl delete pvc pvc-agent-1

Configurer une restauration à un moment précis et un transfert de propriété

Utilisez ce modèle pour cloner des ensembles de données afin d'exécuter des tests parallèles, de déboguer ou de travailler de manière indépendante. L'espace de travail d'un agent est initialisé à partir d'un ensemble de données historiques (ou d'un état partagé), ce qui permet d'enregistrer les modifications ultérieures dans une couche privée et modifiable distincte, sans modifier le modèle de base.

L'implémentation de référence de cette section utilise la création directe de bac à sable et s'applique aux agents qui tolèrent une latence de démarrage de plusieurs secondes. Cette approche repose sur l'orchestrateur pour provisionner de manière dynamique de nouvelles PersistentVolumeClaims (PVC) à partir d'anciens VolumeSnapshots avant de lancer une nouvelle session sandbox.

Créer la classe VolumeSnapshotClass

Créez une VolumeSnapshotClass qui spécifie le pilote CSI et la règle de suppression. Pour Hyperdisk, utilisez le pilote pd.csi.storage.gke.io.

  1. Enregistrez le manifeste suivant sous le nom 1-snapshot-class.yaml :

    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshotClass
    metadata:
      name: standard-rwo-snapshot
    driver: pd.csi.storage.gke.io
    deletionPolicy: Delete
    
  2. Appliquez le fichier manifeste :

    kubectl apply -f 1-snapshot-class.yaml
    

Provisionner l'espace de travail initial

Créez un volume dans lequel l'agent effectuera son travail initial.

  1. Enregistrez le manifeste suivant sous le nom 2-source-pvc.yaml :

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: agent-source-pvc
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: dynamic-rwo
      resources:
        requests:
          storage: 10Gi
    
  2. Appliquez le fichier manifeste :

    kubectl apply -f 2-source-pvc.yaml
    

Générer des données d'état

Déployez un pod bac à sable pour écrire des données sur le volume.

  1. Enregistrez le manifeste suivant sous le nom 3-source-sandbox.yaml :

    apiVersion: agents.x-k8s.io/v1alpha1
    kind: Sandbox
    metadata:
      name: agent-session-v1
      namespace: default
    spec:
      replicas: 1
      podTemplate:
        spec:
          runtimeClassName: gvisor
          automountServiceAccountToken: false # Required
          securityContext:
            runAsNonRoot: true # Required
            runAsUser: 1000
            fsGroup: 1000 # Grant group access to the volume
          nodeSelector:
            sandbox.gke.io/runtime: gvisor # Required
          tolerations:
          - key: "sandbox.gke.io/runtime"
            value: "gvisor"
            effect: "NoSchedule" # Required
          containers:
          - name: agent
            image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0
            ports:
            - containerPort: 8888
            volumeMounts:
            - name: workspace
              mountPath: /workspace
            resources:
              limits:
                cpu: "500m"
                memory: "1Gi" # Required
            securityContext:
              capabilities:
                drop: ["ALL"] # Required
          volumes:
          - name: workspace
            persistentVolumeClaim:
              claimName: agent-source-pvc
          restartPolicy: OnFailure
    
  2. Appliquez le fichier manifeste :

    kubectl apply -f 3-source-sandbox.yaml
    
  3. Attendez que le pod soit en cours d'exécution, puis écrivez un fichier d'état :

    POD_NAME=agent-session-v1
    kubectl exec $POD_NAME -- sh -c "echo 'Point-in-Time Snapshot - v1' > /workspace/state.txt"
    

Archiver l'état historique (CSI VolumeSnapshot)

Déclenchez un VolumeSnapshot CSI pour figer l'état actuel. Lorsque vous créez un instantané, suivez les bonnes pratiques pour les instantanés de disque.

  1. Enregistrez le manifeste suivant sous le nom 4-volume-snapshot.yaml :

    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshot
    metadata:
      name: agent-session-v1-snapshot
    spec:
      volumeSnapshotClassName: standard-rwo-snapshot
      source:
        persistentVolumeClaimName: agent-source-pvc
    
  2. Appliquez le fichier manifeste :

    kubectl apply -f 4-volume-snapshot.yaml
    

Restaurer le volume à partir de l'instantané

Déployez une nouvelle PVC avec son dataSource pointant vers le VolumeSnapshot CSI.

  1. Enregistrez le manifeste suivant sous le nom 5-restored-pvc.yaml :

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: agent-restored-pvc
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: dynamic-rwo
      dataSource:
        name: agent-session-v1-snapshot
        kind: VolumeSnapshot
        apiGroup: snapshot.storage.k8s.io
      resources:
        requests:
          storage: 10Gi
    
  2. Appliquez le fichier manifeste :

    kubectl apply -f 5-restored-pvc.yaml
    

Lancer la session Agent Sandbox restaurée

Provisionnez une nouvelle ressource Sandbox qui référence le PVC nouvellement restauré.

  1. Enregistrez le manifeste suivant sous le nom 6-restored-sandbox.yaml :

    apiVersion: agents.x-k8s.io/v1alpha1
    kind: Sandbox
    metadata:
      name: agent-session-v2-restored
      namespace: default
    spec:
      replicas: 1
      podTemplate:
        spec:
          runtimeClassName: gvisor
          automountServiceAccountToken: false # Required
          securityContext:
            runAsNonRoot: true # Required
            runAsUser: 1000
            fsGroup: 1000 # Grant group access to the volume
          nodeSelector:
            sandbox.gke.io/runtime: gvisor # Required
          tolerations:
          - key: "sandbox.gke.io/runtime"
            value: "gvisor"
            effect: "NoSchedule" # Required
          containers:
          - name: agent
            image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0
            ports:
            - containerPort: 8888
            volumeMounts:
            - name: workspace
              mountPath: /workspace
            resources:
              limits:
                cpu: "500m"
                memory: "1Gi" # Required
            securityContext:
              capabilities:
                drop: ["ALL"] # Required
          volumes:
          - name: workspace
            persistentVolumeClaim:
              claimName: agent-restored-pvc
          restartPolicy: OnFailure
    
  2. Appliquez le fichier manifeste :

    kubectl apply -f 6-restored-sandbox.yaml
    

Vérifier la persistance et la restauration

Vérifiez que l'agent peut lire les données historiques.

NEW_POD_NAME=agent-session-v2-restored
kubectl exec $NEW_POD_NAME -- cat /workspace/state.txt

Résultat attendu : Point-in-Time Snapshot - v1

Effectuer un nettoyage des ressources

Supprimez les bacs à sable de l'agent, les PVC et le VolumeSnapshot :

kubectl delete sandbox agent-session-v1
kubectl delete sandbox agent-session-v2-restored
kubectl delete pvc agent-source-pvc
kubectl delete pvc agent-restored-pvc
kubectl delete volumesnapshot agent-session-v1-snapshot
kubectl delete volumesnapshotclass standard-rwo-snapshot

Configurer un espace de travail éphémère

Utilisez le modèle d'espace de travail éphémère lorsqu'un agent a besoin d'un volume de stockage pour stocker des fichiers temporaires pendant qu'il est actif. Aucune donnée ne doit être conservée lors de la suppression du bac à sable de l'agent.

Configurer avec un démarrage en moins d'une seconde

Utilisez les pools de préchauffage du bac à sable de l'agent pour préprovisionner des volumes vides en arrière-plan.

Définir le SandboxTemplate

Définissez le stockage éphémère de sauvegarde dans le bloc volumeClaimTemplate.

  1. Enregistrez le manifeste suivant sous le nom stateless-template.yaml :

    apiVersion: extensions.agents.x-k8s.io/v1alpha1
    kind: SandboxTemplate
    metadata:
      name: stateless-sandbox-template
      namespace: default
    spec:
      podTemplate:
        spec:
          runtimeClassName: gvisor
          automountServiceAccountToken: false
          securityContext:
            runAsNonRoot: true
            runAsUser: 1000
            fsGroup: 1000 # Grant group access to the volume
          nodeSelector:
            sandbox.gke.io/runtime: gvisor
          tolerations:
          - key: "sandbox.gke.io/runtime"
            value: "gvisor"
            effect: "NoSchedule"
          containers:
          - name: agent
            image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0
            ports:
            - containerPort: 8888
            volumeMounts:
            - name: ephemeral-disk
              mountPath: /workspace
            resources:
              limits:
                cpu: "500m"
                memory: "1Gi" # Required
            securityContext:
              capabilities:
                drop: ["ALL"] # Required
      volumeClaimTemplates:
      - metadata:
          name: ephemeral-disk
        spec:
          accessModes: ["ReadWriteOnce"]
          storageClassName: dynamic-rwo # Selects disk type compatible with node machine family
          resources:
            requests:
              storage: 10Gi
    

Lancer le pool de préchauffage du bac à sable

  1. Enregistrez le manifeste suivant sous le nom stateless-warmpool.yaml :

    apiVersion: extensions.agents.x-k8s.io/v1alpha1
    kind: SandboxWarmPool
    metadata:
      name: stateless-warmpool
      namespace: default
    spec:
      replicas: 5 # Keep five standby Pods with pre-attached empty disks
      sandboxTemplateRef:
        name: stateless-sandbox-template
    
  2. Appliquez les deux fichiers manifestes :

    kubectl apply -f stateless-template.yaml
    kubectl apply -f stateless-warmpool.yaml
    

Revendiquer le bac à sable

Définissez un SandboxClaim qui se déclenche lorsqu'un utilisateur démarre une session.

  1. Enregistrez le manifeste suivant sous le nom stateless-sandbox-claim.yaml :

    apiVersion: extensions.agents.x-k8s.io/v1alpha1
    kind: SandboxClaim
    metadata:
      name: agent-1-claim
    spec:
      sandboxTemplateRef:
        name: stateless-sandbox-template
    
  2. Appliquez le fichier manifeste :

    kubectl apply -f stateless-sandbox-claim.yaml
    

Vérifier l'exécution en moins d'une seconde

Capturez le nom du pod Agent Sandbox et vérifiez que le répertoire /workspace est monté et prêt à être utilisé immédiatement :

export POD_NAME=$(kubectl get sandboxclaim agent-1-claim -o jsonpath='{.status.sandbox.name}')
kubectl exec $POD_NAME -- ls -la /workspace

Mettre fin à la session de l'agent

Pour mettre fin à la session de l'agent et libérer le bac à sable revendiqué, supprimez la ressource SandboxClaim :

kubectl delete sandboxclaim agent-1-claim

Effectuer un nettoyage des ressources

Supprimez le pool de préchauffage et le modèle du bac à sable :

kubectl delete sandboxwarmpool stateless-warmpool
kubectl delete sandboxtemplate stateless-sandbox-template

Configurer avec un démarrage de plusieurs secondes

Pour implémenter un espace de travail éphémère qui tolère une latence de plusieurs secondes, utilisez la création directe de bac à sable d'agent sans pool de préchauffage.

Définir un bac à sable Agent Sandbox sans état

  1. Enregistrez le manifeste suivant sous le nom sandbox-direct-stateless.yaml :

    apiVersion: agents.x-k8s.io/v1alpha1
    kind: Sandbox
    metadata:
      name: sandbox-direct-stateless
      namespace: default
    spec:
      replicas: 1
      podTemplate:
        spec:
          runtimeClassName: gvisor
          automountServiceAccountToken: false
          securityContext:
            runAsNonRoot: true
            runAsUser: 1000
            fsGroup: 1000 # Grant group access to the volume
          nodeSelector:
            sandbox.gke.io/runtime: gvisor
          tolerations:
          - key: "sandbox.gke.io/runtime"
            value: "gvisor"
            effect: "NoSchedule"
          containers:
          - name: agent
            image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0
            ports:
            - containerPort: 8888
            volumeMounts:
            - name: ephemeral-disk
              mountPath: /workspace
            resources:
              limits:
                cpu: "500m"
                memory: "1Gi" # Required
            securityContext:
              capabilities:
                drop: ["ALL"] # Required
          restartPolicy: OnFailure
      volumeClaimTemplates:
      - metadata:
          name: ephemeral-disk
        spec:
          accessModes: ["ReadWriteOnce"]
          storageClassName: dynamic-rwo
          resources:
            requests:
              storage: 10Gi
    

Déployer Agent Sandbox

Pour provisionner dynamiquement le disque et l'associer au nœud planifié, appliquez le fichier manifeste :

kubectl apply -f sandbox-direct-stateless.yaml

Vérifier la latence et l'exécution du démarrage

Surveillez l'état du pod pour observer le délai d'association avant que le pod passe à l'état Running :

kubectl get pods -w

Une fois le pod en cours d'exécution, capturez son nom et vérifiez que le répertoire /workspace est disponible :

POD_NAME=sandbox-direct-stateless
kubectl exec $POD_NAME -- ls -la /workspace

Mettre fin à la session de l'agent

Supprimez la ressource Sandbox pour arrêter automatiquement le pod et détruire son stockage éphémère :

kubectl delete sandbox sandbox-direct-stateless

Étapes suivantes