GKE Standard での高性能分散 RL: 完全ガイド

1. はじめに

このラボでは、GKE StandardGKE Agent Sandbox(gVisor)で、trl ライブラリの Group Relative Policy Optimization(GRPO)アルゴリズムを使用して、高性能の分散型強化学習(RL)トレーニング ループを構築、プロビジョニング、実行する方法について詳しく説明します。

このチュートリアルの目的は、RL トレーニング ループ中に信頼できない LLM 生成コードを安全に評価する方法を示すことです。これは、オーケストレーション プレーン(Ray)と実行プレーン(GKE Agent Sandbox)を分離することで実現します。

RL コード評価の技術的課題

強化学習を使用して LLM エージェントをトレーニングする場合(単体テストで出力を評価してコードを記述するモデルをトレーニングする場合など)、トレーニング ループで信頼できない LLM 生成の Python スクリプトを数千個並行して実行する必要があります。これには重大な課題があります。

  1. Pod Churn Bottleneck: 従来の評価フレームワークでは、タスクごとに新しい Docker コンテナが起動されます。RL トレーニング ループ中に数百の並列ロールアウトに対してこれを動的に行うと、Kubernetes コントロール プレーンに大きな負荷がかかります。レイテンシにより、高頻度の RL トレーニングは不可能になります。
  2. セキュリティ リスク: 標準のコンテナ ランタイム内で LLM 生成の任意のコードを実行すると、ホスト OS カーネルが共有されます。1 つのエスケープの脆弱性により、ノードが侵害される可能性があります。
  3. IAM トークンの盗難: Kubernetes Pod 内で実行されている LLM 生成コードが、クラウド プロバイダのメタデータ サーバーにクエリを実行して、ノードの IAM サービス アカウント トークンを盗む可能性があります。

解決策: オーケストレーションと実行の分離

このアーキテクチャでは、オーケストレーションと実行が分離されています。

  • オーケストレーター(Ray): 分散 Ray クラスタが RL トレーニング ループを管理し、ロールアウト生成を分散します。
  • 実行プレーン(GKE Agent Sandbox): Ray ワーカーは、Kubernetes Pod を動的に作成するのではなく、専用の Sandbox Router に単純な HTTP 呼び出しを行います。ルーターは、gVisor(GKE Sandbox)で実行されている分離された事前ウォーミング済みのコンテナをワーカーに即座に割り当てます。
  • 1 秒未満のレイテンシ: サンドボックスはマネージド SandboxWarmPool で事前ウォームアップされ、高速 HTTP ゲートウェイ経由で管理されるため、環境の作成は 200 ミリ秒未満に短縮され、Kubernetes コントロール プレーンを完全にバイパスします。

ラボの目標

この Codelab では、以下について学びます。

  • RL ループで信頼できないコードを評価するためのアーキテクチャ上の課題とソリューション。
  • 効率的なロールアウトのためのカスタム サンドボックス イメージをビルドする方法。
  • GKE Agent Sandbox と SandboxWarmPool を構成して使用する方法。
  • IAM トークンの盗難を防ぐためにサンドボックスを安全に分離する方法。
  • Ray を使用してオーケストレーションと実行を分離し、SweBench と TRL で基本的な RL トレーニング ジョブを実行する方法。

2. クラスタの作成と前提条件

続行する前に、高パフォーマンスの GPU ノードプールと、トレーニング ワークロードを管理するためにインストールされた Ray Operator を含む GKE クラスタが必要です。

前提条件

この Codelab では、次のツールがインストールされ、構成されていることを前提としています。

環境変数

まず、この Codelab 全体で使用する環境変数を設定します。次のコマンドでは、適切なデフォルト値を使用していますが、必要に応じて特定の Google Cloud 環境に合わせて変更できます。

export PROJECT_ID=$(gcloud config get-value project)
export REGION="us-west3"
export ZONE="us-west3-a"
export REPO_NAME="rl-sandbox-repo"

カスタム コンテナ イメージを保持する Artifact Registry リポジトリを作成します。

gcloud artifacts repositories create $REPO_NAME \
    --repository-format=docker \
    --location=$REGION \
    --description="Repository for RL Sandbox images"

クラスタ構成

AI ワークロード向けに最適化された GKE クラスタ(GPUDirect RDMA ネットワーク配線を含む)のプロビジョニングに関する完全なチュートリアルについては、公式ドキュメントの GKE AI Hypercompute カスタム クラスタを作成するをご覧ください。

重要な前提条件: クラスタまたは特定の実行ノードプールを作成するときは、--enable-agent-sandbox フラグと --sandbox type=gvisor フラグを渡して、Sandbox ウォームプールの必要なカスタム リソース定義(CRD)をインストールしてください。

クラスタ、GPU、Ray Operator が実行されていることを前提として、以下では実行プレーンを構成して RL ループを実行する方法について説明します。

3. カスタム イメージをビルドする

高パフォーマンスの RL を実行するうえで重要なのは、依存関係をイメージに組み込むことです。モデルを実行する GPU ワーカー用のイメージと、信頼できない評価コードを実行する分離されたサンドボックス用のイメージの 2 つの異なるイメージが必要です。

1. GPU ワーカー イメージをビルドする

Ray GPU ワーカーは、言語モデルを実行してトレーニング ループをオーケストレートするためにライブラリを必要とします。このイメージは公式の vLLM イメージの上に構築されているため、最新の GPU をサポートし、PyTorch/CUDA がプリインストールされています。

次のコマンドを実行して Dockerfile.gpu_worker を作成します。

cat << 'EOF' > Dockerfile.gpu_worker
# ==============================================================================
# Base Image: Use the official vLLM production image. 
# This image comes pre-baked with PyTorch 2.11, CUDA 13.0, and vLLM.
# It supports sm_100 Blackwell GPUs natively!
# ==============================================================================
FROM vllm/vllm-openai:latest

USER root

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    numactl \
    libnuma-dev \
    wget \
    ca-certificates \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Install Ray, TRL, and Sandbox tools
# TRL does not require compiling flash_attn from source.
RUN pip install --no-cache-dir \
    "ray[default]==2.55.1" \
    "numpy<2.0" \
    gymnasium>=0.28.1 \
    k8s-agent-sandbox>=0.4.6 \
    trl transformers packaging ninja cachetools accelerate datasets peft
EOF

イメージをビルドして Artifact Registry リポジトリに push します。

export WORKER_REPO="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ray-gpu-worker:v1"
docker build -f Dockerfile.gpu_worker -t $WORKER_REPO .
docker push $WORKER_REPO

注: このガイドでは、ローカルの docker コマンドを使用してイメージをビルドします。イメージをリモートでビルドする場合は、代わりに Cloud Buildgcloud builds submit など)を使用できます。

2. CPU ヘッダー画像をビルドする

Ray ヘッドノードはクラスタをオーケストレートするだけで、重い GPU トレーニング モデルは実行しません。標準の CPU ノードで大規模なイメージ プル ボトルネック(通常は 15 GB 以上)が発生しないように、ヘッドノード用に軽量の CPU 専用イメージをビルドします。このイメージには Ray と必要な Python ライブラリが含まれていますが、CUDA や vLLM などの重い GPU ライブラリは含まれていません。

次のコマンドを実行して Dockerfile.head を作成します。

cat << 'EOF' > Dockerfile.head
# ==============================================================================
# Base Image: Use the official Python slim image for the exact patch version.
# This aligns the Python version (3.12.13) with the GPU worker node.
# ==============================================================================
FROM python:3.12.13-slim

USER root

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    wget \
    ca-certificates \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Install Ray, TRL, and Sandbox tools (CPU versions where applicable)
# We install torch CPU first to avoid pulling the 2GB+ CUDA torch package.
RUN pip install --no-cache-dir torch --index-url https://download.pytorch.org/whl/cpu && \
    pip install --no-cache-dir \
    "ray[default]==2.55.1" \
    "numpy<2.0" \
    gymnasium>=0.28.1 \
    k8s-agent-sandbox>=0.4.6 \
    trl transformers packaging ninja cachetools accelerate datasets peft

# Create a 'ray' user to run the container securely and match Ray conventions
RUN useradd -ms /bin/bash ray
USER ray
WORKDIR /home/ray
EOF

イメージをビルドして push します。

export HEAD_REPO="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ray-head:v1"
docker build -f Dockerfile.head -t $HEAD_REPO .
docker push $HEAD_REPO

3. サンドボックス イメージをビルドする

サンドボックスには、評価するタスクの特定の依存関係が必要です。これにより、ランタイム インストールが瞬時に行われます。この Codelab では、SWE-bench の django/django リポジトリの問題を使用します。リポジトリを事前にクローンし、Python 環境を事前にビルドして、モデル スクリプトが RL ループでダウンロードに時間を費やさないようにします。

次のコマンドを実行して Dockerfile.sandbox を作成します。

cat << 'EOF' > Dockerfile.sandbox
# Use a stable Debian-based Miniconda image
FROM condaforge/miniforge3:latest

# 1. Install essential system libraries (including sqlite3 for Django tests)
RUN apt-get update && apt-get install -y \
    git \
    build-essential \
    libsqlite3-dev \
    && rm -rf /var/lib/apt/lists/*

# 2. Set up the /workspace directory and grant ownership to the pre-existing non-root 'ubuntu' user (UID 1000)
RUN mkdir -p /workspace \
    && chown -R 1000:1000 /workspace

# 3. Switch to the non-root user
USER ubuntu
WORKDIR /workspace

# 4. Pre-configure Git globally so the agent can run git commands
RUN git config --global user.email "agent@gke-sandbox.local" \
    && git config --global user.name "Agent"

# 5. Pre-clone the repository as the non-root user
RUN git clone https://github.com/django/django.git .

# 6. Pre-build Conda environments and pre-cache common dependencies
# We do NOT run "pip install -e ." here to avoid Python version conflicts with the main branch.
# Instead, we pre-install the heavy dependencies so that runtime installation is instantaneous.
RUN conda create -y -n django-py39 python=3.9 \
    && conda run -n django-py39 pip install --no-cache-dir asgiref sqlparse tzdata pytest pytest-django

RUN conda create -y -n django-py310 python=3.10 \
    && conda run -n django-py310 pip install --no-cache-dir asgiref sqlparse tzdata pytest pytest-django

# --- Add Agent Server ---
# We use a multi-stage build to copy the agent server from the official python-runtime-sandbox image
COPY --from=registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0 /app /opt/sandbox-agent
USER root
RUN chown -R 1000:1000 /opt/sandbox-agent \
    && /opt/conda/bin/pip install --no-cache-dir -r /opt/sandbox-agent/requirements.txt \
    && sed -i 's|"/app"|"/workspace"|g' /opt/sandbox-agent/main.py
USER ubuntu
# ------------------------

# Prepend the django-py39 conda environment bin to PATH for commands executed inside the container
ENV PATH=/home/ubuntu/.conda/envs/django-py39/bin:$PATH

# Keep the container alive and run the agent server using the system Python
CMD ["/opt/conda/bin/python3", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8888", "--log-level", "trace", "--app-dir", "/opt/sandbox-agent"]
EOF

イメージをビルドして push します。

export SANDBOX_REPO="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/django-sandbox:v1"
docker build -f Dockerfile.sandbox -t $SANDBOX_REPO .
docker push $SANDBOX_REPO

4. オーケストレーションと実行を構成する

オーケストレーション用の Ray クラスタと実行用の Sandbox リソースをデプロイします。

1. Ray クラスタの構成

RayCluster カスタム リソースをデプロイします。クラスタで使用可能なリソース(メモリ、CPU、GPU のタイプなど)は異なる場合があります。resources のリクエストと上限を適宜調整します。

次のコマンドを実行して raycluster.yaml を作成します。これは、cat << EOF を使用して、環境変数をマニフェストに自動的に置き換えます。

cat << EOF > raycluster.yaml
apiVersion: ray.io/v1
kind: RayCluster
metadata:
  name: grpo-cluster
  namespace: default
spec:
  rayVersion: "2.55.1"
  headGroupSpec:
    rayStartParams:
      dashboard-host: "0.0.0.0"
    template:
      spec:
        containers:
        - name: ray-head
          image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ray-head:v1
          ports:
          - containerPort: 6379
            name: gcs-server
          - containerPort: 8265
            name: dashboard
          - containerPort: 10001
            name: client
          resources:
            limits:
              cpu: "2"
              memory: "8Gi"
            requests:
              cpu: "2"
              memory: "8Gi"
  workerGroupSpecs:
  - groupName: gpu-group
    replicas: 1
    minReplicas: 1
    maxReplicas: 1
    rayStartParams: {}
    template:
      spec:
        containers:
        - name: ray-worker
          image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/ray-gpu-worker:v1
          resources:
            limits:
              cpu: "12"
              memory: "120Gi"
              nvidia.com/gpu: "1"
            requests:
              cpu: "12"
              memory: "120Gi"
              nvidia.com/gpu: "1"
EOF

適用します。

kubectl apply -f raycluster.yaml

クラスタが作成され、実行されていることを確認します(数分かかることがあります)。

kubectl get raycluster

予想される出力:

NAME       DESIRED WORKERS   AVAILABLE WORKERS   CPUS   MEMORY   GPUS   STATUS   AGE
rl-cluster   1                 1                                            ready    2m

2. SandboxRouter の構成

SandboxRouter は高速 HTTP ゲートウェイとして機能し、Ray ワーカーからのリクエストを処理して、使用可能な gVisor Pod に瞬時にブリッジします。これにより、低速の Kubernetes API サーバー Pod のライフサイクルをバイパスします。

次のコマンドを実行して sandbox_router.yaml を作成します。

cat << 'EOF' > sandbox_router.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: sandbox-claim-manager
rules:
- apiGroups: ["extensions.agents.x-k8s.io"]
  resources: ["sandboxclaims"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["agents.x-k8s.io"]
  resources: ["sandboxes"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: sandbox-claim-manager-binding
  namespace: default
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: Role
  name: sandbox-claim-manager
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Service
metadata:
  name: sandbox-router
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: sandbox-router
  ports:
  - name: http
    protocol: TCP
    port: 8080
    targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sandbox-router-deployment
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: sandbox-router
  template:
    metadata:
      labels:
        app: sandbox-router
    spec:
      containers:
      - name: router
        image: us-central1-docker.pkg.dev/k8s-staging-images/agent-sandbox/sandbox-router:latest-main
        ports:
        - containerPort: 8080
        env:
        - name: ALLOW_UNAUTHENTICATED_ROUTER
          value: "true"
EOF

適用します。

kubectl apply -f sandbox_router.yaml

デプロイが実行されていることを確認します。

kubectl get deployment sandbox-router-deployment

予想される出力:

NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
sandbox-router-deployment   2/2     2            2           1m

3. SandboxTemplate と WarmPool の構成

GKE Agent Sandbox では、Sandbox Router を使用して、分離された事前ウォーム コンテナを即座に割り当てることができます。Pod を準備状態に保つために、SandboxTemplateSandboxWarmPool を定義します。

次のコマンドを実行して、環境変数を使用して sandbox_warmpool.yaml を作成します。

cat << EOF > sandbox_warmpool.yaml
apiVersion: extensions.agents.x-k8s.io/v1alpha1
kind: SandboxTemplate
metadata:
  name: swe-bench-django
  namespace: default
spec:
  podTemplate:
    spec:
      runtimeClassName: gvisor
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
      nodeSelector:
        sandbox.gke.io/runtime: gvisor
      tolerations:
      - key: sandbox.gke.io/runtime
        operator: Equal
        value: gvisor
        effect: NoSchedule
      containers:
      - name: sandbox
        image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/django-sandbox:v1
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
        resources:
          requests:
            cpu: "2"
            memory: "4Gi"
          limits:
            cpu: "2"
            memory: "4Gi"
---
apiVersion: extensions.agents.x-k8s.io/v1alpha1
kind: SandboxWarmPool
metadata:
  name: swe-bench-django-warmpool
  namespace: default
spec:
  replicas: 10
  sandboxTemplateRef:
    name: swe-bench-django
EOF

適用します。

kubectl apply -f sandbox_warmpool.yaml

SandboxWarmPool が初期化されていることを確認します。

kubectl get sandboxwarmpool

予想される出力:

NAME                        READY   AGE
swe-bench-django-warmpool   10      1m

4. セキュリティ分離

NetworkPolicy はサンドボックスを厳密に分離し、GCP メタデータ サーバーへの下り(外向き)を禁止することで、IAM トークンの盗難を防ぎます。

次のコマンドを実行して network_policy.yaml を作成します。

cat << 'EOF' > network_policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: block-metadata-egress
  namespace: default
spec:
  podSelector:
    matchLabels:
      sandbox.gke.io/runtime: gvisor
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 169.254.169.254/32
EOF

ポリシーを適用します。

kubectl apply -f network_policy.yaml

NetworkPolicy が作成されたことを確認します。

kubectl get networkpolicy

予想される出力:

NAME                 POD-SELECTOR     AGE
block-metadata-egress             sandbox.gke.io/runtime=gvisor     1m

5. SweBench と TRL を使用した基本的な RL ジョブ

クラスタとサンドボックスの準備ができたら、GRPO トレーニング ループを実行できます。trl ライブラリを使用して GRPO アルゴリズムをオーケストレートし、ray リモート関数を使用して分離されたサンドボックス内で生成されたコードを評価します。

この Codelab の実行を高速化するため、1 つの Django の問題に絞り込みます。次のルーティング ロジックは、リポジトリごとに異なるウォームプールを選択する方法を示しています。これは、SWE-bench データセット全体に拡張する場合に便利です。

トレーニング スクリプト

次のコマンドを実行して train_trl.py を作成します。

cat << 'EOF' > train_trl.py
import ray
from k8s_agent_sandbox import SandboxClient
from k8s_agent_sandbox.models import SandboxDirectConnectionConfig
from trl import GRPOConfig, GRPOTrainer
from transformers import AutoModelForCausalLM, AutoTokenizer
from datasets import load_dataset
import urllib.request
import re

ray.init(ignore_reinit_error=True)

# 1. Define the Ray remote evaluation function
@ray.remote
def evaluate_rollout(code, prompt_data):
    client = SandboxClient(connection_config=SandboxDirectConnectionConfig(api_url="http://sandbox-router.default.svc.cluster.local:8080"))
    
    # Claim a pre-warmed sandbox instantly based on the repo
    repo = prompt_data.get("repo")
    
    # In a full system, you'd route to different warmpools based on repo
    # Here we default to django for our single task
    sandbox = client.create_sandbox(
        template="swe-bench-django",
        warmpool="swe-bench-django-warmpool",
        sandbox_ready_timeout=600
    )
    
    try:
        # Check if the code is correctly formatted
        bash_match = re.search(r"```bash\n(.*?)\n```", code, re.DOTALL)
        if not bash_match:
            return 0.0
            
        script = bash_match.group(1)

        # In a real environment, we would apply the base commit and install here
        # For simplicity, we just execute the script
        import shlex
        script_cmd = f"bash -c {shlex.quote(script)}"
        result = sandbox.commands.run(script_cmd, timeout=60)
        
        # Calculate continuous reward based on test passage ratio
        if result.exit_code == 0:
            return 1.0
        
        # Very simple heuristic reward
        return 0.1
        
    finally:
        # Clean up and release the sandbox back to the pool
        client.delete_sandbox(sandbox.claim_name)

# 2. Define the Reward Function for TRL
def sandbox_reward_func(prompts, completions, **kwargs):
    # Dispatch evaluation to Ray cluster
    futures = [
        evaluate_rollout.remote(completion, {
            "repo": kwargs.get('repo', [])[i] if 'repo' in kwargs else None,
            "base_commit": kwargs.get('base_commit', [])[i] if 'base_commit' in kwargs else None
        }) for i, completion in enumerate(completions)
    ]
    
    # Block and wait for all sandbox evaluations to complete
    rewards = ray.get(futures)
    return rewards

# 3. Setup GRPO Trainer
@ray.remote(num_gpus=1, num_cpus=8)
def train():
    # Load dataset
    dataset = load_dataset("princeton-nlp/SWE-bench_Lite", split="test")
    # Filter to our selected target issue
    dataset = dataset.filter(lambda x: x["instance_id"] == "django__django-15388")
    
    def format_dataset(example):
        files = re.findall(r'^\+\+\+ b/(.+)$', example["patch"], re.MULTILINE)
        target_file = files[0] if files else ""
        
        file_content = ""
        if target_file:
            try:
                github_repo = example["repo"]
                url = f"https://raw.githubusercontent.com/{github_repo}/{example['base_commit']}/{target_file}"
                with urllib.request.urlopen(url) as response:
                    file_content = response.read().decode('utf-8')
            except Exception as e:
                pass
                
        prompt = f"""You are an expert software engineer.
You are given a GitHub issue and the content of the file that contains the bug.
Write an executable bash script that will modify the target file to fix the bug (e.g. using cat << 'EOF' > {target_file} or inline python edits).
Wrap your bash script in ```bash ... ``` tags. Do not output raw python code directly.

Target File: {target_file}

Original File Content:
```python
{file_content}
```

Issue:
{example['problem_statement']}
"""
        return {
            "prompt": prompt,
            "repo": example["repo"],
            "instance_id": example["instance_id"],
            "base_commit": example["base_commit"],
        }
        
    dataset = dataset.map(format_dataset)

    model_name = "Qwen/Qwen2.5-Coder-1.5B-Instruct"
    tokenizer = AutoTokenizer.from_pretrained(model_name)

    training_args = GRPOConfig(
        output_dir="outputs",
        learning_rate=5e-6,
        max_steps=50,
        per_device_train_batch_size=1,
        gradient_accumulation_steps=4,
        num_generations=4,
    )

    trainer = GRPOTrainer(
        model=model_name,
        processing_class=tokenizer,
        reward_funcs=[sandbox_reward_func],
        args=training_args,
        train_dataset=dataset,
    )

    print("Starting GRPO training with GKE Agent Sandboxes...")
    trainer.train()

def main():
    print("Submitting training job to GPU worker...")
    ray.get(train.remote())

if __name__ == "__main__":
    main()
EOF

クラスタにジョブを送信する

まず、Ray Head ダッシュボードにポート転送し、ローカルマシンからトレーニング ジョブを送信します。

kubectl port-forward service/grpo-cluster-head-svc 8265:8265 &

ray job submit \
  --address http://localhost:8265 \
  --runtime-env-json '{"working_dir": "."}' \
  -- python train_trl.py

実行をモニタリングする

実行の進行状況をモニタリングできます。

  • Ray ダッシュボード: ブラウザで http://localhost:8265 を開きます。
  • サンドボックスの要求: GKE が gVisor の下でサンドボックスを動的に要求して解放する様子を確認します。
    watch -n 1 "kubectl get sandboxclaims,sandboxes,pods"
    

6. まとめ

おめでとうございます!GKE Agent Sandbox を使用して、GKE Standard で高パフォーマンスの分散 RL トレーニング ループを安全に構成して実行しました。