管理 GKE 儲存空間上的 Agent Sandbox

本文件提供參考實作,說明如何根據代理的資料生命週期需求,管理 GKE 上 Agent Sandbox 的儲存空間。

請根據代理程式的資料生命週期需求,選擇下列其中一項設定:

如要進一步瞭解如何選擇儲存空間解決方案,請參閱「選擇 AI 代理工作負載的儲存空間」。

下列文件使用 dynamic-rwo StorageClass 自動選取磁碟類型,佈建與節點機型相容的磁碟,並在這些節點上排定 GKE Pod 的 Agent Sandbox。為確保 GKE 為代理的儲存空間佈建 Hyperdisk Balanced 磁碟區,您必須在相容機器系列 (例如 N4) 節點上的 GKE Pod 排定 Agent Sandbox,否則 GKE 會改用 pd-balanced。

本文使用 ReadWriteOnce (RWO) 存取權,實作私人隔離工作區資料存取模式。在這種模式下,代理程式會以私人隔離儲存目錄啟動,且只有該目錄具備讀取和寫入權限。

除非另有指定,否則本文件中的參考實作會使用直接建立沙箱,適用於可容忍多秒啟動延遲時間的代理。如要讓有狀態或時間點還原工作區的啟動延遲時間低於一秒,請務必使用 GKE 暖集區中的 Agent Sandbox。如要將儲存空間繫結至已認領的暖集區 Pod,必須使用自訂指令碼和具備特殊權限的 DaemonSet。如需實作參考,請參閱這個 GitHub 範例。

其他存取模式

如要支援其他存取模式,您可以在設定中修改磁碟區和快照定義:

  • 協作工作區:將 accessModes 變更為 ReadWriteMany,並使用支援 RWX 的 StorageClass,例如 Filestore Multishares (Enterprise) (enterprise-multishare-rwx)。
  • 探索分支工作區:將範本資料夾掛接為唯讀,並提供獨立的可寫入記事本。基礎範本必須使用支援多個唯讀連結的儲存空間,例如採用 ReadOnlyMany (ROX) 存取模式的 Hyperdisk ML,或採用 RWX 存取模式的 Filestore 多重共用。

事前準備

確認您有已安裝 Agent Sandbox 控制器的 GKE 叢集。如果沒有,請僅完成「在 GKE 上安裝 Agent Sandbox」的下列部分,然後返回本文件:

  1. 定義環境變數
  2. 建立 GKE 叢集
  3. 安裝 Agent Sandbox
  4. 套用建議的安全性政策

如果您已完成該文件的「部署沙箱環境」一節,請刪除該節建立的範例資源,確保節點有足夠容量容納本文件中的沙箱:

kubectl delete sandboxclaim sandbox-claim --ignore-not-found
kubectl delete sandboxwarmpool python-runtime-warmpool --ignore-not-found
kubectl delete sandbox sandbox-example-2 --ignore-not-found

設定有狀態工作區

請使用這個模式,保留代理檔案的最新狀態。如果代理必須在工作階段暫停或終止 (Agent Sandbox 刪除) 時保留狀態,並在工作階段啟用 (Agent Sandbox 重新建立) 時從最新狀態還原資料,這項功能就非常實用。

本節中的參考實作會直接建立沙箱,適用於可容忍多秒啟動延遲時間的代理。

這種方法會使用標準 GKE PersistentVolumeClaim (PVC) 資源,將沙箱連結至含有使用者資料的現有 PVC。

有狀態工作區模式會依序執行下列事件:

  1. 佈建:管理員或自動調度管理工具會使用確定性 ID (例如 pvc-agent-1),手動為每個代理工作階段佈建私人 PVC。
  2. 參照:在 Sandbox 資源中,使用 volumes 區塊內的 persistentVolumeClaim 欄位,指定現有磁碟區的確切 claimName。
  3. 延遲時間:建立沙箱時,GKE 必須動態將 Compute Engine 磁碟連接至節點 VM,這會導致標準延遲時間增加數秒。
  4. 持續性:工作階段終止 (刪除 Sandbox 資源) 時,GKE 會卸載磁碟,但不會刪除 PVC,確保下一個工作階段能保留最新狀態。

如要設定有狀態工作區,在工作階段之間保留資料,請完成下列子節中的步驟。

佈建永久工作區 (PVC)

建立使用確定性 ID (例如 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

部署 Sandbox 自訂資源,並參照確定性 PVC。

  1. 將下列資訊清單儲存為 sandbox-agent-1.yaml:

    apiVersion: agents.x-k8s.io/v1beta1
    kind: Sandbox
    metadata:
      name: sandbox-agent-1 # Traceable sandbox name
      namespace: default
    spec:
      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
    
  3. 等待沙箱準備就緒:

    kubectl wait sandbox sandbox-agent-1 \
        --for=condition=Ready \
        --timeout=300s
    

    GKE 會驗證節點容量並連接磁碟,這項作業需要幾秒鐘才能完成。容器會在使用者空間 gVisor 核心內初始化。在 Autopilot 叢集中,沙箱可能需要幾分鐘才能準備就緒,因為 GKE 可能需要為其建立節點。

寫入代理資料

將文字檔案寫入掛接的磁碟,模擬 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

kubectl wait sandbox sandbox-agent-1 \
    --for=condition=Ready \
    --timeout=300s

磁碟會重新連接 (產生連接延遲),容器也會啟動。

確認資料是否保留

檢查新建立的沙箱容器,確認先前的階段資料已保留。

# 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 ${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

建立 VolumeSnapshotClass,指定 CSI 驅動程式和刪除政策。如果是 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/v1beta1
    kind: Sandbox
    metadata:
      name: agent-session-v1
      namespace: default
    spec:
      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. 等待沙箱準備就緒,然後寫入狀態檔案。sync 指令會將寫入內容清除至磁碟,因此下一節的快照會包含檔案內容:

    kubectl wait sandbox agent-session-v1 \
        --for=condition=Ready \
        --timeout=300s
    
    POD_NAME=agent-session-v1
    kubectl exec ${POD_NAME} -- sh -c "echo 'Point-in-Time Snapshot - v1' > /workspace/state.txt && sync"
    

封存歷來狀態 (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
    
  3. 等待快照準備就緒:

    kubectl wait volumesnapshot agent-session-v1-snapshot \
        --for=jsonpath='{.status.readyToUse}'=true \
        --timeout=600s
    

從快照還原磁碟區

部署新的 PVC,並將其 dataSource 指向 CSI VolumeSnapshot。

  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/v1beta1
    kind: Sandbox
    metadata:
      name: agent-session-v2-restored
      namespace: default
    spec:
      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
    
  3. 等待沙箱準備就緒:

    kubectl wait sandbox agent-session-v2-restored \
        --for=condition=Ready \
        --timeout=600s
    

    這個沙箱可能需要較長時間才能準備就緒,因為 GKE 會在快照準備就緒後,從快照建立磁碟。

驗證持續性和還原

確認代理可以讀取歷來資料。

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 時,不需要保留任何資料。

設定一秒內啟動

在 GKE 暖集區使用 Agent Sandbox,在背景預先佈建空白磁碟區。

定義 SandboxTemplate 資源

在 volumeClaimTemplate 區塊中定義臨時儲存空間備份。

  1. 將下列資訊清單儲存為 stateless-template.yaml:

    apiVersion: extensions.agents.x-k8s.io/v1beta1
    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
    

啟動 SandboxWarmPool 資源

  1. 將下列資訊清單儲存為 stateless-warmpool.yaml:

    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxWarmPool
    metadata:
      name: stateless-warmpool
      namespace: default
    spec:
      replicas: 2 # Keep two 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
    
  3. 等待暖集區的沙箱準備就緒:

    kubectl wait sandboxwarmpool stateless-warmpool \
        --for=jsonpath='{.status.readyReplicas}'=2 \
        --timeout=600s
    

    如果您在集區的沙箱準備就緒前建立 SandboxClaim 資源,控制器可能會為要求建立新的沙箱,而不是從集區指派沙箱。在 Autopilot 叢集中,沙箱可能需要幾分鐘才能準備就緒,因為 GKE 可能需要為沙箱建立節點。

建立 SandboxClaim 資源

定義 SandboxClaim 資源,在使用者開始工作階段時觸發。

  1. 將下列資訊清單儲存為 stateless-sandbox-claim.yaml:

    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxClaim
    metadata:
      name: agent-1-claim
    spec:
      warmPoolRef:
        name: stateless-warmpool
    
  2. 套用資訊清單:

    kubectl apply -f stateless-sandbox-claim.yaml
    

確認執行時間不到一秒

等待宣告準備就緒,擷取 Agent Sandbox Pod 名稱,然後確認 /workspace 目錄已掛接並可立即使用:

kubectl wait sandboxclaim agent-1-claim --for=condition=Ready --timeout=300s
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

清除所用資源

刪除 SandboxWarmPool 和 SandboxTemplate 資源:

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/v1beta1
    kind: Sandbox
    metadata:
      name: sandbox-direct-stateless
      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
          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 執行後,按下 Control+C 鍵即可停止監控。

擷取 Pod 名稱,並確認 /workspace 目錄可用:

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

終止代理工作階段

刪除 Sandbox 資源,自動終止 Pod 並刪除其臨時儲存空間:

kubectl delete sandbox sandbox-direct-stateless

後續步驟