1. 소개
이 실습에서는 trl 라이브러리와 함께 그룹 상대 정책 최적화 (GRPO) 알고리즘을 사용하여 GKE 에이전트 샌드박스 (gVisor)가 있는 GKE Standard에서 고성능 분산 강화 학습 (RL) 학습 루프를 빌드, 프로비저닝, 실행하는 방법을 자세히 설명합니다.
목표는 RL 학습 루프 중에 신뢰할 수 없는 LLM 생성 코드를 안전하게 평가하는 방법을 보여주는 것입니다. 오케스트레이션 플레인 (Ray)을 실행 플레인 (GKE 에이전트 샌드박스)에서 분리하여 이를 달성합니다.
RL 코드 평가의 기술적 과제
강화 학습을 사용하여 LLM 에이전트를 학습시킬 때 (예: 단위 테스트에서 출력을 평가하여 코드를 작성하는 모델 학습) 학습 루프는 신뢰할 수 없는 LLM 생성 Python 스크립트를 수천 개 병렬로 실행해야 합니다. 이로 인해 다음과 같은 심각한 문제가 발생합니다.
- 포드 처닝 병목 현상: 기존 평가 프레임워크는 작업당 새 Docker 컨테이너를 실행합니다. RL 학습 루프 중에 수백 개의 병렬 출시를 위해 이를 동적으로 실행하면 Kubernetes 컨트롤 플레인에 심각한 부하가 발생합니다. 지연 시간으로 인해 고빈도 RL 학습이 불가능합니다.
- 보안 위험: 표준 컨테이너 런타임 내에서 임의의 LLM 생성 코드를 실행하면 호스트 OS 커널이 공유됩니다. 단일 이스케이프 취약점으로 노드가 손상될 수 있습니다.
- IAM 토큰 도용: Kubernetes 포드 내에서 실행되는 LLM 생성 코드는 클라우드 제공업체의 메타데이터 서버를 쿼리하여 노드 IAM 서비스 계정 토큰을 도용할 수 있습니다.
해결책: 오케스트레이션 및 실행 분리
이 아키텍처는 실행에서 오케스트레이션을 분리합니다.
- 조정자 (Ray): 분산 Ray 클러스터는 RL 학습 루프를 관리하고 출시 생성을 분산합니다.
- 실행 플레인 (GKE 에이전트 샌드박스): Ray 작업자는 Kubernetes 포드를 동적으로 만드는 대신 전용 샌드박스 라우터에 간단한 HTTP 호출을 합니다. 라우터는 작업자에게 gVisor (GKE Sandbox)에서 실행되는 격리된 사전 워밍 컨테이너를 즉시 할당합니다.
- 1초 미만의 지연 시간: 샌드박스가 관리형
SandboxWarmPool에서 사전 워밍되고 고속 HTTP 게이트웨이를 통해 관리되므로 환경 생성이 200ms 미만으로 줄어들어 Kubernetes 컨트롤 플레인을 완전히 우회합니다.
실습 목표
이 Codelab에서는 다음에 관해 알아봅니다.
- RL 루프에서 신뢰할 수 없는 코드를 평가하기 위한 아키텍처 문제와 솔루션
- 효율적인 출시를 위해 맞춤 샌드박스 이미지를 빌드하는 방법
- GKE 에이전트 샌드박스 및 SandboxWarmPool을 구성하고 사용하는 방법
- IAM 토큰 도용을 방지하기 위해 샌드박스를 안전하게 격리하는 방법
- Ray를 사용하여 오케스트레이션을 실행에서 분리하여 SweBench 및 TRL로 기본 RL 학습 작업을 실행하는 방법
2. 클러스터 생성 및 기본 요건
계속하기 전에 고성능 GPU 노드 풀이 있고 학습 워크로드를 관리하기 위해 Ray Operator가 설치된 GKE 클러스터가 필요합니다.
기본 요건
이 Codelab에서는 다음 도구가 설치되고 구성되었다고 가정합니다.
- Google Cloud SDK (
gcloud) - Docker (로컬에서 맞춤 이미지를 빌드하는 데 필요)
kubectl
환경 변수
먼저 이 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 맞춤 클러스터 만들기를 참고하세요.
중요한 사전 요구사항: 클러스터 또는 특정 실행 노드 풀을 만들 때 샌드박스 워밍 풀에 필요한 커스텀 리소스 정의 (CRD)를 설치하도록 --enable-agent-sandbox 및 --sandbox type=gvisor 플래그를 전달해야 합니다.
클러스터, GPU, Ray Operator가 실행 중이라고 가정하면 아래에서는 실행 플레인을 구성하고 RL 루프를 실행하는 방법을 자세히 설명합니다.
3. 맞춤 이미지 빌드
고성능 RL을 실행하는 데 있어 중요한 측면은 종속 항목을 이미지에 포함하는 것입니다. 모델을 실행하는 GPU 작업자와 신뢰할 수 없는 평가 코드를 실행하는 격리된 샌드박스용으로 각각 다른 이미지가 두 개 필요합니다.
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 저장소에 푸시합니다.
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 Build를 대신 사용할 수 있습니다 (예: gcloud builds submit 사용).
2. CPU 헤드 이미지 빌드
Ray 헤드 노드는 클러스터만 오케스트레이션하며 대량의 GPU 학습 모델을 실행하지 않습니다. 표준 CPU 노드에서 대규모 이미지 풀 병목 현상 (일반적으로 15GB 이상)을 방지하기 위해 헤드 노드용 경량 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
이미지를 빌드하고 푸시합니다.
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 저장소에 있는 문제를 사용합니다. 모델 스크립트가 RL 루프에서 다운로드하는 데 시간을 낭비하지 않도록 저장소를 미리 클론하고 Python 환경을 미리 빌드합니다.
다음 명령어를 실행하여 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
이미지를 빌드하고 푸시합니다.
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 클러스터와 실행을 위한 샌드박스 리소스를 배포합니다.
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 포드로 즉시 연결하여 느린 Kubernetes API 서버 포드 수명 주기를 우회합니다.
다음 명령어를 실행하여 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 에이전트 샌드박스를 사용하면 샌드박스 라우터를 사용하여 격리되고 사전 워밍된 컨테이너를 즉시 할당할 수 있습니다. 포드를 준비된 상태로 유지하기 위해 SandboxTemplate 및 SandboxWarmPool를 정의합니다.
다음 명령어를 실행하여 환경 변수를 사용하여 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에서 실행 속도를 높이기 위해 단일 Django 문제로 필터링합니다. 아래 라우팅 로직은 다양한 저장소에 대해 다양한 warmpool을 선택하는 방법을 보여줍니다. 이는 전체 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 에이전트 샌드박스를 사용하여 GKE Standard에서 고성능 분산 RL 학습 루프를 안전하게 구성하고 실행했습니다.