포드 스냅샷을 사용하여 GKE 환경에서 에이전트 샌드박스 저장 및 복원

이 문서에서는 GKE 포드 스냅샷을 사용하여 GKE 환경에서 실행 중인 Agent Sandbox의 상태를 저장하는 방법을 보여줍니다.

GKE의 Agent Sandbox는 대규모 언어 모델 (LLM)에서 생성된 코드와 같은 신뢰할 수 없는 코드를 실행하기 위한 격리된 환경을 제공하여 보안을 개선합니다. 이러한 유형의 코드를 클러스터에서 직접 실행하면 신뢰할 수 없는 코드가 다른 앱이나 기본 클러스터 노드 자체에 액세스하거나 간섭할 수 있으므로 보안 위험이 발생합니다.

GKE 포드 스냅샷을 사용하면 샌드박스 환경의 상태를 저장하고 복원할 수 있습니다. 이 기능은 다음과 같은 이유로 유용합니다.

  • 빠른 시작: 사전 준비된 스냅샷에서 복원하여 샌드박스 시작 시간을 줄입니다.
  • 장기 실행 에이전트: 실행하는 데 시간이 오래 걸리는 샌드박스를 일시중지하고 나중에 다시 시작하거나 진행 상황을 잃지 않고 다른 노드로 이동합니다.
  • 스테이트풀(Stateful) 워크로드: 샌드박스 환경의 상태를 저장하고 복원하여 대화 기록 또는 중간 계산과 같은 에이전트의 컨텍스트를 유지합니다.
  • 재현성: 특정 상태를 캡처하고 이를 기반으로 동일한 초기화 상태로 여러 개의 새 샌드박스를 시작합니다.

스냅샷은 다음 두 가지 방법으로 트리거할 수 있습니다.

  • 수동 트리거: PodSnapshotManualTrigger 리소스를 만들어 스냅샷을 트리거합니다.
  • 워크로드 트리거: 샌드박스 처리된 애플리케이션 자체가 저장할 준비가 되면 신호를 보냅니다.

이 문서에서는 스냅샷을 수동으로 트리거하는 방법을 보여줍니다.

시작하기 전에

  1. Google Cloud 콘솔의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트를 선택하거나 만드는 데 필요한 역할

    • 프로젝트 선택: 프로젝트를 선택하는 데 특정 IAM 역할이 필요하지 않습니다. 역할이 부여된 모든 프로젝트를 선택할 수 있습니다.
    • 프로젝트 만들기: 프로젝트를 만들려면 resourcemanager.projects.create 권한이 포함된 프로젝트 생성자 역할(roles/resourcemanager.projectCreator)이 필요합니다. 역할 부여 방법 알아보기

    프로젝트 선택기로 이동

  2. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  3. Google Kubernetes Engine, Cloud Storage, Identity and Access Management (IAM) API를 아직 사용 설정하지 않은 경우 사용 설정합니다.

    API 사용 설정에 필요한 역할

    API를 사용 설정하려면 serviceusage.services.enable 권한이 필요합니다. 프로젝트를 만든 경우 소유자 역할 (roles/owner)을 통해 이 권한이 이미 있을 수 있습니다. 그렇지 않으면 서비스 사용량 관리자 역할 (roles/serviceusage.serviceUsageAdmin)을 통해 이 권한을 얻을 수 있습니다. 역할 부여 방법 알아보기

    API 사용 설정

  4. Google Cloud 콘솔에서 Cloud Shell을 활성화합니다.

    Cloud Shell 활성화

요구사항

GKE 포드 스냅샷에는 GKE 버전 1.35.3-gke.1234000 이상이 필요합니다. Autopilot 모드와 일반 모드가 모두 지원됩니다.

포드 스냅샷에는 gVisor가 필요하며 microVM 샌드박스에서는 작동하지 않습니다.

포드 스냅샷에는 GKE Sandbox가 필요하므로 환경에 특정 제한사항이 적용됩니다. 예를 들어 포드 스냅샷은 E2 머신 유형을 지원하지 않습니다. 따라서 이 튜토리얼에서는 N2 머신으로 구성된 노드 풀을 만듭니다.

GPU 기반 머신 유형 사용에 대한 정보를 포함한 전체 제한사항 목록은 제한사항 및 요구사항을 참조하세요.

환경 변수 정의

이 문서에서 실행하는 명령어를 간소화하기 위해 Cloud Shell에서 환경 변수를 설정할 수 있습니다. 이러한 변수는 Google Cloud 프로젝트의 ID, 스냅샷을 저장할 Cloud Storage 버킷의 이름, GKE 클러스터의 위치와 같은 값을 저장합니다.

이러한 변수를 정의한 후에는 매번 값을 다시 입력하거나 바꾸는 대신 변수 이름 (예: $CLUSTER_NAME)을 참조하여 여러 명령어에서 재사용할 수 있습니다. 이 접근 방식을 사용하면 프로세스를 더 쉽게 따라갈 수 있으므로 오류 위험이 줄어듭니다.

Cloud Shell에서 다음 유용한 환경 변수를 정의하려면 다음 명령어를 실행합니다.

export PROJECT_ID=$(gcloud config get project)
export CLUSTER_NAME="agent-sandbox-cluster"
export GKE_LOCATION="us-central1"
export ZONE="us-central1-a"
export AGENT_SANDBOX_VERSION="v1.0.6"
export NODE_POOL_NAME="agent-sandbox-node-pool"
export MACHINE_TYPE="n2-standard-2"
export SNAPSHOTS_BUCKET_NAME="agent-sandbox-snapshots-${PROJECT_ID}"
export SNAPSHOT_NAMESPACE="pod-snapshots-ns"
export SNAPSHOT_KSA_NAME="pod-snapshot-sa"
export SNAPSHOT_FOLDER="my-snapshots"
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")

다음은 이러한 환경 변수에 대한 설명입니다.

  • PROJECT_ID: 현재 Google Cloud 프로젝트의 ID입니다. 이 문서의 명령어는 이 ID를 사용하여 리소스 이름을 지정하고 IAM 권한을 부여합니다.
  • CLUSTER_NAME: GKE 클러스터의 이름입니다 (예: agent-sandbox-cluster).
  • GKE_LOCATION: Cloud Storage 버킷의 Google Cloud 리전(예: us-central1). Autopilot 클러스터를 만드는 경우 클러스터에서도 이 리전을 사용합니다.
  • ZONE: GKE 클러스터의 영역입니다. Standard 클러스터를 만드는 경우 이를 GKE_LOCATION 리전의 영역(예: us-central1-a)으로 설정합니다. 비용을 줄이기 위해 이 문서에서는 영역 Standard 클러스터를 만듭니다.
  • AGENT_SANDBOX_VERSION: 설치할 오픈소스 Agent Sandbox 컨트롤러의 버전입니다. 이 문서에서는 버전 1.0.6을 사용합니다.
  • NODE_POOL_NAME: 샌드박스 워크로드를 실행할 노드 풀의 이름입니다 (예: agent-sandbox-node-pool).
  • MACHINE_TYPE: 노드 풀에 있는 노드의 머신 유형입니다 (예: n2-standard-2). 포드 스냅샷은 E2 머신 유형을 지원하지 않습니다. 노드 풀의 노드에 GPU 기반 머신 유형을 사용하려면 제한사항 및 요구사항을 참조하세요. 다양한 머신 시리즈와 다양한 옵션 중에서 선택하는 방법에 대한 자세한 내용은 머신 계열 리소스 및 비교 가이드를 참조하세요.
  • SNAPSHOTS_BUCKET_NAME: 스냅샷을 저장하기 위해 만들 Cloud Storage 버킷의 이름입니다.
  • SNAPSHOT_NAMESPACE: 스냅샷 워크로드 및 서비스 계정이 상주하는 Kubernetes 네임스페이스입니다.
  • SNAPSHOT_KSA_NAME: 워크로드가 인증에 사용할 Kubernetes 서비스 계정의 이름입니다.
  • SNAPSHOT_FOLDER: 스냅샷이 구성되는 Cloud Storage 버킷 내의 디렉터리입니다.
  • PROJECT_NUMBER: IAM 권한 바인딩에 사용되는 프로젝트의 고유 숫자 식별자입니다.

구성 단계 개요

GKE 환경에서 Agent Sandbox의 포드 스냅샷을 사용 설정하려면 몇 가지 구성 단계를 수행해야 합니다. 이러한 단계를 이해하려면 먼저 몇 가지 주요 개념을 이해한 후 스냅샷 프로세스를 이해하는 것이 좋습니다.

주요 개념

  • 환경: 샌드박스 처리된 애플리케이션은 GKE 클러스터 노드의 Kubernetes 포드 내에서 실행됩니다.
  • ID: 포드는 Kubernetes 서비스 계정과 연결되며 사용자가 만드는 특수 네임스페이스에서 실행됩니다. Kubernetes 서비스 계정과 네임스페이스는 포드에 Google Cloud 리소스에 대한 보안 액세스 권한을 부여하는 데 사용되는 고유한 ID를 형성합니다.
  • 권한: 스냅샷을 Cloud Storage에 저장할 수 있도록 하려면 포드의 ID에 Cloud Storage 버킷에 쓸 수 있는 특정 IAM 권한을 부여해야 합니다.

스냅샷 프로세스

  1. 트리거: 스냅샷은 수동 (외부)으로 또는 샌드박스 처리된 워크로드 자체에 의해 시작됩니다. 이 문서에서는 PodSnapshotManualTrigger 리소스를 만들어 시작하는 수동 트리거를 보여줍니다.
  2. 캡처: GKE는 포드의 메모리 상태 및 파일 시스템과 같은 포드의 실행 상태를 캡처합니다.
  3. 업로드: GKE는 포드의 Kubernetes 서비스 계정에 부여된 권한을 사용하여 캡처된 상태를 스냅샷 파일로 지정된 Cloud Storage 버킷에 업로드합니다.

GKE가 Kubernetes 서비스 계정과 IAM 역할을 사용하여 Google Cloud 리소스에 액세스하는 방법에 대한 자세한 내용은 GKE 워크로드에서Google Cloud API에 인증을 참조하세요.

GKE 환경에서 Agent Sandbox의 포드 스냅샷을 사용 설정하려면 다음 구성을 수행합니다. 먼저 GKE용 워크로드 아이덴티티 제휴 및 포드 스냅샷 기능이 사용 설정된 GKE 클러스터를 만들어 클러스터 환경을 준비합니다. 다음으로 스냅샷이 안전하게 저장되고 샌드박스에 필요한 권한이 있도록 Cloud Storage 및 IAM 정책을 구성합니다. 마지막으로 샌드박스의 스토리지 위치와 정책을 지정하는 스냅샷 리소스를 만듭니다.

다음 표에는 수행해야 하는 구성 단계가 요약되어 있으며 각 단계는 다음 섹션에서 설명합니다.

주제 작업
클러스터 설정 1. GKE 클러스터를 만들고 GKE용 포드 스냅샷 및 GKE용 워크로드 아이덴티티 제휴 기능을 사용 설정합니다.
2. Agent Sandbox를 배포합니다.
스토리지 및 권한 구성 1. Cloud Storage 버킷 및 관리 폴더를 만듭니다.
2. 커스텀 IAM 역할을 만듭니다.
3. Kubernetes 네임스페이스와 Kubernetes 서비스 계정 (KSA)을 만듭니다.
4. IAM 역할을 Kubernetes 서비스 계정에 바인딩합니다.
5. 스냅샷 컨트롤러에 권한을 부여합니다.
스냅샷 리소스 구성 1. PodSnapshotStorageConfig 리소스를 만듭니다
2. PodSnapshotPolicy 리소스를 만듭니다
3. SandboxTemplate, SandboxWarmPool, SandboxClaim 리소스 만들기

클러스터 설정

샌드박스 처리된 앱은 GKE 클러스터 노드의 포드 내에서 실행되므로 클러스터 환경을 설정해야 합니다. 이 섹션에서는 GKE 클러스터를 만들고 Agent Sandbox 컨트롤러를 배포하는 방법을 보여줍니다.

요구사항을 충족하는 새 GKE 클러스터를 만듭니다.

포드 스냅샷이 사용 설정된 새 GKE 클러스터를 만듭니다. 포드 스냅샷에는 GKE 버전 1.35.3-gke.1234000 이상이 필요합니다. 다음 명령어는 기본 버전이 이 요구사항을 충족하는 빠른 출시 채널에 클러스터를 등록합니다.

Autopilot

필수 기능이 있는 Autopilot 클러스터를 만듭니다.

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

표준

필수 기능이 있는 Standard 클러스터를 만듭니다. 비용을 줄이기 위해 다음 명령어는 한 영역에서 컨트롤 플레인과 노드를 실행하는 영역 클러스터를 만듭니다.

gcloud container clusters create ${CLUSTER_NAME} \
   --release-channel=rapid \
   --enable-pod-snapshots \
   --machine-type=${MACHINE_TYPE} \
   --workload-pool=${PROJECT_ID}.svc.id.goog \
   --workload-metadata=GKE_METADATA \
   --num-nodes=1 \
   --location=${ZONE}

GKE Sandbox가 사용 설정된 노드 풀을 만듭니다. GKE Sandbox는 실행 중인 애플리케이션과 호스트 운영체제 사이에 추가 격리 레이어를 제공하는 오픈소스 gVisor 프로젝트를 기반으로 하는 컨테이너 보안 기능입니다.

gcloud container node-pools create ${NODE_POOL_NAME} \
   --cluster ${CLUSTER_NAME} \
   --num-nodes=1 \
   --location=${ZONE} \
   --project=${PROJECT_ID} \
   --machine-type=${MACHINE_TYPE} \
   --sandbox type=gvisor

사용자 인증 정보 검색

kubectl CLI가 클러스터에 연결할 수 있도록 클러스터의 사용자 인증 정보를 검색합니다.

Autopilot

gcloud container clusters get-credentials ${CLUSTER_NAME} \
    --location=${GKE_LOCATION}

표준

gcloud container clusters get-credentials ${CLUSTER_NAME} \
    --location=${ZONE}

클러스터에 Agent Sandbox 컨트롤러 배포

공식 출시 매니페스트를 클러스터에 적용하여 Agent Sandbox 컨트롤러와 필수 구성요소를 배포할 수 있습니다. 이 매니페스트는 클러스터에 Agent Sandbox 컨트롤러를 배포하고 실행하는 데 필요한 모든 구성요소를 다운로드하도록 Kubernetes에 지시하는 구성 파일입니다.

GKE 클러스터에 Agent Sandbox를 배포하려면 다음 명령어를 실행합니다.

# Apply the release manifest for the controller and its CustomResourceDefinitions
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/sandbox-with-extensions.yaml

Agent Sandbox 설치에 대한 자세한 내용은 GKE에 Agent Sandbox 설치를 참조하세요.

컨트롤러 확인

매니페스트를 적용한 후 Agent Sandbox 컨트롤러 포드가 agent-sandbox-system 네임스페이스에서 올바르게 실행 중인지 확인합니다. 이전 단계에서 매니페스트를 적용했을 때 매니페스트가 agent-sandbox-system 네임스페이스를 자동으로 만들었습니다.

kubectl get pods -n agent-sandbox-system

포드가 STATUS 열에 'Running'을 표시하고 READY 열에 '1/1'을 표시할 때까지 기다립니다. 포드가 올바르게 실행되면 출력은 다음과 비슷합니다.

NAME                                        READY   STATUS    RESTARTS   AGE
agent-sandbox-controller-7d5c9b8f6d-x2k9p   1/1     Running   0          2m

이제 에이전트 샌드박스 컨트롤러가 실행 중이므로 클러스터에서 만드는 모든 Sandbox 리소스에 대해 샌드박스 환경을 자동으로 만들고 관리할 수 있습니다.

스토리지 및 권한 구성

이 섹션에서는 포드 스냅샷에 필요한 스토리지 및 권한을 구성하는 방법을 보여줍니다. 스냅샷 데이터를 저장할 Cloud Storage 버킷과 관리형 폴더를 만듭니다. 그런 다음 샌드박스와 스냅샷 컨트롤러에 해당 스토리지에 액세스하는 데 필요한 권한을 부여합니다.

Cloud Storage 버킷 만들기

스냅샷을 저장할 버킷을 만듭니다. 스냅샷 프로세스가 빠르고 비용 효율적인지 확인하려면 다음 설정으로 버킷을 만듭니다.

  • 계층적 네임스페이스 사용 설정: 계층적 네임스페이스 기능은 버킷을 플랫 네임스페이스가 아닌 파일 시스템 계층 구조로 구성합니다. 이 구성을 사용하면 읽기 및 쓰기 처리량이 높아져 스냅샷 저장 및 복원 속도가 빨라집니다.
  • 소프트 삭제 사용 중지: 소프트 삭제 기능은 삭제된 파일을 일정 기간 보관하여 데이터를 보호합니다. 하지만 스냅샷 프로세스는 업로드 중에 많은 임시 파일을 만들고 삭제합니다. 이러한 임시 파일을 저장하는 데 불필요한 요금이 청구되지 않도록 소프트 삭제를 사용 중지합니다.

이러한 설정으로 버킷을 만들려면 다음 명령어를 실행합니다.

gcloud storage buckets create "gs://${SNAPSHOTS_BUCKET_NAME}" \
    --uniform-bucket-level-access \
    --enable-hierarchical-namespace \
    --soft-delete-duration=0d \
    --location="${GKE_LOCATION}"

관리형 폴더 만들기

버킷 내에서 스냅샷을 정리할 관리 폴더를 만듭니다. 관리형 폴더를 사용하면 전체 버킷이 아닌 특정 폴더에 IAM 권한을 적용할 수 있습니다. 이 폴더 수준 액세스는 샌드박스의 액세스를 자체 스냅샷으로만 제한하고 해당 스냅샷을 버킷의 다른 데이터와 격리합니다.

관리형 폴더를 만들려면 다음 명령어를 실행합니다.

gcloud storage managed-folders create "gs://${SNAPSHOTS_BUCKET_NAME}/${SNAPSHOT_FOLDER}/"

서비스 계정 및 IAM 역할 구성

GKE에서 스냅샷을 안전하게 저장할 수 있도록 하려면 샌드박스 처리된 워크로드를 실행하는 포드에서 사용하는 Kubernetes 서비스 계정에 버킷에 쓸 수 있는 권한이 필요합니다. 포드에서 사용하는 Kubernetes 서비스 계정에 Google CloudIAM 역할을 바인딩하여 이 권한을 부여합니다. 이 섹션에서는 커스텀 IAM 역할을 만들고, Kubernetes 서비스 계정을 만들고, 필요한 권한을 구성하는 방법을 보여줍니다.

  1. 스냅샷 데이터를 작성하는 데 필요한 권한이 포함된 podSnapshotGcsReadWriter라는 커스텀 IAM 역할을 만듭니다. 이 문서의 이전 실행 등으로 인해 이 역할이 프로젝트에 이미 있으면 이 단계를 건너뜁니다. 그렇지 않으면 다음 명령어를 실행합니다.

    gcloud iam roles create podSnapshotGcsReadWriter \
        --project="${PROJECT_ID}" \
        --permissions="storage.objects.get,storage.objects.create,storage.objects.delete,storage.folders.create"
    

    역할이 성공적으로 생성되면 다음과 같이 출력됩니다.

    Created role [podSnapshotGcsReadWriter].
    etag: BwZJUfjNbew=
    includedPermissions:
    - storage.folders.create
    - storage.objects.create
    - storage.objects.delete
    - storage.objects.get
    name: projects/${PROJECT_ID}/roles/podSnapshotGcsReadWriter
    stage: ALPHA
    title: podSnapshotGcsReadWriter
    

    역할 ID가 삭제 대상으로 표시되었다는 FAILED_PRECONDITION 오류와 함께 명령어가 실패하면 이 ID를 가진 역할을 최근에 삭제한 것입니다(예: 이 문서의 이전 실행 정리 단계). IAM에서는 최대 37일 동안 해당 ID를 재사용할 수 없습니다. podSnapshotGcsReadWriter2와 같은 다른 역할 ID로 명령어를 다시 실행하고 이 문서의 나머지 부분에서 podSnapshotGcsReadWriter 대신 해당 ID를 사용합니다.

  2. 샌드박스 및 해당 서비스 계정이 상주할 네임스페이스를 만듭니다.

    kubectl create namespace "${SNAPSHOT_NAMESPACE}"
    
  3. 방금 만든 네임스페이스에 Kubernetes 서비스 계정을 만듭니다. Kubernetes 서비스 계정과 네임스페이스는 샌드박스에 Google Cloud리소스에 대한 보안 액세스 권한을 부여하는 데 사용되는 고유한 ID를 형성합니다.

    kubectl create serviceaccount "${SNAPSHOT_KSA_NAME}" \
        --namespace "${SNAPSHOT_NAMESPACE}"
    
  4. 네임스페이스의 모든 서비스 계정에 roles/storage.bucketViewer 역할을 부여합니다. 이 역할을 사용하면 계정에서 버킷의 메타데이터를 볼 수 있지만 데이터 자체를 읽거나 쓸 수는 없습니다.

    gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
        --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/namespace/${SNAPSHOT_NAMESPACE}" \
        --role="roles/storage.bucketViewer"
    
  5. 샌드박스의 Kubernetes 서비스 계정에 커스텀 podSnapshotGcsReadWriter 역할을 부여합니다. 이 바인딩은 이 특정 계정만 관리 폴더에 데이터를 쓸 수 있도록 허용합니다. 새 커스텀 역할을 사용할 수 있게 되기까지 몇 분 정도 걸릴 수 있으므로 역할이 존재하지 않아 이 명령어가 실패하면 잠시 기다린 후 명령어를 다시 실행합니다.

    gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
        --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/${SNAPSHOT_NAMESPACE}/sa/${SNAPSHOT_KSA_NAME}" \
        --role="projects/${PROJECT_ID}/roles/podSnapshotGcsReadWriter"
    
  6. Kubernetes 서비스 계정에 roles/storage.objectUser 역할을 부여합니다. 이 역할은 포드 스냅샷 에이전트가 관리 폴더에서 작업을 수행하는 데 필요합니다.

    gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
        --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/${SNAPSHOT_NAMESPACE}/sa/${SNAPSHOT_KSA_NAME}" \
        --role="roles/storage.objectUser"
    

스냅샷 컨트롤러에 권한 부여

GKE 시스템의 스냅샷 컨트롤러에 objectUser 역할을 부여합니다. 이 권한을 통해 컨트롤러는 PodSnapshot 리소스를 삭제할 때 스냅샷 객체를 삭제하는 등 스냅샷 수명 주기를 관리할 수 있습니다.

gcloud storage buckets add-iam-policy-binding "gs://${SNAPSHOTS_BUCKET_NAME}" \
    --member="serviceAccount:service-${PROJECT_NUMBER}@container-engine-robot.iam.gserviceaccount.com" \
    --role="roles/storage.objectUser"

스냅샷 리소스 구성

이 섹션에서는 GKE 워크로드의 Agent Sandbox에 대한 스냅샷 리소스를 구성하는 방법을 보여줍니다.

스냅샷 스토리지 및 규칙 정의

GKE가 스냅샷을 저장하는 위치와 스냅샷 프로세스에 적용되는 규칙을 지정하려면 커스텀 리소스 두 개를 만듭니다.

  • PodSnapshotStorageConfig: 이 리소스는 GKE가 스냅샷 파일을 저장하는 Cloud Storage 버킷 및 폴더 위치를 지정합니다.
  • PodSnapshotPolicy: 이 리소스는 Kubernetes 라벨을 기준으로 스냅샷에 적합한 포드를 정의합니다. 또한 스냅샷이 수동인지 아니면 샌드박스 워크로드에 의해 시작되는지 여부와 같은 트리거 규칙을 지정합니다. 이 예시에서는 Agent Sandbox 컨트롤러가 각 샌드박스의 포드에 추가하는 agents.x-k8s.io/sandbox-name-hash 라벨을 기준으로 스냅샷을 그룹화합니다. 이 그룹화는 GKE가 자체 스냅샷에서만 각 샌드박스를 복원함을 의미합니다.

한 단계에서 두 리소스를 모두 적용하려면 Cloud Shell에서 다음 명령어를 실행합니다. 이 방법을 사용하면 환경 변수가 올바르게 삽입됩니다.

kubectl apply -f - <<EOF
apiVersion: podsnapshot.gke.io/v1
kind: PodSnapshotStorageConfig
metadata:
  name: cpu-pssc-gcs
spec:
  snapshotStorageConfig:
    gcs:
      bucket: "${SNAPSHOTS_BUCKET_NAME}"
      path: "${SNAPSHOT_FOLDER}"
EOF

sleep 5

kubectl apply -f - <<EOF
apiVersion: podsnapshot.gke.io/v1
kind: PodSnapshotPolicy
metadata:
  name: cpu-psp
  namespace: ${SNAPSHOT_NAMESPACE}
spec:
  storageConfigName: cpu-pssc-gcs
  selector:
    matchLabels:
      app: agent-sandbox-workload
  triggerConfig:
    type: manual
    postCheckpoint: resume
  snapshotGroupingRules:
    groupByLabelValue:
      labels:
      - agents.x-k8s.io/sandbox-name-hash
EOF

구성 확인

스냅샷 스토리지 구성 및 정책을 적용한 후 리소스를 사용할 준비가 되었는지 확인합니다. 이 섹션에서는 이러한 커스텀 리소스의 상태를 확인하는 방법을 보여줍니다.

  1. PodSnapshotStorageConfig 리소스 상태를 확인합니다.

    kubectl get podsnapshotstorageconfigs.podsnapshot.gke.io cpu-pssc-gcs -o yaml
    

    출력에는 type: Ready 및 status: "True"가 포함된 조건이 포함되어야 합니다.

    status:
      conditions:
      - lastTransitionTime: "2025-10-31T18:18:02Z"
        message: Valid PodSnapshotStorageConfig
        reason: StorageConfigValid
        status: "True"
        type: Ready
    
  2. PodSnapshotPolicy 리소스 상태를 확인합니다.

    kubectl get podsnapshotpolicies.podsnapshot.gke.io cpu-psp \
      --namespace "${SNAPSHOT_NAMESPACE}" -o yaml
    

    출력에는 type: Ready 및 status: "True"가 포함된 조건이 포함되어야 합니다. 또한 참조된 PodSnapshotStorageConfig 리소스가 발견되었음을 나타내야 합니다.

    status:
      conditions:
      - lastTransitionTime: "2025-10-31T18:19:47Z"
        message: The referenced PodSnapshotStorageConfig "cpu-pssc-gcs" was found
        reason: StorageConfigValid
        status: "True"
        type: Ready
    

샌드박스 템플릿 만들기

이제 스토리지 정책과 권한이 설정되었으므로 SandboxTemplate, SandboxWarmPool, SandboxClaim 리소스를 만듭니다. SandboxWarmPool 리소스는 사전 준비된 샌드박스를 계속 실행하고 SandboxClaim 리소스는 풀에서 해당 샌드박스를 요청합니다. 스냅샷 프로세스가 작동하려면 이 문서 앞부분에서 만든 Kubernetes 서비스 계정으로 샌드박스를 실행해야 합니다. 샌드박스에는 이전에 PodSnapshotPolicy 리소스에서 지정한 라벨도 있어야 합니다.

이 예시에서는 로그에 증가하는 카운터를 출력하는 Python 앱을 사용합니다. 이 카운터를 사용하면 상태가 성공적으로 저장되고 나중에 복원되는지 확인할 수 있습니다.

Autopilot

포드 스냅샷은 E2 머신 유형을 지원하지 않습니다. Autopilot에서 GKE는 포드 스냅샷을 지원하지 않는 머신 유형으로 기본 설정될 수 있습니다. 워크로드가 호환되는 하드웨어에서 실행되도록 하려면 커스텀 ComputeClass를 사용하여 호환되는 머신 계열의 우선순위를 지정해야 합니다.

  1. 다음 매니페스트를 non-e2-class.yaml로 저장합니다.

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: non-e2-class
    spec:
      priorities:
      - machineFamily: n2
      - machineFamily: c3
      activeMigration:
        optimizeRulePriority: false
      whenUnsatisfiable: DoNotScaleUp
    
  2. 매니페스트를 적용합니다.

    kubectl apply -f non-e2-class.yaml
    
  3. SandboxTemplate 및 SandboxWarmPool 리소스를 만들려면 다음 매니페스트를 적용합니다. SandboxTemplate 리소스는 cloud.google.com/compute-class: non-e2-class 노드 선택기를 사용하여 방금 만든 ComputeClass를 참조합니다.

    kubectl apply -f - <<EOF
    ---
    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxTemplate
    metadata:
      name: python-runtime-template
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      podTemplate:
        metadata:
          labels:
            app: agent-sandbox-workload
        spec:
          serviceAccountName: ${SNAPSHOT_KSA_NAME}
          runtimeClassName: gvisor
          nodeSelector:
            cloud.google.com/compute-class: non-e2-class
          containers:
          - name: my-container
            image: python:3.10-slim
            command: ["python3", "-c"]
            args:
              - |
                import time
                i = 0
                while True:
                  print(f"Count: {i}", flush=True)
                  i += 1
                  time.sleep(1)
    ---
    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxWarmPool
    metadata:
      name: python-sandbox-warmpool
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      replicas: 1
      sandboxTemplateRef:
        name: python-runtime-template
    EOF
    

표준

SandboxTemplate 및 SandboxWarmPool 리소스를 만들려면 다음 매니페스트를 적용합니다.

kubectl apply -f - <<EOF
---
apiVersion: extensions.agents.x-k8s.io/v1beta1
kind: SandboxTemplate
metadata:
  name: python-runtime-template
  namespace: ${SNAPSHOT_NAMESPACE}
spec:
  podTemplate:
    metadata:
      labels:
        app: agent-sandbox-workload
    spec:
      serviceAccountName: ${SNAPSHOT_KSA_NAME}
      runtimeClassName: gvisor
      containers:
      - name: my-container
        image: python:3.10-slim
        command: ["python3", "-c"]
        args:
          - |
            import time
            i = 0
            while True:
              print(f"Count: {i}", flush=True)
              i += 1
              time.sleep(1)
---
apiVersion: extensions.agents.x-k8s.io/v1beta1
kind: SandboxWarmPool
metadata:
  name: python-sandbox-warmpool
  namespace: ${SNAPSHOT_NAMESPACE}
spec:
  replicas: 1
  sandboxTemplateRef:
    name: python-runtime-template
EOF

리소스를 만든 후 웜 풀에서 샌드박스를 요청합니다.

  1. 웜 풀의 샌드박스가 준비될 때까지 기다립니다.

    kubectl wait sandboxwarmpool python-sandbox-warmpool \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=jsonpath='{.status.readyReplicas}'=1 \
      --timeout=600s
    
  2. 웜 풀에서 샌드박스를 요청하는 SandboxClaim 리소스를 만듭니다.

    kubectl apply -f - <<EOF
    apiVersion: extensions.agents.x-k8s.io/v1beta1
    kind: SandboxClaim
    metadata:
      name: python-sandbox-example
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      warmPoolRef:
        name: python-sandbox-warmpool
    EOF
    
  3. 클레임이 준비될 때까지 기다린 후 클레임에서 사용하는 샌드박스의 이름을 저장합니다. 샌드박스의 포드 이름은 샌드박스와 동일합니다.

    kubectl wait sandboxclaim python-sandbox-example \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=condition=Ready \
      --timeout=300s
    
    export SANDBOX_NAME=$(kubectl get sandboxclaim python-sandbox-example \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      -o jsonpath='{.status.sandbox.name}')
    echo "${SANDBOX_NAME}"
    

이제 샌드박스가 올바른 ID로 실행되고 있으며 스냅샷을 생성할 준비가 되었습니다.

스냅샷 만들기

이 섹션에서는 실행 중인 샌드박스의 스냅샷을 수동으로 트리거하는 방법을 보여줍니다. 샌드박스 포드를 타겟팅하는 트리거 리소스를 만든 다음 스냅샷 프로세스가 성공적으로 완료되었는지 확인합니다.

  1. 초기 카운터 로그 확인: 스냅샷을 트리거하기 전에 실행 중인 샌드박스의 로그를 확인하여 현재 카운터 값을 확인합니다. 로그를 보면 복원 후 비교할 기준이 설정됩니다.

    kubectl logs "${SANDBOX_NAME}" --namespace "${SNAPSHOT_NAMESPACE}" --tail=5
    

    출력에는 카운터의 마지막 몇 줄이 표시됩니다. 예를 들면 다음과 같습니다.

    Count: 15
    Count: 16
    Count: 17
    

    출력된 마지막 몇 개의 'Count' 값을 확인합니다.

  2. PodSnapshotManualTrigger 리소스 만들기: 스냅샷을 시작합니다.

    kubectl apply -f - <<EOF
    apiVersion: podsnapshot.gke.io/v1
    kind: PodSnapshotManualTrigger
    metadata:
      name: cpu-snapshot-trigger
      namespace: ${SNAPSHOT_NAMESPACE}
    spec:
      targetPod: ${SANDBOX_NAME}
    EOF
    
  3. 수동 트리거가 성공했는지 확인합니다.

    kubectl get podsnapshotmanualtriggers.podsnapshot.gke.io \
      --namespace "${SNAPSHOT_NAMESPACE}"
    

    출력에 Complete 상태가 표시되어 GKE가 대상 포드의 스냅샷을 트리거했음을 나타냅니다.

    NAME                   TARGET POD                      STATUS     AGE
    cpu-snapshot-trigger   python-sandbox-warmpool-x7k2p   Complete   XXs
    
  4. 트리거를 설명하여 캡처된 상태에 대한 세부정보를 확인합니다.

    kubectl describe podsnapshotmanualtriggers.podsnapshot.gke.io cpu-snapshot-trigger \
      --namespace "${SNAPSHOT_NAMESPACE}"
    

    출력에는 버킷에 저장된 스냅샷 파일의 고유한 이름이 있는 Snapshot Created 섹션이 포함됩니다.

    Status:
      Conditions:
        Last Transition Time:  2026-01-30T19:11:04Z
        Message:               checkpoint completed successfully
        Reason:                Complete
        Status:                True
        Type:                  Triggered
      Observed Generation:     1
      Snapshot Created:
        Name:  <UNIQUE_SNAPSHOT_NAME>
    

스냅샷을 사용하여 복원

스냅샷을 캡처한 후 샌드박스를 정지하여 컴퓨팅 리소스를 확보하고 나중에 저장된 상태에서 샌드박스를 재개할 수 있습니다. 샌드박스를 정지하면 에이전트 샌드박스 컨트롤러가 샌드박스의 포드를 삭제하지만 Sandbox 리소스는 유지합니다. 샌드박스를 재개하면 컨트롤러가 포드를 다시 만들고 포드 스냅샷 컨트롤러가 해당 샌드박스의 최신 스냅샷에서 포드를 자동으로 복원합니다.

  1. 스냅샷이 준비될 때까지 기다립니다. GKE는 준비된 스냅샷에서만 포드를 복원합니다. 스냅샷이 준비되기 전에 샌드박스를 정지하면 샌드박스를 재개할 때 저장된 상태 없이 시작됩니다.

    export SNAPSHOT_NAME=$(kubectl get podsnapshotmanualtriggers.podsnapshot.gke.io cpu-snapshot-trigger \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      -o jsonpath='{.status.snapshotCreated.name}')
    
    kubectl wait podsnapshots.podsnapshot.gke.io "${SNAPSHOT_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=condition=Ready \
      --timeout=600s
    
  2. 샌드박스를 정지하려면 operatingMode 필드를 Suspended로 설정한 후 컨트롤러가 샌드박스의 포드를 삭제할 때까지 기다립니다.

    kubectl patch sandbox "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --type=merge \
      -p '{"spec":{"operatingMode":"Suspended"}}'
    
    kubectl wait pod "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=delete \
      --timeout=120s
    
  3. 샌드박스를 재개하려면 operatingMode 필드를 Running로 설정한 후 샌드박스가 준비될 때까지 기다립니다.

    kubectl patch sandbox "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --type=merge \
      -p '{"spec":{"operatingMode":"Running"}}'
    
    kubectl wait sandbox "${SANDBOX_NAME}" \
      --namespace "${SNAPSHOT_NAMESPACE}" \
      --for=condition=Ready \
      --timeout=300s
    
  4. 로그를 확인하여 복원이 수행되었는지 확인합니다. 카운터는 스냅샷이 생성된 지점부터 계속됩니다.

    kubectl logs "${SANDBOX_NAME}" --namespace "${SNAPSHOT_NAMESPACE}"
    

    출력에 카운터가 다시 시작되는 것으로 표시됩니다. 예를 들면 다음과 같습니다.

    Count: 18
    Count: 19
    Count: 20
    Count: 21
    

    카운터가 0에서 시작되면 포드가 스냅샷에서 복원하지 않고 시작된 것입니다.

리소스 삭제

이 문서에서 사용한 리소스의 비용이 Google Cloud 계정에 청구되지 않도록 하려면 다음 단계를 수행하여 만든 리소스를 삭제합니다.

  1. 샌드박스 클레임과 웜 풀을 삭제하여 실행 중인 포드를 중지하고 Agent Sandbox 컨트롤러가 컨테이너를 단계적으로 종료할 수 있도록 합니다.

    kubectl delete sandboxclaims --all --namespace "${SNAPSHOT_NAMESPACE}"
    kubectl delete sandboxwarmpools --all --namespace "${SNAPSHOT_NAMESPACE}"
    
  2. 샌드박스를 만들고 스냅샷을 시작하는 데 사용된 샌드박스 템플릿과 수동 트리거를 삭제합니다.

    # Delete the blueprints
    kubectl delete sandboxtemplates --all --namespace "${SNAPSHOT_NAMESPACE}"
    
    # Delete the snapshot initiation objects
    kubectl delete podsnapshotmanualtriggers --all --namespace "${SNAPSHOT_NAMESPACE}"
    
  3. 네임스페이스 내에서 스냅샷을 만들 수 있는 포드를 정의하는 스냅샷 정책을 삭제합니다.

    kubectl delete podsnapshotpolicy cpu-psp --namespace "${SNAPSHOT_NAMESPACE}"
    
  4. 스냅샷 스토리지 백엔드의 전역 정의인 스냅샷 스토리지 구성을 삭제합니다. 이 리소스는 클러스터 범위이므로 네임스페이스 플래그를 사용하지 마세요.

    kubectl delete podsnapshotstorageconfig cpu-pssc-gcs
    
  5. Autopilot용으로 만든 경우 ComputeClass를 삭제합니다.

    kubectl delete computeclass non-e2-class
    
  6. Kubernetes 네임스페이스를 삭제하여 Kubernetes 서비스 계정과 나머지 네임스페이스 메타데이터를 자동으로 삭제합니다.

    kubectl delete namespace "${SNAPSHOT_NAMESPACE}"
    
  7. GKE 클러스터를 삭제하여 기본 인프라와 튜토리얼과 연결된 모든 노드를 삭제합니다.

    Autopilot

    gcloud container clusters delete "${CLUSTER_NAME}" \
        --location="${GKE_LOCATION}" --quiet
    

    표준

    gcloud container clusters delete "${CLUSTER_NAME}" \
        --location="${ZONE}" --quiet
    
  8. 스토리지를 완전히 재설정하려면 재귀 삭제 명령어를 사용하여 Cloud Storage 버킷을 삭제합니다 (선택사항). 향후 테스트를 위해 올바르게 구성된 버킷을 재사용하려는 경우 이 단계를 건너뛸 수 있습니다.

    gcloud storage rm --recursive "gs://${SNAPSHOTS_BUCKET_NAME:?Error: SNAPSHOTS_BUCKET_NAME is not set. Please re-define the environment variables you defined earlier.}"
    
  9. 프로젝트를 완전히 깨끗한 상태로 되돌리려면 커스텀 IAM 역할을 삭제합니다 (선택사항). IAM 역할은 클러스터가 삭제된 후에도 유지되므로 별도로 삭제해야 합니다.

    gcloud iam roles delete podSnapshotGcsReadWriter --project="${PROJECT_ID}"
    

다음 단계