به گزارش از وبسایت cncf، تخصیص منابع پویا (DRA) در Kubernetes نسخه 1.35 به وضعیت GA رسیده و بسیاری از افراد علاقه‌مند به آزمایش آن هستند. NVIDIA نیز در کنار پیشرفت‌های خود، dra-driver-nvidia-gpu را به SIG مربوط به Kubernetes منتقل کرده و برچسب بتا را از مستندات حذف نموده که نشان‌دهنده بلوغ روزافزون این فناوری و استانداردهای مرتبط است. من در این پست از GPUهای موجود در آزمایشگاه‌های CNTUG Infra قرض گرفتم تا نحوه تخصیص دستگاه‌ها و منابع با DRA را عملیاتی بررسی کنم. 🚀

آزمایشگاه‌های CNTUG Infra: مروری بر محیط آزمایشگاهی

CNTUG Infra Labs به منظور پرورش نسل بعدی دانشجویان و مهندسان زیرساخت نرم‌افزاری در تایوان راه‌اندازی شده است. این آزمایشگاه در دیتاسنتر Equinix توکیو میزبانی می‌شود و توسط چند عضو جامعه CNTUG پشتیبانی مالی می‌شود. راه‌اندازی محیط متکی بر مجموعه‌ای از پروژه‌های متن‌باز مانند OpenStack، Ceph و Ansible است. از آنجا که نرم‌افزارهای زیرساختی نیازمند منابع محاسباتی، ذخیره‌سازی و شبکه زیاد و همچنین دارای منحنی یادگیری بالا هستند، هدف CNTUG Infra Labs فراهم آوردن یک پلتفرم ابری برای آزمایش و میزبانی سرویس‌ها توسط دانشجویان و اعضای جامعه است. ظرفیت اضافی نیز برای میزبانی سرویس‌های عمومی مانند وب‌سایت‌ها، Mattermost و Jitsi Meet یا رویدادهای کارگاهی در اختیار قرار می‌گیرد.

خوشه آزمایشی ما با استفاده از Cluster API + OpenStack ساخته شده است. برای اجتناب از طولانی شدن پست، مراحل راه‌اندازی اینجا آورده نشده است — برای جزئیات بیشتر می‌توانید به دیگر پست‌های وبلاگ مراجعه کنید یا منتظر پست بعدی باشید. 🙂

مشخصات سیستم:

System OS: Ubuntu 24.04
Kubernetes: v1.35.3
Containerd: 2.2.2
Nodes: 1 Control Plane + etcd, 3 Workers (No GPU), T10 * 2, A5000 * 1
NVIDIA GPU Operator: v26.3.1
NVIDIA DRA Driver GPU: v25.12

پس از بالا آمدن خوشه باید چیزی شبیهِ خروجی زیر را ببینید:

STATUS   ROLES         AGE     VERSION
capi-dralabs-control-plane-xtcth   Ready   control-plane   8m7s    v1.35.3
capi-dralabs-md-0-p4xkh-rpfxc      Ready                   6m55s   v1.35.3
capi-dralabs-md-xpua-djw4          Ready                   2m37s   v1.35.3
capi-dralabs-md-gput10-gzl84-f2m2d Ready                   6m49s   v1.35.3

نصب NVIDIA GPU Operator

قبل از نصب operator، گره‌هایی که GPU دارند را برچسب بزنید. برای محیط من این کار به شکل زیر انجام شد:

kubectl label node capi-dralabs-md-gpua5000-jw4mx-d64jz nvidia.com/dra-kubelet-plugin=true
kubectl label node capi-dralabs-md-gput10-gzl24-f nvidia.com/dra-kubelet-plugin=true

مخزن Helm NVIDIA را اضافه کنید و به‌روزرسانی کنید:

helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update

یک فایل values برای نصب GPU Operator ایجاد کنید (نمونه‌ی خلاصه شده):

values-gpu-operator.yaml
manager:
  env:
    - name: NODE_LABEL_FOR_GPU_POD_EVICTION
      value: "nvidia.com/dra-kubelet-plugin"
# توجه: اگر از توزیع دیگری مانند Rancher یا K3s استفاده می‌کنید،
# مسیر socket مربوط به containerd ممکن است متفاوت باشد:
CONTAINERD_SOCKET: /run/k3s/containerd/containerd.sock

حال GPU Operator را نصب کنید:

helm upgrade --install gpu-operator nvidia/gpu-operator 
  --version=v26.3.1 
  --create-namespace 
  --namespace nvidia

Operator پس از اجرا، درایور GPU را نصب کرده و تنظیمات Container Runtime را تغییر می‌دهد. برای تنظیمات خاص‌تر به اسناد رسمی NVIDIA مراجعه کنید.

نصب NVIDIA DRA Driver

یک فایل values برای nvidia-dra-driver-gpu بسازید:

values-nvidia-dra-driver-gpu.yaml
# version: 25.12.0
nvidiaDriverRoot: /run/nvidia/driver
kubeletPlugin:
  nodeSelector:
    nvidia.com/dra-kubelet-plugin: "true"
resources:
  gpus:
    enabled: true
    computeDomains:
      enabled: false # NVLink موجود نیست
# featureGates:
#   TimeSlicingSettings: true  # فعال کنید اگر می‌خواهید SPU را زمانبندی کنید

درایور NVIDIA DRA را نصب کنید:

helm upgrade -i nvidia-dra-driver-gpu nvidia/nvidia-dra-driver-gpu 
  --version="25.12.0" 
  --namespace nvidia-dra-driver-gpu 
  --create-namespace 
  -f values-nvidia-dra-driver-gpu.yaml

برای تأیید وضعیت Podهای در namespace مربوطه از دستور زیر استفاده کنید:

kubectl get pod -n nvidia-dra-driver-gpu
NAME                                           READY   STATUS    RESTARTS   AGE
...                                           1/1     Running   0          10m

نگاهی اولیه به DRA DeviceClass

پس از نصب، مشاهده خواهید کرد که DeviceClass و ResourceSlice توسط NVIDIA DRA Driver راه‌اندازی شده‌اند. DeviceClass نمایش‌دهنده دسته‌بندی دستگاه‌ها است — برای مثال gpu.nvidia.com، mig.nvidia.com و vfio.gpu.nvidia.com. (اگر computeDomains فعال باشد، اطلاعات مرتبط نیز ظاهر می‌شود.)

kubectl get deviceclass
NAME              AGE
gpu.nvidia.com    44m
mig.nvidia.com    44m
vfio.gpu.nvidia.com 44m

Driver به‌طور خودکار ResourceSliceها را برای دستگاه‌هایی که آن گره را مدیریت می‌کنند ایجاد می‌کند. دستگاه‌های مربوط به یک گره که توسط یک درایور مدیریت می‌شوند، در یک Pool قرار می‌گیرند. اگر تعداد دستگاه‌ها از حدی که در یک شیء گنجانده می‌شود بیشتر شود (تا 128 ورودی، یا 64 در صورت استفاده از برخی ویژگی‌ها)، درایور Pool را به چند ResourceSlice تقسیم می‌کند. فیلدهای .spec.pool.generation و .spec.pool.resourceSliceCount به scheduler کمک می‌کنند تا بفهمند آیا فهرست دستگاه‌ها کامل و به‌روز است یا خیر.

نمونه خروجی ResourceSlice:

kubectl get resourceslices
NAME                                                             NODE                                        DRIVER               POOL   AGE
capi-dralabs-md-gpua5000-jw4mx-d64jz-gpu.nvidia.com-w9fnv       capi-dralabs-md-gpua5000-jw4mx-d64jz        gpu.nvidia.com       1      5m13s
capi-dralabs-md-gput10-gzl84-f2m2d-gpu.nvidia.com-dtgtc         capi-dralabs-md-gput10-gzl84-f2m2d          gpu.nvidia.com       1      23m

برای دیدن محتوای کامل می‌توانید از خروجی YAML استفاده کنید:

kubectl get resourceslices -o yaml

هر ResourceSlice شامل مرجع مالک (.metadata.ownerReferences) و فهرست دستگاه‌ها در spec.devices است. هر دستگاه دارای ویژگی‌هایی مانند architecture، productName، driverVersion و غیره است. از آنجا که در آزمایشگاه ما هر گره حداکثر دو GPU دارد — بسیار کمتر از سقف 128 — هر گره فقط یک ResourceSlice تولید می‌کند.

نمونه‌ای از خروجی کامل ResourceSlice (خلاصه‌شده):

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: capi-dralabs-md-gpua5000-jw4mx-d64jz-gpu.nvidia.com-w9fnv
  generation: 1
spec:
  devices:
    - name: gpu-0
      driver: gpu.nvidia.com
      nodeName: capi-dralabs-md-gpua5000-jw4mx-d64jz
      uuid: GPU-e13ce856-...
      productName: NvidiaRTX
      driverVersion: "580.126.20"
      capacity:
        memory:
          value: 23028Mi
  pool:
    name: capi-dralabs-md-gpua5000-jw4mx-d64jz
    generation: 1

چگونه یک Pod به Kubernetes اعلام می‌کند که به کدام دستگاه نیاز دارد؟ اینجا ResourceClaim و ResourceClaimTemplate وارد عمل می‌شوند.

ResourceClaim & ResourceClaimTemplate

اگر بخواهید چند Pod یک دستگاه را به اشتراک بگذارند، می‌توانید یک ResourceClaim به‌طور دستی ایجاد کنید که مستقل از چرخه عمر Podها باقی می‌ماند. اما چنانچه می‌خواهید هر Pod دستگاه اختصاصی خود را داشته باشد، از ResourceClaimTemplate استفاده کنید: هر زمان یک Pod جدید از یک Deployment به این template ارجاع دهد، یک ResourceClaim مرتبط برای آن Pod ساخته می‌شود و با حذف Pod، آن ResourceClaim نیز حذف خواهد شد. این مدل مشابهٔ نحوه کار PersistentVolumeClaim و PersistentVolumeClaimTemplate در Storage است؛ DeviceClass نقش StorageClass را بازی می‌کند.

مثال سناریوی دستی با DRA — سناریو I: دو کانتینر که یک GPU را به اشتراک می‌گذارند

ابتدا یک ResourceClaim تعریف می‌کنیم که نشان دهد به یک GPU نیاز داریم:

lab01-rc.yaml
apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: must-nvidia-gpu
spec:
  devices:
    requests:
      - name: gpu
        exactly:
          deviceClassName: gpu.nvidia.com
          count: 1

اعمال ResourceClaim:

kubectl apply -f lab01-rc.yaml
kubectl get resourceclaim
NAME            STATE     AGE
must-nvidia-gpu pending   10s

اکنون می‌توان یک Pod با دو کانتینر ایجاد کرد که هر دو از همان ResourceClaim استفاده کنند تا GPU را به اشتراک بگذارند — ادامه این سناریو در بخش‌های بعدی قابل تکمیل است. 😊