۱. مقدمه
در این آزمایشگاه کد، شما یاد خواهید گرفت که چگونه سرویسهای استنتاج vLLM (مدل زبان بزرگ مجازی) چند میزبانه با کارایی بالا را روی موتور گوگل کوبرنتیز (GKE) با استفاده از TPUهای گوگل کلود پیادهسازی کنید. شما استنتاج توزیعشده را با استفاده از Ray پیکربندی خواهید کرد و حجم کار را به صورت بومی روی GKE با استفاده از LeaderWorkerSets مدیریت خواهید کرد.
این راهنما، یک محیط تولید برای ارائه مدلهای بزرگ مانند Qwen 30B را شبیهسازی میکند.
کاری که انجام خواهید داد
- یک شبکه VPC سفارشی برای ترافیک شتابدهنده ایجاد کنید.
- یک کلاستر GKE به همراه Ray Operator و درایور GCS Fuse CSI تهیه کنید.
- برای بارگذاری سریعتر مدل، یک GCS Rapid Cache راهاندازی کنید.
- یک مخزن گره TPU v6e چند میزبانه با ظرفیت رزرو شده فراهم کنید.
- پیکربندی هویت بار کاری برای دسترسی ایمن به وزنهای مدل.
- موتور vLLM را که یک مدل پارامتر 30B را ارائه میدهد، مستقر و آزمایش کنید.

آنچه نیاز دارید
- یک پروژه گوگل کلود با قابلیت پرداخت.
- رزرو فضای ابری گوگل برای منابع TPU v6e (32 تراشه،
ct6e-standard-4t). - دسترسی به کپی کردن وزنهای مدل از یک سطل منبع.
- Cloud Shell یا یک ترمینال محلی با
gcloud،kubectlوhelmنصب شده.
- مدت زمان تخمینی: ۶۰ دقیقه
- هزینه تخمینی: کمتر از ۶۰ دلار (با فرض اینکه کالبدشکافی به سرعت انجام شود).
۲. قبل از شروع
یک پروژه Google Cloud ایجاد یا انتخاب کنید
- در کنسول گوگل کلود ، یک پروژه گوگل کلود انتخاب یا ایجاد کنید.
- مطمئن شوید که پرداخت برای پروژه ابری شما فعال است.
شروع پوسته ابری
- روی فعال کردن Cloud Shell در بالای کنسول Google Cloud کلیک کنید.
- تأیید اعتبار:
gcloud auth list
- پروژه خود را تایید کنید:
gcloud config get project
- در صورت نیاز آن را تنظیم کنید:
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID
تنظیم متغیرهای محیطی
برای آسانتر کردن اجرای دستورات، متغیرهای زیر را در پوسته خود تعریف کنید. <YOUR_ZONE> را با منطقه TPU اختصاص داده شده خود و <YOUR_RESERVATION_NAME> را با شناسه رزرو خود جایگزین کنید. برای دانلود وزنهای مدل دروازهدار، باید یک توکن دسترسی کاربر Hugging Face ایجاد کنید. پس از ایجاد آن، <YOUR_HUGGING_FACE_TOKEN> را با توکن تازه ایجاد شده خود جایگزین کنید.
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
export ZONE="<YOUR_ZONE>" # e.g., us-east5-a
export REGION=${ZONE%-*}
export CLUSTER_NAME="qwen-serving-cluster"
export GVNIC_NETWORK_PREFIX="qwen-serving"
export BUCKET_NAME="inf-demo-model-storage-${PROJECT_NUMBER}"
export RESERVATION_NAME="<YOUR_RESERVATION_NAME>"
export NODE_POOL_NAME="tpu-v6e-32-resvd-pool"
export MULTIHOST_COLLECTION_NAME="tpu-6-collection"
export HF_TOKEN="<YOUR_HUGGING_FACE_TOKEN>" # Token with access to Qwen model if restricted
فعال کردن APIها
سرویسهای مورد نیاز Google Cloud را فعال کنید:
gcloud services enable \
container.googleapis.com \
compute.googleapis.com \
iam.googleapis.com \
cloudresourcemanager.googleapis.com
۳. ایجاد شبکهسازی سفارشی
بارهای کاری TPU چند میزبانه به پیکربندیهای شبکه خاصی نیاز دارند، از جمله اندازههای MTU بالاتر برای ارتباط شتابدهنده کارآمد. یک شبکه VPC سفارشی برای کلاستر خود ایجاد کنید.
- شبکه VPC را با MTU بزرگ (8896) ایجاد کنید :
gcloud compute --project=${PROJECT_ID} \ networks create ${GVNIC_NETWORK_PREFIX}-main \ --subnet-mode=custom \ --mtu=8896 - زیرشبکه را برای کلاستر ایجاد کنید :
gcloud compute --project=${PROJECT_ID} \ networks subnets create ${GVNIC_NETWORK_PREFIX}-tpu \ --network=${GVNIC_NETWORK_PREFIX}-main \ --region=${REGION} \ --range=192.168.100.0/24 - ایجاد قوانین فایروال که به ترافیک داخلی اجازه میدهد تا کارگران بتوانند ارتباط برقرار کنند:
gcloud compute --project=${PROJECT_ID} firewall-rules create ${GVNIC_NETWORK_PREFIX}-allow-internal \ --network=${GVNIC_NETWORK_PREFIX}-main \ --allow=all \ --source-ranges=172.16.0.0/12,192.168.0.0/16,10.0.0.0/8 \ --description="Allow all internal traffic within the network."
۴. خوشه GKE تأمین
یک تنظیمات کلاستر استاندارد GKE ایجاد کنید که برای پشتیبانی از GCS Fuse mounts و بارهای کاری Ray Operator پیکربندی شده باشد.
- خوشه را ایجاد کنید :
gcloud container clusters create ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --location=${REGION} \ --release-channel=rapid \ --machine-type=e2-standard-4 \ --network=${GVNIC_NETWORK_PREFIX}-main \ --subnetwork=${GVNIC_NETWORK_PREFIX}-tpu \ --num-nodes=1 \ --gateway-api=standard \ --enable-managed-prometheus \ --enable-dataplane-v2 \ --enable-dataplane-v2-metrics \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --addons=GcsFuseCsiDriver,RayOperator \ --enable-ip-alias - بازیابی اعتبارنامههای کلاستر :
gcloud container clusters get-credentials ${CLUSTER_NAME} --region=${REGION} - ایجاد راز چهره در آغوش گرفته : توکن خود را به طور ایمن برای دانلودهای دسترسی به کانتینر ذخیره کنید:
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HF_TOKEN} \ --dry-run=client -o yaml | kubectl apply -f - - LeaderWorkerSet (LWS) را از طریق Helm نصب کنید . LWS گروههایی از podها را که باید با هم زمانبندی شوند، مدیریت میکند:
helm install lws oci://registry.k8s.io/lws/charts/lws \ --version=0.7.0 \ --namespace lws-system \ --create-namespace \ --wait
۵. فعال کردن حافظه پنهان سریع GCS
برای سرعت بخشیدن به خواندن دهها گیگابایت وزن از فضای ذخیرهسازی ابری در حین سرویسدهی، یک سطل GCS ایجاد کنید و GCS Rapid Cache را در منطقه خود فعال کنید.
- سطل را ایجاد کنید :
gcloud storage buckets create gs://$BUCKET_NAME \ --location=$REGION \ --uniform-bucket-level-access - مقداردهی اولیه Rapid Cache در ناحیه TPU:
gcloud storage buckets anywhere-caches create gs://$BUCKET_NAME $ZONE \ --ttl=1d \ --admission-policy=ADMIT_ON_FIRST_MISS
۶. تنظیم هویت بار کاری و مجوزهای ذخیرهسازی
پیوندهای هویت را پیکربندی کنید تا سطل وزنه را به طور ایمن در غلافهای GKE خود نصب کنید بدون اینکه کلیدهای بادوام تعبیه کنید.
- یک حساب کاربری اختصاصی برای سرویس IAM ایجاد کنید :
gcloud iam service-accounts create tpu-reader-sa - مجوزهای خواندن باکت را اعطا کنید :
gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \ --member="serviceAccount:tpu-reader-sa@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/storage.objectAdmin" - ایجاد اتصال هویت بار کاری برای فضای نام
defaultحساب سرویس Kubernetes:gcloud iam service-accounts add-iam-policy-binding tpu-reader-sa@${PROJECT_ID}.iam.gserviceaccount.com \ --role="roles/iam.workloadIdentityUser" \ --member="serviceAccount:${PROJECT_ID}.svc.id.goog[default/default]" - Kubernetes SA را حاشیهنویسی کنید :
kubectl annotate serviceaccount default iam.gke.io/gcp-service-account=tpu-reader-sa@${PROJECT_ID}.iam.gserviceaccount.com
۷. تنظیمات وزنهای مدل
برای ارائه یک مدل پارامتر 30B، باید وزنها را از Hugging Face در سطل GCS خود دانلود کنید. برای دور زدن محدودیت سهمیه دیسک Cloud Shell (5 گیگابایت)، از یک کار استاندارد Kubernetes برای دانلود مستقیم درون خوشه و نوشتن ایمن در حجم GCS Fuse نصب شده استفاده کنید.
- استقرار کار دانلود مدل : برای شروع دانلود، فایل مانیفست زیر را ایجاد و اعمال کنید:
cat <<EOF | kubectl apply -f - apiVersion: batch/v1 kind: Job metadata: name: model-downloader spec: ttlSecondsAfterFinished: 60 template: metadata: annotations: gke-gcsfuse/volumes: "true" gke-gcsfuse/memory-limit: "0" spec: serviceAccountName: default restartPolicy: OnFailure containers: - name: downloader image: python:3.10-slim command: ["/bin/sh", "-c"] args: - | pip install -U "huggingface_hub[hf_transfer]" filelock export HF_HUB_ENABLE_HF_TRANSFER=1 python -c ' import filelock class DummyLock: def __init__(self, *args, **kwargs): pass def __enter__(self): return self def __exit__(self, *args): pass def acquire(self, *args, **kwargs): pass def release(self, *args, **kwargs): pass filelock.FileLock = DummyLock from huggingface_hub import snapshot_download snapshot_download( repo_id="Qwen/Qwen3-30B-A3B", local_dir="/models/qwen3-30b-weights", local_dir_use_symlinks=False ) ' env: - name: HF_TOKEN valueFrom: secretKeyRef: name: hf-secret key: hf_api_token volumeMounts: - name: model-weights mountPath: /models volumes: - name: model-weights csi: driver: gcsfuse.csi.storage.gke.io volumeAttributes: bucketName: ${BUCKET_NAME} mountOptions: "implicit-dirs" EOF - نظارت بر دانلود : برای پیگیری پیشرفت، لاگهای مربوط به دانلودر پاد را بررسی کنید:
صبر کنید تا کار با وضعیت موفقیتآمیز به پایان برسد.kubectl logs -f job/model-downloader
۸. ایجاد یک TPU Node Pool رزرو شده
با استفاده از رزرو ظرفیت موجود، قطعه TPU چند میزبانه واقعی را فراهم کنید.
- دستور ایجاد را اجرا کنید :
gcloud beta container node-pools create ${NODE_POOL_NAME} \ --project=${PROJECT_ID} \ --cluster=${CLUSTER_NAME} \ --region=${REGION} \ --node-locations=${ZONE} \ --machine-type=ct6e-standard-4t \ --tpu-topology=4x8 \ --num-nodes=8 \ --scopes=https://www.googleapis.com/auth/cloud-platform \ --reservation-affinity=specific \ --reservation=${RESERVATION_NAME} \ --accelerator-network-profile=auto \ --node-labels=cloud.google.com/gke-nodepool-group-name=${MULTIHOST_COLLECTION_NAME} \ --node-labels=cloud.google.com/gke-workload-type=HIGH_AVAILABILITY \ --node-labels=cloud.google.com/gke-networking-dra-driver=true - منتظر بمانید تا گرهها به هم بپیوندند : میتوانید مقیاسبندی تجمیع گرهها را مستقیماً مشاهده کنید. منتظر بمانید تا ۸ گره حاوی
ct6eبهkubectl get nodesبپیوندند.
۹. استقرار سرویس vLLM
- ایجاد درخواستهای شبکه : شما باید محیط شبکه را درخواست کنید:
cat <<EOF | kubectl apply -f - apiVersion: resource.k8s.io/v1 kind: ResourceClaimTemplate metadata: name: all-netdev spec: spec: devices: requests: - name: req-netdev exactly: deviceClassName: netdev.google.com allocationMode: All EOF - نقطه پایانی API متعادل کننده بار را مستقر کنید :
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: name: vllm-tpu-service spec: type: LoadBalancer selector: leaderworkerset.sigs.k8s.io/name: vllm-tpu-qwen leaderworkerset.sigs.k8s.io/worker-index: "0" ports: - protocol: TCP port: 8000 targetPort: 8000 EOF - استقرار بار کاری LeaderWorkerSet : این مانیفست، تجمیع سر/کارگر Ray را به صورت پویا در 8 میزبان برش آغاز میکند.
cat <<EOF | kubectl apply -f - apiVersion: leaderworkerset.x-k8s.io/v1 kind: LeaderWorkerSet metadata: name: vllm-tpu-qwen spec: replicas: 1 leaderWorkerTemplate: size: 8 restartPolicy: RecreateGroupOnPodRestart workerTemplate: metadata: annotations: gke-gcsfuse/volumes: "true" gke-gcsfuse/memory-limit: "0" labels: leaderworkerset.sigs.k8s.io/name: vllm-tpu-qwen gke-gcsfuse/volumes: "true" spec: hostname: vllm-tpu-qwen serviceAccountName: default containers: - name: vllm-tpu image: vllm/vllm-tpu:nightly command: ["sh", "-c"] args: - | MY_TPU_IP=\$(hostname -I | awk '{print \$1}') echo "My TPU Network IP is: \$MY_TPU_IP" LEADER_DNS="vllm-tpu-qwen-0.vllm-tpu-qwen" until getent hosts \$LEADER_DNS; do echo "DNS not ready. Sleeping 5s..." sleep 5 done LEADER_IP=\$(getent hosts \$LEADER_DNS | awk '{print \$1}') export JAX_PLATFORMS='' export SCAN_TPU_CHIPS=True export TPU_MULTIHOST_BACKEND=ray export JAX_DISTRIBUTED_INITIALIZATION_TIMEOUT=300 export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:/usr/local/lib export VLLM_HOST_IP=\$MY_TPU_IP if [ "\$LWS_WORKER_INDEX" = "0" ]; then echo "Starting Ray Head..." ray start --head --port=6379 --node-ip-address=\$MY_TPU_IP --resources='{"TPU": 4}' --block & sleep 20 until ray status; do sleep 5; done echo "Starting vLLM API Server..." python3 -m vllm.entrypoints.openai.api_server \ --model=/models/qwen3-30b-weights \ --tensor-parallel-size=32 \ --pipeline-parallel-size=1 \ --distributed-executor-backend=ray \ --host=0.0.0.0 --port=8000 \ --enforce-eager \ --gpu-memory-utilization=0.90 else ray start --address=\${LEADER_IP}:6379 --node-ip-address=\$MY_TPU_IP --resources='{"TPU": 4}' --block fi ports: - containerPort: 8000 - containerPort: 6379 volumeMounts: - name: model-weights mountPath: /models readOnly: true - name: dshm mountPath: /dev/shm resources: claims: - name: net-resources limits: google.com/tpu: 4 memory: "100Gi" requests: google.com/tpu: 4 memory: "100Gi" nodeSelector: cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice cloud.google.com/gke-tpu-topology: 4x8 gke.networks.io/accelerator-network-profile: auto resourceClaims: - name: net-resources resourceClaimTemplateName: all-netdev volumes: - name: model-weights csi: driver: gcsfuse.csi.storage.gke.io volumeAttributes: bucketName: ${BUCKET_NAME} mountOptions: "implicit-dirs" - name: dshm emptyDir: medium: Memory EOF
۱۰. تست پاسخ استقرار
ممکن است ۵ تا ۱۰ دقیقه طول بکشد تا تمام پادهای موجود در LeaderWorkerSet تصاویر کانتینر را دریافت کنند، Ray را مقداردهی اولیه کنند و کاملاً Ready شوند. میتوانید وضعیت را با مشاهده مقداردهی اولیه پاد پیگیری کنید:
kubectl get pods -l leaderworkerset.sigs.k8s.io/name=vllm-tpu-qwen -w
صبر کنید تا هر ۸ vllm-tpu-qwen- pods STATUS به صورت Running و READY به صورت 2/2 نشان دهند، و قبل از ادامه، مطمئن شوید که متعادلکننده بار، یک IP خارجی دریافت کرده است. این کار میتواند ۷ تا ۱۰ دقیقه طول بکشد.
- بازیابی آیپی خارجی :
export EXTERNAL_IP=$(kubectl get svc vllm-tpu-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}') echo $EXTERNAL_IP
احتیاط: در یک سرویس در حال تولید، این نقطه پایانی باید با چیزی مانند پروکسی آگاه از هویت (IAP) ایمن شود.
- ارسال درخواست استنتاج با استفاده از
curl: شما باید خروجی شبیه به یک پاسخ JSON حاوی متنی که نشاندهندهی استنتاج تولید شدهی شماست را ببینید!curl -N -s http://$EXTERNAL_IP:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "/models/qwen3-30b-weights", "messages": [{"role": "user", "content": "Write a haiku about high-performance computing on TPUs."}], "temperature": 0.7, "max_tokens": 100, "stream": true }' | sed 's/^data: //' | grep -v '\[DONE\]' | grep -v '^$' | jq -rj '.choices[0].delta.content // empty' ; echo ""
۱۱. تمیز کردن
برای جلوگیری از هزینههای مداوم برای حساب Google Cloud خود، منابع ایجاد شده در طول این codelab را حذف کنید.
- حذف استخر گره :
gcloud container node-pools delete "${NODE_POOL_NAME}" \ --cluster="${CLUSTER_NAME}" \ --region="${REGION}" \ --project="${PROJECT_ID}" --quiet - حذف خوشه :
gcloud container clusters delete "${CLUSTER_NAME}" \ --region="${REGION}" \ --project="${PROJECT_ID}" --quiet - تنظیمات شبکه و فایروال را حذف کنید :
gcloud compute firewall-rules delete \ "${GVNIC_NETWORK_PREFIX}-allow-internal" \ --project="${PROJECT_ID}" --quiet gcloud compute networks subnets delete "${GVNIC_NETWORK_PREFIX}-tpu" \ --region="${REGION}" --quiet gcloud compute networks delete "${GVNIC_NETWORK_PREFIX}-main" --quiet - لغو اتصال و حذف حساب سرویس :
# 1. Create the cleanup script cat << 'EOF' > clean_up_sa.sh #!/bin/bash # Validate that PROJECT_ID is available if [ -z "$PROJECT_ID" ]; then echo "Error: PROJECT_ID environment variable is not set." exit 1 fi SA_EMAIL="tpu-reader-sa@${PROJECT_ID}.iam.gserviceaccount.com" SA_MEMBER="serviceAccount:${SA_EMAIL}" echo "Gathering IAM policy for ${SA_EMAIL}..." # Fetch roles assigned to this specific SA ROLES=$(gcloud projects get-iam-policy ${PROJECT_ID} \ --flatten="bindings[].members" \ --filter="bindings.members:${SA_MEMBER}" \ --format="value(bindings.role)") if [ -z "$ROLES" ]; then echo "No IAM bindings found for this service account." else for ROLE in $ROLES; do echo "Removing binding for: ${ROLE}..." gcloud projects remove-iam-policy-binding ${PROJECT_ID} \ --member="${SA_MEMBER}" \ --role="${ROLE}" --quiet > /dev/null done echo "Successfully unbound all roles." fi # 2. Delete the service account itself echo "Deleting service account..." gcloud iam service-accounts delete ${SA_EMAIL} --project=${PROJECT_ID} --quiet echo "Cleanup complete." EOF # 2. Make the script executable and run it chmod +x clean_up_sa.sh ./clean_up_sa.sh - حذف سطل GCS به کنسول ابری خود بروید، Cloud Storage -> Buckets را انتخاب کنید، inf-demo-model-storage را انتخاب کنید و سپس «حذف» را انتخاب کنید.
۱۲. تبریک
تبریک! شما با موفقیت یک پشته vLLM با نرخ استنتاج بالا و چند میزبانه TPU را با استفاده از Ray به صورت بومی بر روی موتور Google Kubernetes مستقر کردید.
آنچه آموختهاید
- تأمین مسیرهای سفارشی متناسب با ترافیک پرسرعت TPU.
- نصب وزنهها با استفاده از فیوز GCS و حافظههای ذخیرهسازی سریع منطقهای.
- هماهنگسازی برشهای بار کاری چند میزبانه که به صورت بومی از طریق LeaderWorkerSets همگامسازی شدهاند.
- برای کسب اطلاعات بیشتر به راهنمای کاربر vLLM و راهنماهای استقرار llm-d مراجعه کنید.