이 튜토리얼에서는 Google Kubernetes Engine (GKE)에서 강화 학습을 위한 분산 학습 환경을 오케스트레이션하는 방법을 보여줍니다. Ray와 verl (Volcano Engine Reinforcement Learning) 프레임워크를 사용하여 분산 학습 환경을 설정하여 GSM8K 데이터 세트에서 Qwen2.5-32B-Instruct 모델을 미세 조정합니다.
이 튜토리얼에서는 Ray 및 verl을 사용하여 GKE에서 그룹 상대 정책 최적화 (GRPO) 학습 파이프라인에 중점을 둡니다. GRPO는 모델의 추론 능력을 향상하도록 설계된 강화 학습 알고리즘입니다. 이 메모리 효율적인 알고리즘은 Critic 또는 가치 모델을 제거하고 대신 상대적인 그룹 기반 계산을 사용하여 강화 학습 (RL) 프로세스를 간소화합니다.
이 튜토리얼은 효율성을 위해 데이터, 모델 가중치, 학습 엔진이 분리된 분산 학습 환경을 설정해야 하는 경우 좋은 출발점이 될 수 있습니다.
이 튜토리얼에서는 다음 GPU 아키텍처를 지원합니다.
- Intel 또는 AMD 기반 GPU 노드: NVIDIA B200 또는 H200 GPU를 사용하여 설정하고 확장합니다.
- Arm 기반 A4X (GB200) 노드: GKE 동적 리소스 할당 (DRA) 및 멀티 노드 NVLink (IMEX)를 사용하여 NVIDIA GB200 Grace Blackwell Superchips를 통해 설정하고 확장합니다.
배경
다음 섹션에서는 이 튜토리얼에서 사용되는 개념을 간략하게 설명합니다.
강화 학습 (RL)
강화 학습은 정적인 모방이 아닌 경험, 탐색, 피드백을 통해 모델을 학습시킵니다. 사전 학습을 통해 모델에 말해야 할 내용을 가르치는 반면, 인간 피드백 기반 강화 학습 (RLHF)을 통해 유용하고 안전하며 논리적인 방법을 가르칩니다. RL은 기본 모델과 특수 사용 사례를 위해 미세 조정된 모델 간의 다리 역할을 합니다.
자세한 내용은 강화 학습이란 무엇인가요?를 참고하세요.
그룹 상대 정책 최적화 (GRPO)
DeepSeek에서 널리 사용되는 알고리즘인 GRPO는 비평가 모델을 삭제하여 LLM 정렬을 위한 근위 정책 최적화 (PPO)의 메모리 효율적인 대안을 제공합니다. 비평가 네트워크 대신 GRPO는 동일한 프롬프트에 대한 응답 그룹을 생성하고 해당 그룹의 평균 보상을 기준선으로 사용합니다.
자세한 내용은 GRPO를 참고하세요.
Volcano Engine 강화 학습 (verl)
verl은 LLM 기반 RL의 복잡한 메모리 및 컴퓨팅 패턴을 처리하도록 설계된 고성능 프레임워크입니다.
자세한 내용은 verl을 참고하세요.
목표
이 튜토리얼에서는 다음 단계를 완료하여 verl을 사용하여 GKE에서 강화 학습을 설정하는 방법을 보여줍니다.
- A4X (GB200 Superchips), A4 (B200 GPU) 또는 A3 Ultra (H200 GPU)로 GKE 클러스터를 설정합니다.
- 분산 Ray 클러스터를 관리하도록 KubeRay를 구성합니다.
- Cloud Storage FUSE를 사용하여 모든 노드에 Cloud Storage 버킷을 마운트합니다.
- verl을 사용하여 GRPO 학습 작업을 실행하여 Qwen2.5-32B-Instruct 모델을 GSM8K 데이터 세트와 정렬합니다.
시작하기 전에
- Google Cloud 계정에 로그인합니다. Google Cloud를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
-
Google Cloud CLI를 설치합니다.
-
외부 ID 공급업체(IdP)를 사용하는 경우 먼저 제휴 ID로 gcloud CLI에 로그인해야 합니다.
-
gcloud CLI를 초기화하려면, 다음 명령어를 실행합니다.
gcloud init -
Google Cloud 프로젝트를 만들거나 선택합니다.
프로젝트를 선택하거나 만드는 데 필요한 역할
- 프로젝트 선택: 프로젝트를 선택하는 데는 특정 IAM 역할이 필요하지 않습니다. 역할이 부여된 프로젝트를 선택하면 됩니다.
-
프로젝트 만들기: 프로젝트를 만들려면
resourcemanager.projects.create권한이 포함된 프로젝트 생성자 역할(roles/resourcemanager.projectCreator)이 필요합니다. 역할 부여 방법 알아보기
-
Google Cloud 프로젝트를 만듭니다.
gcloud projects create PROJECT_ID
PROJECT_ID를 만들려는 Google Cloud 프로젝트의 이름으로 바꿉니다. -
만든 Google Cloud 프로젝트를 선택합니다.
gcloud config set project PROJECT_ID
PROJECT_ID을 Google Cloud 프로젝트 이름으로 바꿉니다.
필요한 API를 사용 설정합니다.
API 사용 설정에 필요한 역할
API를 사용 설정하려면
serviceusage.services.enable권한이 포함된 서비스 사용량 관리자 IAM 역할 (roles/serviceusage.serviceUsageAdmin)이 필요합니다. 역할 부여 방법 알아보기gcloud services enable container.googleapis.com
storage.googleapis.com compute.googleapis.com -
Google Cloud CLI를 설치합니다.
-
외부 ID 공급업체(IdP)를 사용하는 경우 먼저 제휴 ID로 gcloud CLI에 로그인해야 합니다.
-
gcloud CLI를 초기화하려면, 다음 명령어를 실행합니다.
gcloud init -
Google Cloud 프로젝트를 만들거나 선택합니다.
프로젝트를 선택하거나 만드는 데 필요한 역할
- 프로젝트 선택: 프로젝트를 선택하는 데는 특정 IAM 역할이 필요하지 않습니다. 역할이 부여된 프로젝트를 선택하면 됩니다.
-
프로젝트 만들기: 프로젝트를 만들려면
resourcemanager.projects.create권한이 포함된 프로젝트 생성자 역할(roles/resourcemanager.projectCreator)이 필요합니다. 역할 부여 방법 알아보기
-
Google Cloud 프로젝트를 만듭니다.
gcloud projects create PROJECT_ID
PROJECT_ID를 만들려는 Google Cloud 프로젝트의 이름으로 바꿉니다. -
만든 Google Cloud 프로젝트를 선택합니다.
gcloud config set project PROJECT_ID
PROJECT_ID을 Google Cloud 프로젝트 이름으로 바꿉니다.
필요한 API를 사용 설정합니다.
API 사용 설정에 필요한 역할
API를 사용 설정하려면
serviceusage.services.enable권한이 포함된 서비스 사용량 관리자 IAM 역할 (roles/serviceusage.serviceUsageAdmin)이 필요합니다. 역할 부여 방법 알아보기gcloud services enable container.googleapis.com
storage.googleapis.com compute.googleapis.com -
사용자 계정에 역할을 부여합니다. 다음 IAM 역할마다 다음 명령어를 1회 실행합니다.
roles/container.admin, roles/iam.serviceAccountAdmin, roles/storage.admingcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE
다음을 바꿉니다.
PROJECT_ID: 프로젝트 ID입니다.USER_IDENTIFIER: 사용자 계정의 식별자입니다. 예를 들면myemail@example.com입니다.ROLE: 사용자 계정에 부여할 IAM 역할입니다.
- Hugging Face 계정이 아직 없으면 이 계정을 만듭니다.
- Hugging Face 토큰이 있는지 확인합니다.
- 프로젝트에 A4X (GB200 Superchip), A4 (B200 GPU) 또는 A3 Ultra (H200 GPU) 할당량이 충분한지 확인합니다. 자세한 내용은 GPU 할당량 계획 및 GPU 할당량을 참고하세요.
- GPU 머신 유형에 대해 활성 용량 예약이 있는지 확인합니다. 자세한 내용은 계정팀을 통해 용량 예약을 참고하세요.
- A4X (GB200) 설정의 경우 Helm이 설치되어 있는지 확인합니다.
개발 환경 준비
이 튜토리얼에서는 Cloud Shell을 사용합니다.
Google Cloud 콘솔로 이동합니다.
Google Cloud 콘솔 창 상단에서 Cloud Shell 활성화 버튼을 클릭합니다.
환경 변수를 설정합니다.
export PROJECT_ID=$(gcloud config get project) export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)") export CONTROL_PLANE_REGION=CONTROL_PLANE_REGION export NODE_ZONE=NODE_ZONE export CLUSTER_NAME=CLUSTER_NAME export KSA_NAME=KSA_NAME export GS_BUCKET=BUCKET_NAME-${PROJECT_ID} export NAMESPACE=default export GPU_TYPE=GPU_TYPE export MACHINE_TYPE=MACHINE_TYPE export RESERVATION=RESERVATION export HF_TOKEN=YOUR_HUGGING_FACE_TOKEN # A4 (B200 GPUs) or A3 Ultra (H200 GPUs) only variables export GVNIC_NETWORK_PREFIX=YGVNIC_NAME export RDMA_NETWORK_PREFIX=RDMA_NAME # A4X (GB200 Superchips) only variables export NUM_GPU_NODES=4 export VERL_IMAGE=verlai/verl:vllm023.aarch64.dev1 export VERL_REF=ddbcdb7다음 값을 바꿉니다.
CONTROL_PLANE_REGION: GKE 클러스터 컨트롤 플레인의 Compute Engine 리전입니다.NODE_ZONE: 노드가 예약된 영역입니다. 자세한 내용은 GPU 가용성을 참고하세요.CLUSTER_NAME: GKE 클러스터의 이름입니다.KSA_NAME: Kubernetes 서비스 계정의 이름입니다.BUCKET_NAME: Cloud Storage 버킷의 기본 이름입니다.gs://접두사를 지정할 필요가 없습니다.GPU_TYPE: Compute Engine 용량 예약에서 예약한 가속기. 다음 값 중 하나여야 합니다.nvidia-gb200: A4X (GB200 Superchips)nvidia-b200: A4 (B200 GPU)nvidia-h200-141gb: A3 Ultra (H200 GPU)
MACHINE_TYPE: 사용할 머신 유형입니다.- A4X (GB200 Superchips)의 경우
a4x-highgpu-4g를 사용합니다. - A4 (B200 GPU)의 경우
a4-highgpu-8g이상을 사용합니다. - A3 Ultra (H200 GPU)의 경우
a3-ultragpu-8g이상을 사용합니다.
- A4X (GB200 Superchips)의 경우
RESERVATION: 용량 예약의 이름입니다.YOUR_HUGGING_FACE_TOKEN: Hugging Face 토큰입니다.GVNIC_NAME(A4 또는 A3 Ultra만 해당): gVNIC 네트워크 이름의 접두사입니다. 원하는 접두사를 사용할 수 있습니다.RDMA_NAME(A4 또는 A3 Ultra만 해당): 원격 직접 메모리 액세스 (RDMA) 네트워크의 접두사입니다. 원하는 접두사를 사용할 수 있습니다.
인프라 설정
이 섹션에서는 표준 VPC 네트워크와 GKE 클러스터를 만듭니다.
RDMA 네트워크 및 서브넷 만들기 (A4 및 A3 Ultra만 해당)
이 섹션은 A4 및 A3 Ultra GPU에만 필요합니다.
A4X (GB200) GPU를 사용하는 경우 이 섹션을 건너뛰고 GKE 클러스터 만들기로 바로 진행하세요. A4X (GB200) GPU의 경우 노드 풀에서 auto 가속기 네트워크 프로필을 사용하면 GKE에서 네트워크를 자동으로 만듭니다. Cluster Toolkit 청사진은 enable_dranet:true 플래그를 사용하여 이 프로필을 사용 설정합니다.
gVNIC 인터페이스의 VPC 네트워크를 만듭니다.
gcloud compute networks create ${GVNIC_NETWORK_PREFIX}-net \ --subnet-mode=custom \ --project=${PROJECT_ID} gcloud compute networks subnets create ${GVNIC_NETWORK_PREFIX}-sub \ --network=${GVNIC_NETWORK_PREFIX}-net \ --region=${CONTROL_PLANE_REGION} \ --range=192.168.0.0/24 gcloud compute firewall-rules create ${GVNIC_NETWORK_PREFIX}-internal \ --network=${GVNIC_NETWORK_PREFIX}-net \ --action=ALLOW \ --rules=tcp:0-65535,udp:0-65535,icmp \ --source-ranges=192.168.0.0/168개의 GPU에 대해 8개의 서브넷이 있는 RDMA용 VPC 네트워크 및 서브넷을 만듭니다.
gcloud beta compute networks create ${RDMA_NETWORK_PREFIX}-net \ --network-profile=${NODE_ZONE}-vpc-roce \ --subnet-mode=custom for N in $(seq 0 7); do gcloud compute networks subnets create ${RDMA_NETWORK_PREFIX}-sub-$N \ --network=${RDMA_NETWORK_PREFIX}-net \ --region=${CONTROL_PLANE_REGION} \ --range=192.168.$((N+1)).0/24 & done wait샘플 저장소를 클론합니다.
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git cd kubernetes-engine-samples작업 디렉터리로 이동합니다.
cd ai-ml/verl-on-gke
GKE 클러스터 만들기
GPU 아키텍처에 해당하는 GKE 클러스터를 만듭니다.
A4 및 A3 Ultra
사용할 GKE 클러스터 모드를 선택합니다.
Autopilot
Autopilot 클러스터를 만듭니다.
gcloud container clusters create-auto ${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION} \ --enable-multi-networking \ --enable-ray-operator클러스터의 사용자 인증 정보를 가져옵니다.
gcloud container clusters get-credentials ${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION}Autopilot용 NCCL RDMA 설치 프로그램을 설치합니다.
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/refs/heads/master/gpudirect-rdma/nccl-rdma-installer-autopilot.yaml
표준
표준 클러스터 만들기
gcloud container clusters create ${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION} \ --enable-dataplane-v2 \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --enable-ip-alias \ --enable-multi-networking \ --addons=RayOperator,GcsFuseCsiDriver \ --machine-type=c2-standard-16 \ --num-nodes=1 \ --min-nodes=1 \ --max-nodes=5 \ --enable-autoscaling클러스터의 사용자 인증 정보를 가져옵니다.
gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${CONTROL_PLANE_REGION}GPU 노드 풀을 만듭니다. 이러한 노드 풀은 예약을 사용하여 가용성을 보장합니다. 두 개의 노드로 시작합니다.
gcloud container node-pools create gpu-pool \ --cluster=${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION} \ --node-locations=${NODE_ZONE} \ --machine-type=${MACHINE_TYPE} \ --accelerator=type=${GPU_TYPE},count=8,gpu-driver-version=DEFAULT \ --reservation-affinity=specific \ --reservation=${RESERVATION} \ --enable-autoscaling \ --num-nodes=2 \ --total-max-nodes=10 \ --additional-node-network=network=${GVNIC_NETWORK_PREFIX}-net,subnetwork=${GVNIC_NETWORK_PREFIX}-sub \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-0 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-1 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-2 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-3 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-4 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-5 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-6 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-7Standard 클러스터에 사용되는 NCCL RDMA 설치 프로그램을 설치합니다.
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/refs/heads/master/gpudirect-rdma/nccl-rdma-installer.yaml
A4X
Cluster Toolkit
gke-a4x블루프린트를 사용하여 GKE 클러스터와 노드 풀을 만듭니다. 블루프린트는 예약에 바인딩된 A4X 노드 풀, 가속기 네트워크 (추가 gVNIC 1개와 RDMA 레일 4개), CX-7 NIC를 DRA 기기로 노출하는 관리형 DRANET 드라이버를 비롯한 GKE 클러스터를 프로비저닝합니다.블루프린트의 배포 안내에 따라 매개변수(예:
PROJECT_ID,CONTROL_PLANE_REGION,NODE_ZONE, 예약,NUM_GPU_NODES)를 구성한 다음 클러스터를 배포합니다. 또는 A4X GKE 클러스터 생성 가이드에 따라 클러스터를 수동으로 만들 수 있습니다.클러스터의 사용자 인증 정보를 가져옵니다.
gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${CONTROL_PLANE_REGION}클러스터가 DRA를 통해 RDMA NIC를 노출하는지 확인합니다.
kubectl get deviceclasses출력에
mrdma.google.com이 포함되어야 합니다.A4X 노드가 있는지 확인합니다.
kubectl get nodes -l cloud.google.com/gke-accelerator=nvidia-gb200gIB NCCL 플러그인 (A4X 변형)을 설치합니다.
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-rdma/nccl-rdma-installer-a4x.yaml다중 노드 NVLink용
ComputeDomain(IMEX) 채널을 제공하는 NVIDIA DRA 드라이버를 설치합니다.helm repo add nvidia https://helm.ngc.nvidia.com/nvidia && helm repo update kubectl create namespace nvidia-dra-driver-gpu kubectl apply -f - <<EOF apiVersion: v1 kind: ResourceQuota metadata: name: nvidia-dra-driver-gpu-quota namespace: nvidia-dra-driver-gpu spec: hard: pods: "$((2 * NUM_GPU_NODES + 1))" scopeSelector: matchExpressions: - operator: In scopeName: PriorityClass values: - system-node-critical - system-cluster-critical EOF helm upgrade --install nvidia-dra-driver-gpu nvidia/nvidia-dra-driver-gpu \ --version=25.3.1 --namespace nvidia-dra-driver-gpu \ --set nvidiaDriverRoot=/home/kubernetes/bin/nvidia \ --set resources.gpus.enabled=false \ --set kubeletPlugin.tolerations[0].key=nvidia.com/gpu \ --set kubeletPlugin.tolerations[0].operator=Exists \ --set kubeletPlugin.tolerations[1].key=kubernetes.io/arch \ --set kubeletPlugin.tolerations[1].operator=Exists워크로드 네임스페이스로 범위가 지정된 KubeRay 연산자를 설치합니다.
kubectl create namespace ${NAMESPACE} helm repo add kuberay https://ray-project.github.io/kuberay-helm/ && helm repo update helm upgrade --install kuberay-operator kuberay/kuberay-operator \ --namespace ${NAMESPACE} \ --set singleNamespaceInstall=true --set "watchNamespace={${NAMESPACE}}"
네트워크 매핑 구성 (A4 및 A3 Ultra만 해당)
이 단계는 표준 GPU 설정 (A4 및 A3 Ultra만 해당)에 필요합니다. A4X (GB200)를 사용하는 경우 GKE에서 네트워크 인터페이스를 자동으로 관리하므로 이 섹션을 건너뛰세요.
network-mapping.yaml매니페스트를 검사합니다.매니페스트를 적용합니다.
envsubst < network-mapping.yaml > network-mapping-updated.yaml kubectl apply -f network-mapping-updated.yaml
데이터 및 스토리지 준비
Cloud Storage 및 Kubernetes 리소스를 구성합니다.
Cloud Storage 버킷을 만듭니다.
gcloud storage buckets create gs://${GS_BUCKET} \ --location=${CONTROL_PLANE_REGION} \ --enable-hierarchical-namespace \ --uniform-bucket-level-accessKubernetes 서비스 계정 (KSA)을 만들고 버킷에 바인딩합니다.
kubectl create serviceaccount ${KSA_NAME} --namespace ${NAMESPACE} gcloud storage buckets add-iam-policy-binding gs://${GS_BUCKET} \ --member "principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/${NAMESPACE}/sa/${KSA_NAME}" \ --role "roles/storage.objectUser"Hugging Face의 보안 비밀을 만듭니다.
kubectl create secret generic hf-secret --from-literal=hf_api_token=${HF_TOKEN}gcsfuse-storage.yaml매니페스트를 검사합니다.매니페스트를 적용합니다.
envsubst < gcsfuse-storage.yaml > gcsfuse-storage-updated.yaml kubectl apply -f gcsfuse-storage-updated.yaml
모델 및 데이터 준비
모델 가중치와 데이터 세트로 Cloud Storage 버킷을 채웁니다. 버킷을 채우려면 로컬 또는 GKE 포드에서 다음 명령어를 실행하세요.
verl 저장소를 클론하고 가상 환경을 준비하고 GSM8K 데이터 세트를 처리합니다.
git clone https://github.com/volcengine/verl.git git -C verl checkout ${VERL_REF} VENV_DIR=.venv python3 -m venv $VENV_DIR source $VENV_DIR/bin/activate pip install verl python verl/examples/data_preprocess/gsm8k.py --local_save_dir ~/data/gsm8kHugging Face CLI를 사용하여 Qwen2.5-32B-Instruct 모델을 다운로드합니다(디스크 공간이 약 66GB 필요).
hf download Qwen/Qwen2.5-32B-Instruct --local-dir Qwen2.5-32B-Instruct모델, 데이터, verl 코드를 Cloud Storage 버킷에 업로드합니다.
gcloud storage cp --recursive verl gs://${GS_BUCKET}/verl gcloud storage cp --recursive Qwen2.5-32B-Instruct gs://${GS_BUCKET}/Qwen2.5-32B-Instruct gcloud storage cp --recursive ~/data/gsm8k/* gs://${GS_BUCKET}/gsm8k/
RayCluster 커스텀 리소스 배포
하나의 시스템 헤드 포드와 여러 GPU 지원 작업자 포드로 구성된 RayCluster 커스텀 리소스를 배포합니다.
A4 및 A3 Ultra
클러스터를 만드는 데 사용한 GKE 클러스터 모드를 선택합니다.
Autopilot
RayCluster를 배포합니다. 다음 코드를
ray-cluster-auto.yaml에 저장합니다.RayCluster를 적용합니다.
envsubst < ray-cluster-auto.yaml > ray-cluster-auto-updated.yaml kubectl apply -f ray-cluster-auto-updated.yaml
표준
RayCluster를 배포합니다. 다음 구성을
ray-cluster-standard.yaml에 저장합니다.RayCluster를 적용합니다.
envsubst < ray-cluster-standard.yaml > ray-cluster-updated.yaml kubectl apply -f ray-cluster-updated.yaml
A4X
RDMA
ResourceClaimTemplate및 NVIDIAComputeDomain을 만듭니다. 각 GPU 작업자 포드는 RDMA NIC 4개 (노드의 모든 레일)와 IMEX 채널 1개를 요청합니다. 다음 매니페스트를compute-domain-a4x.yaml에 저장합니다.apiVersion: resource.k8s.io/v1 kind: ResourceClaimTemplate metadata: name: verl-rdma-nic namespace: ${NAMESPACE} spec: spec: devices: requests: - name: nic exactly: deviceClassName: mrdma.google.com allocationMode: ExactCount count: 1 --- apiVersion: resource.nvidia.com/v1beta1 kind: ComputeDomain metadata: name: verl-compute-domain namespace: ${NAMESPACE} spec: numNodes: ${NUM_GPU_NODES} channel: resourceClaimTemplate: name: verl-compute-domain-channel매니페스트를 적용합니다.
kubectl apply -f compute-domain-a4x.yamlRayCluster를 배포합니다. Ray 헤드 포드는 GPU를 요청하지 않고 A4X 노드에서 실행됩니다 (이미지가
arm64전용이므로). 다음 구성을ray-cluster-a4x.yaml에 저장합니다.apiVersion: ray.io/v1 kind: RayCluster metadata: name: gb200-ray-cluster namespace: ${NAMESPACE} spec: rayVersion: '2.49.0' headGroupSpec: rayStartParams: dashboard-host: '0.0.0.0' num-cpus: "0" template: metadata: annotations: gke-gcsfuse/volumes: "true" spec: serviceAccountName: ${KSA_NAME} nodeSelector: cloud.google.com/gke-accelerator: nvidia-gb200 tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule - key: kubernetes.io/arch operator: Exists effect: NoSchedule containers: - name: ray-head image: ${VERL_IMAGE} lifecycle: postStart: exec: command: - /bin/bash - -c - pip3 install --quiet TransferQueue==0.1.8 ports: - containerPort: 6379 name: gcs-server - containerPort: 8265 name: dashboard - containerPort: 10001 name: client resources: limits: cpu: "12" memory: 32Gi ephemeral-storage: 20Gi requests: cpu: "12" memory: 32Gi ephemeral-storage: 20Gi volumeMounts: - mountPath: /tmp/ray name: ray-logs - name: training-bucket-vol mountPath: /data volumes: - name: ray-logs emptyDir: {} - name: training-bucket-vol persistentVolumeClaim: claimName: training-bucket-pvc workerGroupSpecs: - replicas: ${NUM_GPU_NODES} minReplicas: ${NUM_GPU_NODES} maxReplicas: ${NUM_GPU_NODES} groupName: gpu-group rayStartParams: num-cpus: "120" template: metadata: annotations: gke-gcsfuse/volumes: "true" spec: serviceAccountName: ${KSA_NAME} nodeSelector: cloud.google.com/gke-accelerator: nvidia-gb200 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: ray.io/group: gpu-group topologyKey: kubernetes.io/hostname tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule - key: kubernetes.io/arch operator: Exists effect: NoSchedule containers: - name: ray-worker image: ${VERL_IMAGE} lifecycle: postStart: exec: command: - /bin/bash - -c - pip3 install --quiet TransferQueue==0.1.8 env: - name: LD_LIBRARY_PATH value: /usr/local/nvidia/lib64 resources: limits: cpu: "120" memory: 600Gi nvidia.com/gpu: "4" ephemeral-storage: 500Gi requests: cpu: "120" memory: 600Gi nvidia.com/gpu: "4" ephemeral-storage: 500Gi claims: - name: rdma-nic-0 - name: rdma-nic-1 - name: rdma-nic-2 - name: rdma-nic-3 - name: compute-domain-channel volumeMounts: - name: nvidia mountPath: /usr/local/nvidia - name: gib mountPath: /usr/local/gib - name: shared-memory mountPath: /dev/shm - name: ray-tmp-storage mountPath: /tmp - name: training-bucket-vol mountPath: /data resourceClaims: - name: rdma-nic-0 resourceClaimTemplateName: verl-rdma-nic - name: rdma-nic-1 resourceClaimTemplateName: verl-rdma-nic - name: rdma-nic-2 resourceClaimTemplateName: verl-rdma-nic - name: rdma-nic-3 resourceClaimTemplateName: verl-rdma-nic - name: compute-domain-channel resourceClaimTemplateName: verl-compute-domain-channel volumes: - name: gib hostPath: path: /home/kubernetes/bin/gib - name: nvidia hostPath: path: /home/kubernetes/bin/nvidia - name: shared-memory emptyDir: medium: Memory sizeLimit: 200Gi - name: ray-tmp-storage emptyDir: {} - name: training-bucket-vol persistentVolumeClaim: claimName: training-bucket-pvcRayCluster 매니페스트를 적용합니다.
envsubst < ray-cluster-a4x.yaml | kubectl apply -f -하나의 헤드 포드와 네 개의 작업자 포드가
Running상태가 될 때까지 기다립니다.kubectl get pods -w
GRPO 작업 실행
강화 학습 학습 작업을 구성하고 제출합니다.
A4 및 A3 Ultra
Ray 대시보드 노드로의 포트 전달을 설정합니다. 이 명령어는 실행되는 동안 터미널을 차단하므로 별도의 터미널 창을 사용하세요. Ctrl+C를 사용하여 중지합니다.
kubectl port-forward svc/b200-ray-cluster-head-svc 8265:8265runtime-env.yaml매니페스트를 검사합니다.H200 GPU를 사용하는 경우
NCCL_TUNER_CONFIG_PATH를/usr/local/gib/configs/tuner_config_a3u.txtpb로 변경합니다.이 파일은 Ray 클라이언트에서 사용합니다. 이 매니페스트를 클러스터에 적용할 필요는 없습니다.
ray job submit를 사용하여 작업을 제출합니다.ray job submit \ --address "http://localhost:8265" \ --runtime-env runtime-env.yaml \ -- \ bash -c " cd /data/verl && PYTHONUNBUFFERED=1 python3 -m verl.trainer.main_ppo \ data.train_files=/data/gsm8k/train.parquet \ data.val_files=/data/gsm8k/test.parquet \ data.train_batch_size=256 \ data.max_prompt_length=512 \ data.max_response_length=512 \ actor_rollout_ref.model.path=/data/Qwen2.5-32B-Instruct \ actor_rollout_ref.actor.optim.lr=1e-5 \ actor_rollout_ref.actor.ppo_mini_batch_size=256 \ actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=64 \ actor_rollout_ref.rollout.name=vllm \ actor_rollout_ref.rollout.log_prob_micro_batch_size_per_gpu=8 \ actor_rollout_ref.rollout.tensor_model_parallel_size=8 \ actor_rollout_ref.rollout.gpu_memory_utilization=0.6 \ actor_rollout_ref.ref.log_prob_micro_batch_size_per_gpu=4 \ actor_rollout_ref.actor.strategy=fsdp2 \ algorithm.kl_ctrl.kl_coef=0.001 \ trainer.logger=console \ trainer.val_before_train=False \ trainer.n_gpus_per_node=8 \ trainer.nnodes=2 \ trainer.save_freq=10 \ trainer.test_freq=10 \ trainer.default_local_dir=/data/verl/checkpoints \ algorithm.adv_estimator=grpo \ actor_rollout_ref.rollout.n=8 \ trainer.total_epochs=2"Ray 대시보드 또는 콘솔 출력에서 로그를 모니터링합니다. 학습을 나타내는
critic/score/mean가 증가하는지 확인합니다.학습이 완료되면 학습된 모델의 체크포인트가
gs://$GS_BUCKET/verl/checkpoints에 있습니다.
A4X
Ray 헤드 포드 이름을 가져옵니다.
export HEAD_POD=$(kubectl get pod -n ${NAMESPACE} -l ray.io/node-type=head -o jsonpath='{.items[0].metadata.name}')헤드 포드에서 직접 Ray 런타임 환경 파일을 구성합니다.
kubectl exec ${HEAD_POD} -c ray-head -- bash -c 'mkdir -p /tmp/submit && cat > /tmp/submit/runtime-env.yaml <<EOF working_dir: "." env_vars: PYTHONPATH: "/data/verl" LD_LIBRARY_PATH: "/usr/local/nvidia/lib64:/usr/local/gib/lib64" NCCL_DEBUG: "INFO" NCCL_ENV_PLUGIN: "gcp" HF_HOME: "/data/huggingface_cache" GLOO_SOCKET_IFNAME: "eth0" EOF'Ray 헤드 Pod에서 실행하여 GRPO 학습 작업을 제출합니다.
kubectl exec ${HEAD_POD} -c ray-head -- bash -c 'cd /tmp/submit && \ ray job submit --runtime-env runtime-env.yaml --no-wait -- \ python3 -m verl.trainer.main_ppo \ algorithm.adv_estimator=grpo \ data.train_files=/data/gsm8k/train.parquet \ data.val_files=/data/gsm8k/test.parquet \ data.train_batch_size=256 \ data.max_prompt_length=512 \ data.max_response_length=512 \ actor_rollout_ref.model.path=/data/Qwen2.5-32B-Instruct \ actor_rollout_ref.actor.optim.lr=1e-5 \ actor_rollout_ref.actor.ppo_mini_batch_size=64 \ actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=8 \ actor_rollout_ref.actor.use_kl_loss=True \ actor_rollout_ref.actor.strategy=fsdp2 \ actor_rollout_ref.rollout.name=vllm \ actor_rollout_ref.rollout.tensor_model_parallel_size=4 \ actor_rollout_ref.rollout.gpu_memory_utilization=0.6 \ actor_rollout_ref.rollout.n=8 \ actor_rollout_ref.rollout.log_prob_micro_batch_size_per_gpu=16 \ actor_rollout_ref.ref.log_prob_micro_batch_size_per_gpu=16 \ algorithm.kl_ctrl.kl_coef=0.001 \ trainer.logger=console \ trainer.n_gpus_per_node=4 \ trainer.nnodes=4 \ trainer.save_freq=10 \ trainer.test_freq=10 \ trainer.total_epochs=2 \ trainer.default_local_dir=/data/verl/checkpoints'작업 로그를 모니터링합니다 (
ray job submit에서 반환된 고유 ID 사용).kubectl exec ${HEAD_POD} -c ray-head -- ray job logs <var>JOB_ID</var> --followJOB_ID을 바꿉니다.via P2P/MNNVL가 포함된 로그에서 NCCL 줄을 찾아 크로스 노드 NVLink가 활성 상태인지 확인합니다.
삭제
요금이 청구되지 않도록 하려면 리소스를 삭제하세요.
A4 및 A3 Ultra
kubectl delete raycluster b200-ray-cluster
gcloud container clusters delete ${CLUSTER_NAME} --location=${CONTROL_PLANE_REGION}
gcloud storage rm -r gs://${GS_BUCKET}
A4X
kubectl delete raycluster gb200-ray-cluster
kubectl delete computedomain verl-compute-domain
gcloud storage rm -r gs://${GS_BUCKET}
gcloud container clusters delete ${CLUSTER_NAME} --location=${CONTROL_PLANE_REGION}