이 문서에서는 에이전트의 데이터 수명 주기 요구사항에 맞게 조정된 에이전트 샌드박스의 스토리지를 관리하기 위한 참조 구현을 제공합니다.
에이전트의 데이터 수명 주기 요구사항에 따라 다음 구성 중 하나를 선택합니다.
스토리지 솔루션 선택에 대한 자세한 내용은 AI 에이전트 워크로드의 스토리지 선택을 참조하세요.
다음 문서에서는 자동 디스크 유형
선택
을 위한 dynamic-rwo StorageClass를 사용하여 에이전트 샌드박스
포드가 예약된 노드의 머신 유형과 호환되는 디스크를 프로비저닝합니다. GKE가 에이전트의 스토리지에
Hyperdisk Balanced 볼륨을 프로비저닝하도록 하려면
에이전트 샌드박스를 호환되는 머신
계열의 노드(예: N4)에
예약해야 합니다. 그렇지 않으면 GKE가 pd-balanced로 대체됩니다.
이 문서에서는 ReadWriteOnce (RWO) 액세스를 사용하여 비공개 격리된 작업공간 데이터 액세스 모드를 구현합니다. 이 모드에서 에이전트는 읽기 및 쓰기 액세스 권한이 있는 비공개 격리된 스토리지 디렉터리로 시작됩니다.
별도로 지정되지 않은 한 이 문서의 참조 구현은 직접 샌드박스 생성을 사용하며, 이는 여러 초의 시작 지연 시간을 허용하는 에이전트에 적용됩니다. 상태 저장 또는 특정 시점 복원 작업공간의 시작 지연 시간을 1초 미만으로 만들려면 GKE 에이전트 샌드박스 워밍 풀을 사용해야 합니다. 클레임된 워밍 풀 포드에 스토리지를 바인딩하려면 커스텀 스크립팅과 권한 있는 DaemonSet이 필요합니다. 참조 구현은 이 GitHub 예시를 참조하세요.
대체 액세스 모드
대체 액세스 모드를 지원하려면 구성에서 볼륨 및 스냅샷 정의를 수정하면 됩니다.
- 공동작업 작업공간:
accessModes를ReadWriteMany로 변경하고 Filestore Multishares (Enterprise)와 같은 RWX 지원 StorageClass(enterprise-multishare-rwx)를 사용합니다. - 탐색 분기 작업공간: 템플릿 폴더를 읽기 전용으로 마운트하고 별도의 쓰기 가능한 스크래치패드를 제공합니다.
기본 템플릿의 경우 여러 읽기 전용
연결을 지원하는 스토리지를 사용해야 합니다. 예를 들어 Hyperdisk ML의
ReadOnlyMany(ROX) 액세스 모드 또는 RWX 액세스 모드의 Filestore Multishares를 사용할 수 있습니다.
시작하기 전에
상태 저장 작업공간 구성
이 패턴을 사용하여 에이전트 파일의 최신 상태를 보존합니다. 에이전트 세션이 일시중지되거나 종료될 때 (에이전트 샌드박스가 삭제됨) 에이전트가 상태를 보존하고 에이전트 세션이 활성화될 때 (에이전트 샌드박스가 다시 생성됨) 최신 상태에서 데이터를 복원해야 하는 경우에 유용합니다.
이 섹션의 참조 구현은 직접 샌드박스 생성을 사용하며 여러 초의 시작 지연 시간을 허용하는 에이전트에 적용됩니다.
이 접근 방식은 표준 GKE PersistentVolumeClaim (PVC) 리소스를 사용하여 샌드박스를 사용자 데이터가 포함된 기존 PVC에 연결합니다.
상태 저장 작업공간 패턴은 다음과 같은 이벤트 시퀀스를 따릅니다.
- 프로비저닝: 관리자 또는 오케스트레이터가 결정적 식별자 (예:
pvc-agent-1)를 사용하여 각 에이전트 세션에 비공개 PVC를 수동으로 프로비저닝합니다. - 참조: 샌드박스 리소스에서
volumes블록 내의persistentVolumeClaim필드를 사용하여 기존 볼륨의 정확한claimName을 지정합니다. - 지연 시간: 샌드박스가 생성되면 GKE가 Compute Engine 디스크를 노드 VM에 동적으로 연결해야 하므로 표준 여러 초의 지연 시간이 발생합니다.
- 지속성: 세션 종료 시 (샌드박스 삭제) GKE는 디스크를 분리하지만 PVC를 삭제하지 않으므로 다음 세션에서 최신 상태를 보존하는 데 도움이 됩니다.
세션 간에 데이터를 보존하는 상태 저장 작업공간을 구성하려면 다음 하위 섹션의 단계를 완료하세요.
영구 작업공간 (PVC) 프로비저닝
pvc-agent-1과 같은 결정적 식별자를 사용하는 비공개 PersistentVolumeClaim (PVC)을 만듭니다.
다음 매니페스트를
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매니페스트를 적용합니다.
kubectl apply -f pvc-agent-1.yaml
스토리지 클래스는 동적 볼륨 바인딩을 사용하므로 디스크가 아직 노드에 연결되지 않았습니다. 디스크를 요청하는 포드가 예약될 때까지 Pending 상태로 유지됩니다.
에이전트 샌드박스 배포
결정적 PVC를 참조하여 샌드박스 커스텀 리소스를 배포합니다.
다음 매니페스트를
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매니페스트를 적용합니다.
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
에이전트 세션 종료
에이전트가 유휴 상태일 때 세션 축소 또는 종료를 시뮬레이션하려면 샌드박스 리소스를 삭제하되 기본 스토리지는 보존합니다.
kubectl delete sandbox sandbox-agent-1
GKE는 디스크를 마운트 해제하고 분리합니다. pvc-agent-1 PVC가 유지되어 데이터가 보존됩니다.
에이전트 세션 재활성화
세션을 재활성화하려면 동일한 PVC를 참조하는 새 샌드박스 리소스를 다시 배포합니다.
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이 표시됩니다.
리소스 정리
에이전트 샌드박스 및 연결된 영구 볼륨 클레임을 삭제합니다.
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-snapshot-class.yaml로 저장합니다.apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshotClass metadata: name: standard-rwo-snapshot driver: pd.csi.storage.gke.io deletionPolicy: Delete매니페스트를 적용합니다.
kubectl apply -f 1-snapshot-class.yaml
초기 작업공간 프로비저닝
에이전트가 초기 작업을 수행할 볼륨을 만듭니다.
다음 매니페스트를
2-source-pvc.yaml로 저장합니다.apiVersion: v1 kind: PersistentVolumeClaim metadata: name: agent-source-pvc spec: accessModes: ["ReadWriteOnce"] storageClassName: dynamic-rwo resources: requests: storage: 10Gi매니페스트를 적용합니다.
kubectl apply -f 2-source-pvc.yaml
상태 데이터 생성
샌드박스 포드를 배포하여 볼륨에 데이터를 씁니다.
다음 매니페스트를
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매니페스트를 적용합니다.
kubectl apply -f 3-source-sandbox.yaml포드가 실행될 때까지 기다린 후 상태 파일을 작성합니다.
POD_NAME=agent-session-v1 kubectl exec $POD_NAME -- sh -c "echo 'Point-in-Time Snapshot - v1' > /workspace/state.txt"
이전 상태 보관처리 (CSI VolumeSnapshot)
CSI VolumeSnapshot을 트리거하여 현재 상태를 고정합니다. 스냅샷을 만들 때는 디스크 스냅샷 권장사항을 따르세요.
다음 매니페스트를
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매니페스트를 적용합니다.
kubectl apply -f 4-volume-snapshot.yaml
스냅샷에서 볼륨 복원
dataSource가 CSI VolumeSnapshot을 가리키는 새 PVC를 배포합니다.
다음 매니페스트를
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매니페스트를 적용합니다.
kubectl apply -f 5-restored-pvc.yaml
복원된 에이전트 샌드박스 세션 시작
새로 복원된 PVC를 참조하는 새 샌드박스 리소스를 프로비저닝합니다.
다음 매니페스트를
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매니페스트를 적용합니다.
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
리소스 정리
에이전트 샌드박스, 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
임시 작업공간 구성
에이전트가 활성 상태일 때 임시 파일을 저장하기 위해 스토리지 볼륨이 필요한 경우 임시 작업공간 패턴을 사용합니다. 에이전트 샌드박스 삭제 시 보존해야 하는 데이터가 없습니다.
1초 미만 시작으로 구성
에이전트 샌드박스 워밍 풀을 사용하여 백그라운드에서 빈 볼륨을 미리 프로비저닝합니다.
SandboxTemplate 정의
volumeClaimTemplate 블록 내에서 임시 스토리지 지원을 정의합니다.
다음 매니페스트를
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
샌드박스 워밍 풀 시작
다음 매니페스트를
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두 매니페스트를 모두 적용합니다.
kubectl apply -f stateless-template.yaml kubectl apply -f stateless-warmpool.yaml
샌드박스 클레임
사용자가 세션을 시작할 때 트리거되는 SandboxClaim을 정의합니다.
다음 매니페스트를
stateless-sandbox-claim.yaml로 저장합니다.apiVersion: extensions.agents.x-k8s.io/v1alpha1 kind: SandboxClaim metadata: name: agent-1-claim spec: sandboxTemplateRef: name: stateless-sandbox-template매니페스트를 적용합니다.
kubectl apply -f stateless-sandbox-claim.yaml
1초 미만 실행 확인
에이전트 샌드박스 포드 이름을 캡처하고 /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
여러 초 시작으로 구성
여러 초의 지연 시간을 허용하는 임시 작업공간을 구현하려면 워밍 풀 없이 직접 에이전트 샌드박스 생성을 사용합니다.
상태 비저장 에이전트 샌드박스 정의
다음 매니페스트를
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
에이전트 샌드박스 배포
디스크를 동적으로 프로비저닝하고 예약된 노드에 연결하려면 매니페스트를 적용합니다.
kubectl apply -f sandbox-direct-stateless.yaml
시작 지연 시간 및 실행 확인
포드가 Running 상태로 전환되기 전에 포드 상태를 모니터링하여 연결 지연 시간을 관찰합니다.
kubectl get pods -w
포드가 실행된 후 포드 이름을 캡처하고 /workspace 디렉터리를 사용할 수 있는지 확인합니다.
POD_NAME=sandbox-direct-stateless
kubectl exec $POD_NAME -- ls -la /workspace
에이전트 세션 종료
샌드박스 리소스를 삭제하여 포드를 자동으로 종료하고 임시 스토리지를 삭제합니다.
kubectl delete sandbox sandbox-direct-stateless
다음 단계
- GKE 에이전트 샌드박스에 대해 자세히 알아봅니다.
- 에이전트 샌드박스를 사용하여 AI 코드 실행을 격리하는 방법을 알아봅니다.
- 포드 스냅샷으로 에이전트 샌드박스 환경을 저장하고 복원하는 방법을 알아봅니다.