Pod スナップショットを使用して GKE 環境で Agent Sandbox を保存、復元する

このドキュメントでは、GKE Pod スナップショットを使用して、GKE 環境で実行中の Agent Sandbox の状態を保存する方法について説明します。

GKE の Agent Sandbox は、大規模言語モデル(LLM)によって生成されたコードなど、信頼性の低いコードを実行するための分離された環境を提供することで、セキュリティを向上させます。このタイプのコードをクラスタで直接実行すると、信頼できないコードが他のアプリや基盤となるクラスタノード自体にアクセスしたり、干渉する可能性があるため、セキュリティ上のリスクが生じます。

GKE Pod スナップショットを使用すると、サンドボックス環境の状態を保存して復元できます。この機能は、次の理由で役立ちます。

  • 高速起動: 事前ウォームアップされたスナップショットから復元することで、サンドボックスの起動時間を短縮します。
  • 長時間実行エージェント: 実行に時間がかかるサンドボックスを一時停止して後で再開したり、進行状況を失うことなく別のノードに移動したりできます。
  • ステートフル ワークロード: サンドボックス環境の状態を保存して復元することで、会話履歴や中間計算などのエージェントのコンテキストを保持します。
  • 再現性: 特定の状態をキャプチャし、それをベースとして、同じ初期化状態の新しいサンドボックスを複数起動します。

スナップショットは、次の 2 つの方法でトリガーできます。

  • 手動トリガー: 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)を介してこの権限がすでに付与されている可能性があります。それ以外の場合は、Service Usage 管理者ロール(roles/serviceusage.serviceUsageAdmin)を介してこの権限を取得できます。ロールを付与する方法を確認する。

    API を有効にする

  4. Google Cloud コンソールで Cloud Shell をアクティブにします。

    Cloud Shell をアクティブにする

要件

GKE Pod スナップショットには、GKE バージョン 1.35.3-gke.1234000 以降が必要です。Autopilot モードと標準モードの両方がサポートされています。

Pod スナップショットには gVisor が必要です。microVM サンドボックスでは動作しません。

Pod スナップショットには GKE Sandbox が必要なため、環境には特定の制限が適用されます。たとえば、Pod スナップショットは、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 など)。Pod スナップショットは、E2 マシンタイプをサポートしていません。ノードプール内のノードに GPU ベースのマシンタイプを使用する場合は、制限事項と要件をご覧ください。さまざまなマシンシリーズとさまざまなオプションの選択の詳細については、マシン ファミリーのリソースと比較ガイドをご覧ください。
  • SNAPSHOTS_BUCKET_NAME: スナップショットを保存するために作成する Cloud Storage バケットの名前。
  • SNAPSHOT_NAMESPACE: スナップショット ワークロードとサービス アカウントが存在する Kubernetes Namespace。
  • SNAPSHOT_KSA_NAME: ワークロードが認証に使用する Kubernetes サービス アカウントの名前。
  • SNAPSHOT_FOLDER: スナップショットが整理される Cloud Storage バケット内のディレクトリ。
  • PROJECT_NUMBER: IAM 権限バインディングに使用される、プロジェクトの一意の数値識別子。

構成手順の概要

GKE 環境で Agent Sandbox の Pod スナップショットを有効にするには、いくつかの構成手順を行う必要があります。これらの手順を理解するには、まずいくつかの重要なコンセプトを理解してから、スナップショット プロセスを理解することをおすすめします。

主なコンセプト

  • 環境: サンドボックス化されたアプリケーションは、GKE クラスタノードの Kubernetes Pod 内で実行されます。
  • ID: Pod は Kubernetes サービス アカウントに関連付けられ、作成した特別な Namespace で実行されます。Kubernetes サービス アカウントと Namespace は、Pod に Google Cloud リソースへの安全なアクセスを許可するために使用される一意の ID を形成します。
  • 権限: スナップショットを Cloud Storage に保存できるようにするには、Pod の ID に、Cloud Storage バケットへの書き込みを許可する特定の IAM 権限を付与する必要があります。

スナップショット プロセス

  1. トリガー: スナップショットが手動(外部)またはサンドボックス化されたワークロード自体によって開始されます。このドキュメントでは、PodSnapshotManualTrigger リソースを作成して開始する手動トリガーについて説明します。
  2. キャプチャ: GKE は、Pod のメモリやファイル システムの状態など、Pod の実行状態をキャプチャします。
  3. アップロード: Pod の Kubernetes サービス アカウントに付与された権限を使用して、GKE はキャプチャされた状態をスナップショット ファイルとして指定された Cloud Storage バケットにアップロードします。

GKE が Kubernetes サービス アカウントと IAM ロールを使用して Google Cloud リソースにアクセスする方法については、GKE ワークロードからGoogle Cloud API に対する認証を行うをご覧ください。

GKE 環境で Agent Sandbox の Pod スナップショットを有効にするには、次の構成を行います。まず、Workload Identity Federation for GKE と Pod スナップショット機能を有効にして GKE クラスタを作成し、クラスタ環境を準備します。次に、Cloud Storage と IAM ポリシーを構成して、スナップショットが安全に保存され、サンドボックスに必要な権限が付与されるようにします。最後に、サンドボックスのストレージ ロケーションとポリシーを指定するスナップショット リソースを作成します。

次の表に、実行する必要がある構成手順をまとめます。各手順については、以降のセクションで説明します。

トピック タスク
クラスタの設定 1. GKE クラスタを作成し、Pod スナップショット機能と Workload Identity Federation for GKE 機能を有効にします。
2. Agent Sandbox をデプロイする。
ストレージと権限を構成する 1. Cloud Storage バケットとマネージド フォルダを作成します。
2. カスタム IAM ロールを作成します。
3. Kubernetes Namespace と Kubernetes サービス アカウント(KSA)を作成します。
4. IAM ロールを Kubernetes サービス アカウントにバインドします。
5. スナップショット コントローラに権限を付与します。
スナップショット リソースを構成する 1. PodSnapshotStorageConfig リソースを作成する
2. PodSnapshotPolicy リソースを作成する
3. SandboxTemplate、SandboxWarmPool、SandboxClaim リソースを作成する

クラスタの設定

サンドボックス化されたアプリは GKE クラスタノードの Pod 内で実行されるため、クラスタ環境を設定する必要があります。このセクションでは、GKE クラスタを作成し、Agent Sandbox コントローラをデプロイする方法について説明します。

要件を満たす新しい GKE クラスタを作成する

Pod スナップショットを有効にして新しい GKE クラスタを作成します。Pod スナップショットには、GKE バージョン 1.35.3-gke.1234000 以降が必要です。次のコマンドは、デフォルト バージョンがこの要件を満たす Rapid リリース チャンネルにクラスタを登録します。

Autopilot

必要な機能を備えた Autopilot クラスタを作成します。

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

Standard

必要な機能を備えた Standard クラスタを作成します。費用を削減するため、次のコマンドでは、コントロール プレーンとノードを 1 つのゾーンで実行するゾーンクラスタを作成します。

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}

Standard

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

Agent Sandbox コントローラをクラスタにデプロイする

公式リリース マニフェストをクラスタに適用することで、Agent Sandbox コントローラとその必須コンポーネントをデプロイできます。このマニフェストは、クラスタに Agent Sandbox コントローラをデプロイして実行するために必要なすべてのコンポーネントをダウンロードするように Kubernetes に指示する構成ファイルです。

Agent Sandbox を GKE クラスタにデプロイするには、次のコマンドを実行します。

# 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-system 名前空間で Agent Sandbox コントローラ Pod が正しく実行されていることを確認します。前の手順でマニフェストを適用したときに、agent-sandbox-system Namespace が自動的に作成されました。

kubectl get pods -n agent-sandbox-system

Pod の STATUS 列に「Running」、READY 列に「1/1」が表示されるまで待ちます。Pod が正常に実行されている場合、出力は次のようになります。

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

Agent Sandbox コントローラが実行されると、クラスタに作成した Sandbox リソースのサンドボックス環境を自動的に作成して管理できます。

ストレージと権限を構成する

このセクションでは、Pod スナップショットに必要なストレージと権限を構成する方法について説明します。スナップショット データを保存する 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 がスナップショットを安全に保存できるようにするには、サンドボックス化されたワークロードを実行する Pod で使用される Kubernetes サービス アカウントに、バケットへの書き込み権限が必要です。この権限を付与するには、 Google CloudIAM ロールを Pod で使用される Kubernetes サービス アカウントにバインドします。このセクションでは、カスタム 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 を再利用できません。別のロール ID(podSnapshotGcsReadWriter2 など)を指定してコマンドを再度実行し、このドキュメントの残りの部分では podSnapshotGcsReadWriter の代わりにその ID を使用します。

  2. サンドボックスとそのサービス アカウントが存在する名前空間を作成します。

    kubectl create namespace "${SNAPSHOT_NAMESPACE}"
    
  3. 作成した Namespace に Kubernetes サービス アカウントを作成します。Kubernetes サービス アカウントと Namespace は、サンドボックスに 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 ロールを付与します。このバインディングにより、この特定のアカウントのみがマネージド フォルダにデータを書き込むことができます。新しいカスタムロールが使用可能になるまで数分かかることがあります。ロールが存在しないためにこのコマンドが失敗した場合は、1 分待ってからコマンドを再度実行します。

    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 ロールを付与します。このロールは、Pod スナップショット エージェントがマネージド フォルダに対してオペレーションを実行するために必要です。

    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 がスナップショットを保存する場所と、スナップショット プロセスを管理するルールを指定するには、次の 2 つのカスタム リソースを作成します。

  • PodSnapshotStorageConfig: このリソースは、GKE がスナップショット ファイルを保存する Cloud Storage バケットとフォルダの場所を指定します。
  • PodSnapshotPolicy: このリソースは、Kubernetes ラベルに基づいてスナップショットの対象となる Pod を定義します。また、スナップショットが手動か、サンドボックス ワークロードによって開始されるかなど、トリガールールも指定します。この例では、Agent Sandbox コントローラが各サンドボックスの Pod に追加する agents.x-k8s.io/sandbox-name-hash ラベルでスナップショットをグループ化します。このグループ化により、GKE は各サンドボックスを独自のスナップショットからのみ復元します。

両方のリソースを 1 つのステップで適用するには、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

Pod スナップショットは、E2 マシンタイプをサポートしていません。Autopilot では、GKE は Pod スナップショットをサポートしていないマシンタイプをデフォルトで使用する場合があります。ワークロードが互換性のあるハードウェアで実行されるようにするには、カスタム 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
    

Standard

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. クレームの準備が整うまで待ってから、クレームで使用するサンドボックスの名前を保存します。サンドボックスの Pod の名前は、サンドボックスと同じです。

    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 で実行され、スナップショットを作成する準備が整いました。

スナップショットの作成

このセクションでは、実行中のサンドボックスのスナップショットを手動でトリガーする方法について説明します。サンドボックス Pod をターゲットとするトリガー リソースを作成し、スナップショット プロセスが正常に完了したことを確認します。

  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 がターゲット Pod のスナップショットを正常にトリガーしたことを示します。

    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>
    

スナップショットから復元する

スナップショットをキャプチャした後、サンドボックスを一時停止してコンピューティング リソースを解放し、後で保存した状態からサンドボックスを再開できます。サンドボックスを一時停止すると、Agent Sandbox コントローラはサンドボックスの Pod を削除しますが、Sandbox リソースは保持します。サンドボックスを再開すると、コントローラが Pod を再作成し、Pod スナップショット コントローラがそのサンドボックスの最新のスナップショットから Pod を自動的に復元します。

  1. スナップショットの準備が完了するまで待ちます。GKE は、準備が完了しているスナップショットからのみ Pod を復元します。スナップショットの準備が整う前にサンドボックスを一時停止すると、再開時に保存された状態なしでサンドボックスが起動します。

    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 に設定し、コントローラがサンドボックスの Pod を削除するまで待ちます。

    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 から始まる場合、Pod はスナップショットから復元されずに起動しています。

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

このドキュメントで使用したリソースについて、 Google Cloud アカウントに課金されないようにするには、次の手順に沿って、作成したリソースを削除します。

  1. サンドボックス クレームとウォームプールを削除して、実行中の Pod を停止し、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. Namespace 内でスナップショットの対象となる Pod を定義するスナップショット ポリシーを削除します。

    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 Namespace を削除して、Kubernetes サービス アカウントと残りの Namespace メタデータを自動的に削除します。

    kubectl delete namespace "${SNAPSHOT_NAMESPACE}"
    
  7. GKE クラスタを削除して、基盤となるインフラストラクチャと、チュートリアルに関連付けられているすべてのノードを削除します。

    Autopilot

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

    Standard

    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}"
    

次のステップ