Agent Sandbox のストレージを管理する

このドキュメントでは、エージェントのデータライフサイクルのニーズに合わせて調整された Agent Sandbox のストレージを管理するためのリファレンス実装について説明します。

エージェントのデータライフサイクルのニーズに応じて、次のいずれかの構成を選択します。

ストレージ ソリューションの選択の詳細については、AI エージェント ワークロードのストレージを選択するをご覧ください。

次のドキュメントでは、dynamic-rwo StorageClass を使用してディスクタイプの自動 選択 を行い、Agent Sandbox Pod がスケジュールされているノードのマシンタイプと互換性のあるディスクをプロビジョニングします。GKE がエージェントのストレージに Hyperdisk Balanced ボリュームをプロビジョニングするようにするには、 互換性のあるマシン ファミリーのノードで Agent Sandbox をスケジュールする必要があります。そうしないと、GKE はpd-balancedにフォールバックします。

このドキュメントでは、ReadWriteOnce(RWO)アクセスを使用して、プライベート分離ワークスペース データアクセス モードを実装します。このモードでは、エージェントは、読み取りと書き込みのアクセス権を持つプライベート分離ストレージ ディレクトリで起動します。

特に指定がない限り、このドキュメントのリファレンス実装では、数秒の起動レイテンシを許容できるエージェントに適用可能な直接サンドボックス作成を使用します。ステートフル ワークスペースまたはポイントインタイム復元ワークスペースで 1 秒未満の起動レイテンシを実現するには、GKE Agent Sandbox ウォームプールを使用する必要があります。ストレージを要求されたウォームプール Pod にバインドするには、カスタム スクリプトと特権 DaemonSet が必要です。リファレンス実装については、こちらの GitHub の例をご覧ください。

代替アクセスモード

代替アクセスモードをサポートするには、構成でボリュームとスナップショットの定義を変更します。

  • コラボレーション ワークスペース: accessModesReadWriteMany に変更し、 Filestore マルチシェア(Enterprise)(enterprise-multishare-rwx)などの RWX 対応の StorageClass を使用します。
  • 探索ブランチ ワークスペース: テンプレート フォルダを読み取り専用としてマウントし、書き込み可能な別のスクラッチパッドを提供します。 ベース テンプレートには、複数の読み取り専用 アタッチをサポートするストレージを使用する必要があります。たとえば、Hyperdisk ML(ROX) アクセス モードの ReadOnlyManyや RWX アクセス モードの Filestore マルチシェアなどです。

始める前に

クラスタで Agent Sandbox を有効にします

ステートフル ワークスペースを構成する

このパターンを使用して、エージェントのファイルの最新の状態を保持します。エージェント セッションが一時停止または終了(Agent Sandbox が削除)されたときにエージェントが状態を保持し、エージェント セッションがアクティブ化(Agent Sandbox が再作成)されたときに最新の状態からデータを復元する必要がある場合に便利です。

このセクションのリファレンス実装では、直接サンドボックス作成を使用します。これは、数秒の起動レイテンシを許容できるエージェントに適用できます。

このアプローチでは、標準の GKE PersistentVolumeClaim(PVC)リソースを使用して、サンドボックスをユーザーのデータを含む既存の PVC にリンクします。

ステートフル ワークスペース パターンは、次の一連のイベントに従います。

  1. プロビジョニング: 管理者またはオーケストレータは、決定論的識別子( たとえば、 pvc-agent-1)を使用して、各エージェント セッションに プライベート PVC を手動でプロビジョニングします。
  2. 参照: Sandbox リソースで、 persistentVolumeClaim ブロック内の volumes フィールドを使用して、既存のボリュームの正確な claimName を指定します。
  3. レイテンシ: サンドボックスが作成されると、GKE は Compute Engine ディスクをノード VM に動的にアタッチする必要があります。 これにより、標準の数秒の遅延が発生します。
  4. 永続性: セッションの終了時(サンドボックスの削除)に、 GKE はディスクを切断しますが、PVC は破棄しません。これにより、 次のセッションで最新の状態が保持されます。

セッション間でデータを保持するステートフル ワークスペースを構成するには、次のサブセクションの手順を完了します。

永続ワークスペース(PVC)をプロビジョニングする

pvc-agent-1 などの決定論的識別子を使用するプライベート PersistentVolumeClaim(PVC)を作成します。

  1. 次のマニフェストを 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. 次のようにマニフェストを適用します。

    kubectl apply -f pvc-agent-1.yaml
    

ストレージ クラスは動的ボリューム バインディングを使用するため、ディスクはまだどのノードにもアタッチされていません。リクエストする Pod がスケジュールされるまで、Pending 状態のままになります。

Agent Sandbox をデプロイする

決定論的 PVC を参照して、Sandbox カスタム リソースをデプロイします。

  1. 次のマニフェストを 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. 次のようにマニフェストを適用します。

    kubectl apply -f sandbox-agent-1.yaml
    

GKE はノード容量を確認し、ディスクをアタッチします。これには数秒かかります。コンテナはユーザー空間の gVisor カーネル内で初期化されます。

エージェントからデータを書き込む

マウントされたディスクにテキスト ファイルを書き込んで、ワークスペース内でファイル変更を実行するアクティブな AI エージェントをシミュレートします。

# 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

エージェント セッションを終了する

エージェントがアイドル状態になったときにスケールダウンまたはセッションを終了するのをシミュレートするには、Sandbox リソースを削除しますが、基盤となるストレージは保持します。

kubectl delete sandbox sandbox-agent-1

GKE はディスクをマウント解除して切断します。pvc-agent-1 PVC は残り、データが保持されます。

エージェント セッションを再アクティブ化する

セッションを再アクティブ化するには、同じ PVC を参照する新しい Sandbox リソースを再デプロイします。

kubectl apply -f sandbox-agent-1.yaml

ディスクが再アタッチされ(アタッチの遅延が発生します)、コンテナが起動します。

データの保持を確認する

新しく作成したサンドボックス コンテナを調べて、前のセッションのデータが保持されていることを確認します。

# 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

出力には Workspace State Saved - Agent 1 が表示されます。

リソースのクリーンアップ

Agent Sandbox と関連する永続ボリュームのクレームを削除します。

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

ポイントインタイム復元と所有権の転送を構成する

このパターンを使用して、並列実験、デバッグ、独立した作業を行うためのデータセットをクローンします。エージェントのワークスペースは履歴データセット(または共有状態)から初期化され、後続の変更はベース テンプレートを変更せずに、別のプライベート書き込み可能レイヤに保存されます。

このセクションのリファレンス実装では、直接サンドボックス作成を使用します。これは、数秒の起動レイテンシを許容できるエージェントに適用できます。このアプローチでは、オーケストレータが新しいサンドボックス セッションを開始する前に、履歴 VolumeSnapshot から新しい PersistentVolumeClaim(PVC)を動的にプロビジョニングします。

VolumeSnapshotClass を作成する

CSI ドライバと削除ポリシーを指定する VolumeSnapshotClass を作成します。 Hyperdisk の場合は、pd.csi.storage.gke.io ドライバを使用します。

  1. 次のマニフェストを 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. 次のようにマニフェストを適用します。

    kubectl apply -f 1-snapshot-class.yaml
    

初期ワークスペースをプロビジョニングする

エージェントが最初の作業を行うボリュームを作成します。

  1. 次のマニフェストを 2-source-pvc.yaml として保存します。

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: agent-source-pvc
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: dynamic-rwo
      resources:
        requests:
          storage: 10Gi
    
  2. 次のようにマニフェストを適用します。

    kubectl apply -f 2-source-pvc.yaml
    

状態データを生成する

サンドボックス Pod をデプロイして、ボリュームにデータを書き込みます。

  1. 次のマニフェストを 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. 次のようにマニフェストを適用します。

    kubectl apply -f 3-source-sandbox.yaml
    
  3. Pod が実行されるまで待ってから、状態ファイルを書き込みます。

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

履歴状態をアーカイブする(CSI VolumeSnapshot)

CSI VolumeSnapshot をトリガーして、現在の状態をフリーズします。スナップショットを作成する場合は、ディスク スナップショットのベスト プラクティスに従ってください。

  1. 次のマニフェストを 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. 次のようにマニフェストを適用します。

    kubectl apply -f 4-volume-snapshot.yaml
    

スナップショットからボリュームを復元する

dataSource が CSI VolumeSnapshot を指す新しい PVC をデプロイします。

  1. 次のマニフェストを 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. 次のようにマニフェストを適用します。

    kubectl apply -f 5-restored-pvc.yaml
    

復元された Agent Sandbox セッションを開始する

新しく復元された PVC を参照する新しい Sandbox リソースをプロビジョニングします。

  1. 次のマニフェストを 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. 次のようにマニフェストを適用します。

    kubectl apply -f 6-restored-sandbox.yaml
    

永続性と復元を確認する

エージェントが履歴データを読み取れることを確認します。

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

予想される出力: Point-in-Time Snapshot - v1

リソースのクリーンアップ

Agent Sandbox、PVC、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

エフェメラル ワークスペースを構成する

エージェントがアクティブなときに一時ファイルを保存するためのストレージ ボリュームが必要な場合は、エフェメラル ワークスペース パターンを使用します。Agent Sandbox の削除時にデータを保持する必要はありません。

1 秒未満の起動で構成する

Agent Sandbox ウォームプールを使用して、バックグラウンドで空のボリュームを事前プロビジョニングします。

SandboxTemplate を定義する

volumeClaimTemplate ブロック内で、エフェメラル ストレージのバッキングを定義します。

  1. 次のマニフェストを 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
    

サンドボックス ウォームプールを起動する

  1. 次のマニフェストを 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. 両方のマニフェストを適用します。

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

サンドボックスを要求する

ユーザーがセッションを開始したときにトリガーされる SandboxClaim を定義します。

  1. 次のマニフェストを 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. 次のようにマニフェストを適用します。

    kubectl apply -f stateless-sandbox-claim.yaml
    

1 秒未満の実行を確認する

Agent Sandbox Pod 名を取得し、/workspace ディレクトリがマウントされ、すぐに使用できることを確認します。

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

エージェント セッションを終了する

エージェント セッションを終了して、要求されたサンドボックスを解放するには、SandboxClaim リソースを削除します。

kubectl delete sandboxclaim agent-1-claim

リソースのクリーンアップ

サンドボックス ウォームプールとサンドボックス テンプレートを削除します。

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

数秒の起動で構成する

数秒のレイテンシを許容するエフェメラル ワークスペースを実装するには、ウォームプールなしで Agent Sandbox を直接作成します。

ステートレス Agent Sandbox を定義する

  1. 次のマニフェストを 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
    

Agent Sandbox をデプロイする

ディスクを動的にプロビジョニングして、スケジュールされたノードにアタッチするには、マニフェストを適用します。

kubectl apply -f sandbox-direct-stateless.yaml

起動レイテンシと実行を確認する

Pod のステータスをモニタリングして、Pod が Running 状態に移行する前のアタッチの遅延を確認します。

kubectl get pods -w

Pod が実行されたら、Pod 名を取得し、/workspace ディレクトリが使用可能であることを確認します。

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

エージェント セッションを終了する

Sandbox リソースを削除して、Pod を自動的に終了し、エフェメラル ストレージを破棄します。

kubectl delete sandbox sandbox-direct-stateless

次のステップ