במדריך הזה מוסבר איך לפשט ולהאיץ את הטעינה של משקלי מודלים של AI/ML ב-Google Kubernetes Engine (GKE) באמצעות Hyperdisk ML. מנהל ההתקן של ה-CSI של Compute Engine Persistent Disk הוא הדרך העיקרית שלכם לגשת לאחסון Hyperdisk ML באמצעות אשכולות GKE.
סקירה כללית
Hyperdisk ML הוא פתרון אחסון עם ביצועים גבוהים שאפשר להשתמש בו כדי להרחיב את האפליקציות. הוא מספק תפוקה גבוהה מצטברת למכונות וירטואליות רבות בו-זמנית, ולכן הוא אידיאלי אם רוצים להריץ עומסי עבודה של AI/ML שזקוקים לגישה לכמויות גדולות של נתונים.
כשמפעילים את Hyperdisk ML במצב קריאה בלבד, אפשר להשתמש בו כדי להאיץ את הטעינה של משקלי המודל עד פי 11.9 בהשוואה לטעינה ישירות ממאגר מודלים. ההאצה הזו מתאפשרת בזכות ארכיטקטורת Google Cloud Hyperdisk, שמאפשרת התאמה ל-2,500 צמתים בו-זמנית במהירות של 1.2 TiB/s. כך אפשר לקצר את זמני הטעינה ולהפחית את הקצאת היתר של Pod לעומסי העבודה של הסקת מסקנות ב-AI/ML.
אלה השלבים העיקריים ליצירה ולשימוש ב-Hyperdisk ML:
- טעינה מראש של נתונים במטמון או הוספת נתונים לתמונת דיסק של Persistent Disk: טעינת נפחי Hyperdisk ML עם נתונים ממקור נתונים חיצוני (לדוגמה, משקלים של Gemma שנלקחו מ-Cloud Storage) שאפשר להשתמש בהם להצגת נתונים. ה-Persistent Disk של קובץ האימג' חייב להיות תואם ל-Hyperdisk ב-Google Cloud.
- יצירת נפח Hyperdisk ML באמצעות Hyperdisk קיים ב-Google Cloud: יוצרים נפח Kubernetes שמפנה לנפח Hyperdisk ML שנטען עם נתונים. אופציונלי, אפשר ליצור סוגי אחסון מרובי-אזורים כדי לוודא שהנתונים זמינים בכל האזורים שבהם יפעלו ה-Pods.
- יצירת פריסת Kubernetes לשימוש בנפח ה-Hyperdisk ML: מפנים הפניה לנפח ה-Hyperdisk ML עם טעינת נתונים מואצת כדי שהאפליקציות יוכלו להשתמש בו.
נפחי Hyperdisk ML במספר אזורים
דיסקים של Hyperdisk ML זמינים רק בתחום אחד. אופציונלית, אפשר להשתמש בתכונה של Hyperdisk ML לריבוי אזורים כדי לקשר באופן דינמי כמה דיסקים אזוריים שמכילים את אותו התוכן ב-PersistentVolumeClaim וב-PersistentVolume לוגיים יחידים. דיסקים של תחום מוגדר שאליהם מתייחסת התכונה 'תחומים מרובים' צריכים להיות באותו אזור. לדוגמה, אם האשכול האזורי נוצר ב-us-central1, הדיסקים מרובי האזורים צריכים להיות באותו אזור (לדוגמה, us-central1-a, us-central1-b).
תרחיש שימוש נפוץ להסקת מסקנות על ידי AI/ML הוא הפעלת Pods באזורים שונים כדי לשפר את הזמינות של המאיץ ואת היעילות של העלויות באמצעות מכונות וירטואליות זמניות. מכיוון ש-Hyperdisk ML הוא אזורי, אם שרת ההסקה שלכם מפעיל הרבה Pods באזורים שונים, GKE משכפל באופן אוטומטי את הדיסקים באזורים שונים כדי לוודא שהנתונים שלכם יועברו עם האפליקציה.
יש מגבלות על נפחי Hyperdisk ML מרובי אזורים:
- אין תמיכה בפעולות של שינוי גודל של נפח אחסון וצילומי מצב של נפח אחסון.
- נפחי Hyperdisk ML מרובי אזורים נתמכים רק במצב קריאה-בלבד.
- כשמשתמשים בדיסקים קיימים עם נפח אחסון Hyperdisk ML רב-אזורי, GKE לא מבצע בדיקות כדי לוודא שהתוכן של הדיסק זהה בכל האזורים. אם אחד מהדיסקים מכיל תוכן שונה, חשוב לוודא שהאפליקציה לוקחת בחשבון את חוסר העקביות הפוטנציאלי בין האזורים.
מידע נוסף זמין במאמר בנושא יצירת נפח Hyperdisk ML מסוג ReadOnlyMany בכמה אזורים מ-VolumeSnapshot.
לפני שמתחילים
לפני שמתחילים, חשוב לוודא שביצעתם את הפעולות הבאות:
- מפעילים את ממשק ה-API של Google Kubernetes Engine. הפעלת Google Kubernetes Engine API
- אם רוצים להשתמש ב-CLI של Google Cloud למשימה הזו, צריך להתקין ואז להפעיל את ה-CLI של gcloud. אם התקנתם בעבר את ה-CLI של gcloud, מריצים את הפקודה
gcloud components updateכדי לקבל את הגרסה העדכנית. יכול להיות שגרסאות קודמות של ה-CLI של gcloud לא יתמכו בהרצת הפקודות שמופיעות במסמך הזה.
- מגדירים את אזור ברירת המחדל ואת האזור לאחד מהערכים הנתמכים.
- מוודאים של Google Cloud פרויקט יש מכסה מספקת כדי ליצור את הצמתים הדרושים במדריך הזה. קוד הדוגמה ליצירת אשכול GKE ומשאב Kubernetes דורש את המכסה המינימלית הבאה באזור שבחרתם: 88 מעבדי C3, 8 מעבדי NVIDIA L4 GPU.
דרישות
כדי להשתמש בנפחי Hyperdisk ML ב-GKE, האשכולות צריכים לעמוד בדרישות הבאות:
- משתמשים באשכולות Linux שמריצים GKE בגרסה 1.30.2-gke.1394000 או בגרסה מאוחרת יותר. אם אתם משתמשים בערוץ הפצה, צריך לוודא שבערוץ יש את גרסת GKE המינימלית או גרסה מאוחרת יותר שנדרשת למנהל ההתקן הזה.
- מוודאים שהדרייבר של Compute Engine Persistent Disk CSI מופעל. מנהל ההתקן של Persistent Disk ב-Compute Engine מופעל כברירת מחדל באשכולות חדשים במצב Autopilot ובמצב Standard, ואי אפשר להשבית או לערוך אותו כשמשתמשים ב-Autopilot. אם אתם צריכים להפעיל את מנהל ה-CSI של Persistent Disk ב-Compute Engine מהאשכול, תוכלו לעיין במאמר בנושא הפעלת מנהל ה-CSI של Persistent Disk ב-Compute Engine באשכול קיים.
- אם רוצים לשנות את הערך של קריאה מראש, צריך להשתמש בגרסה 1.29.2-gke.1217000 של GKE ואילך.
- אם אתם רוצים להשתמש בתכונה של הקצאת משאבים דינמית בכמה אזורים, אתם צריכים להשתמש ב-GKE בגרסה 1.30.2-gke.1394000 ואילך.
- Hyperdisk ML נתמך רק בסוגים מסוימים של צמתים ואזורים. למידע נוסף, אפשר לעיין במאמר מידע על Hyperdisk ML בתיעוד של Compute Engine.
קבלת גישה למודל
כדי לקבל גישה למודלים של Gemma לצורך פריסה ב-GKE, צריך קודם לחתום על הסכם ההסכמה לרישיון ואז ליצור טוקן גישה של Hugging Face.
חתימה על הסכם הסכמה לרישיון
כדי להשתמש ב-Gemma, צריך לחתום על הסכם ההסכמה. פועלים לפי ההוראות הבאות:
- נכנסים אל דף ההסכמה לשימוש במודל באתר Kaggle.com.
- צריך לאמת את ההסכמה באמצעות חשבון Hugging Face.
- מאשרים את התנאים של המודל.
יצירת אסימון גישה
כדי לגשת למודל דרך Hugging Face, תצטרכו טוקן של Hugging Face.
אם עדיין אין לכם אסימון, אתם צריכים ליצור אסימון חדש. כך עושים זאת:
- לוחצים על הפרופיל שלך > הגדרות > טוקנים של גישה.
- בוחרים באפשרות New Token (טוקן חדש).
- מציינים שם לבחירתכם ותפקיד ברמה של
Readלפחות. - לוחצים על יצירת טוקן.
- מעתיקים את הטוקן שנוצר ללוח.
יצירת אשכול GKE
אפשר להפעיל מודלים של שפה גדולה (LLM) במעבדי GPU באשכול GKE במצב Autopilot או במצב Standard. מומלץ להשתמש באשכול Autopilot כדי ליהנות מחוויית Kubernetes מנוהלת באופן מלא. כדי לבחור את מצב הפעולה של GKE שהכי מתאים לעומסי העבודה שלכם, אפשר לעיין במאמר בחירת מצב פעולה של GKE.
טייס אוטומטי
ב-Cloud Shell, מריצים את הפקודה הבאה:
gcloud container clusters create-auto hdml-gpu-l4 \ --project=PROJECT \ --location=CONTROL_PLANE_LOCATION \ --release-channel=rapid \ --cluster-version=1.30.2-gke.1394000מחליפים את הערכים הבאים:
- PROJECT: מזהה הפרויקט ב- Google Cloud .
- CONTROL_PLANE_LOCATION: האזור של Compute Engine במישור הבקרה של האשכול. מציינים אזור שתומך בסוג המאיץ שרוצים להשתמש בו, לדוגמה,
us-east4עבור L4 GPU.
GKE יוצר אשכול Autopilot עם צמתים של מעבד ו-GPU לפי בקשת עומסי העבודה שנפרסו.
מגדירים את
kubectlכדי לתקשר עם האשכול:gcloud container clusters get-credentials hdml-gpu-l4 \ --location=CONTROL_PLANE_LOCATION
רגילה
ב-Cloud Shell, מריצים את הפקודה הבאה כדי ליצור אשכול רגיל ומאגרי צמתים:
gcloud container clusters create hdml-gpu-l4 \ --location=CONTROL_PLANE_LOCATION \ --num-nodes=1 \ --machine-type=c3-standard-44 \ --release-channel=rapid \ --cluster-version=CLUSTER_VERSION \ --node-locations=ZONES \ --project=PROJECT gcloud container node-pools create gpupool \ --accelerator type=nvidia-l4,count=2,gpu-driver-version=latest \ --location=CONTROL_PLANE_LOCATION \ --project=PROJECT \ --node-locations=ZONES \ --cluster=hdml-gpu-l4 \ --machine-type=g2-standard-24 \ --num-nodes=2מחליפים את הערכים הבאים:
- CLUSTER_VERSION: הגרסה של אשכול GKE (לדוגמה, 1.30.2-gke.1394000).
- CONTROL_PLANE_LOCATION: המיקום של מישור הבקרה של האשכול ב-Compute Engine. במקרה של אשכולות אזוריים, צריך לציין אזור עם אזור תומך במאיץ שרוצים להשתמש בו. במקרה של אשכולות אזוריים, צריך לציין אזור שתומך במאיץ שרוצים להשתמש בו. כדי לבדוק איפה יחידות ה-GPU זמינות, אפשר לעיין במאמר בנושא מיקומים של יחידות GPU.
- ZONES: האזורים שבהם נוצרים הצמתים.
אפשר לציין כמה אזורים שרוצים עבור האשכול. כל האזורים צריכים להיות באותו אזור כמו מישור הבקרה של האשכול, שמוגדר באמצעות הדגל
--location. במקרה של אשכולות אזוריים,--node-locationsצריך להכיל את האזור הראשי של האשכול. - PROJECT: מזהה הפרויקט ב- Google Cloud .
יצירת האשכול עשויה להימשך כמה דקות.
מגדירים את
kubectlכדי לתקשר עם האשכול:gcloud container clusters get-credentials hdml-gpu-l4
שמירת נתונים במטמון מראש בתמונת דיסק של Persistent Disk
כדי להשתמש ב-Hyperdisk ML, צריך לשמור נתונים במטמון מראש בתמונת דיסק, וליצור נפח Hyperdisk ML לגישת קריאה על ידי עומס העבודה ב-GKE. הגישה הזו (שנקראת גם העשרת נתונים) מבטיחה שהנתונים יהיו זמינים כשעומס העבודה יזדקק להם.
בשלבים הבאים מוסבר איך להעתיק נתונים ממקור, כמו מאגר Hugging Face, ישירות לנפח Hyperdisk ML באמצעות Kubernetes Job.
אם הנתונים שלכם כבר נמצאים בקטגוריה של Cloud Storage, אתם יכולים להשתמש ב-Hyperdisk ML כדי להעביר את הנתונים מ-Cloud Storage ל-Hyperdisk ML באופן אוטומטי. כך לא תצטרכו לבצע את השלבים ליצירת משימות שמתוארים בקטעים הבאים.
יצירת StorageClass שתומך ב-Hyperdisk ML
שומרים את מניפסט StorageClass הבא בקובץ בשם
hyperdisk-ml.yaml.apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: hyperdisk-ml parameters: type: hyperdisk-ml provisioned-throughput-on-create: "2400Mi" provisioner: pd.csi.storage.gke.io allowVolumeExpansion: false reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer mountOptions: - read_ahead_kb=4096כדי ליצור את StorageClass, מריצים את הפקודה הבאה:
kubectl create -f hyperdisk-ml.yaml
יצירה של PersistentVolumeClaim מסוג ReadWriteOnce (RWO)
שומרים את מניפסט PersistentVolumeClaim הבא בקובץ בשם
producer-pvc.yaml. תשתמשו ב-StorageClass שיצרתם קודם. ה-PVC הזה משתמש במצב הגישהReadWriteOnceכי הוא משמש את Kubernetes Job להורדת נתוני מודל לדיסק אחסון מתמיד (persistent disk), שדורש גישת כתיבה. Google Cloud Hyperdisk לא תומך במצב הגישהReadWriteMany. מוודאים שיש בדיסק מספיק נפח אחסון לנתונים.kind: PersistentVolumeClaim apiVersion: v1 metadata: name: producer-pvc spec: storageClassName: hyperdisk-ml accessModes: - ReadWriteOnce resources: requests: storage: 300Giמריצים את הפקודה הבאה כדי ליצור את PersistentVolumeClaim:
kubectl create -f producer-pvc.yaml
יצירת משימת Kubernetes לאכלוס נפח Google Cloud Hyperdisk שמוטמע
בקטע הזה מוצגת דוגמה ליצירת משימת Kubernetes שמקצה דיסק ומורידה את מודל Gemma 7B שעבר כוונון להוראות מ-Hugging Face לנפח Google Cloud Hyperdisk המצורף.
כדי לגשת ל-Gemma LLM שמשמש בדוגמאות במדריך הזה, צריך ליצור Kubernetes Secret שמכיל את טוקן Hugging Face:
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=HF_TOKEN\ --dry-run=client -o yaml | kubectl apply -f -מחליפים את HF_TOKEN בטוקן של Hugging Face שיצרתם קודם.
שומרים את קובץ המניפסט לדוגמה הבא בשם
producer-job.yaml:apiVersion: batch/v1 kind: Job metadata: name: producer-job spec: template: spec: affinity: # Node affinity ensures that Pods are scheduled on the nodes that support Hyperdisk ML. nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: # Specifies the Performance compute class. For more information, # see https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-compute-classes#when-to-use. - key: cloud.google.com/compute-class operator: In values: - "Performance" - matchExpressions: - key: cloud.google.com/machine-family operator: In values: - "c3" - matchExpressions: # Restricts Pod scheduling to a specific zone because Hyperdisk ML disks # are a zonal resource. - key: topology.kubernetes.io/zone operator: In values: - "ZONE" containers: - name: copy resources: requests: cpu: "32" limits: cpu: "32" # The image used to download models from Hugging Face. image: huggingface/downloader:0.17.3 command: [ "huggingface-cli" ] args: - download # The Hugging Face model to download. - google/gemma-1.1-7b-it # Destination directory within the container. - --local-dir=/data/gemma-7b - --local-dir-use-symlinks=False env: - name: HUGGING_FACE_HUB_TOKEN valueFrom: secretKeyRef: name: hf-secret key: hf_api_token volumeMounts: # Mount path for the PersistentVolume. - mountPath: "/data" name: volume # Prevents Pod restarts on scheduling failures. The Job will create new Pods # for retries, up to the specified "backoffLimit". restartPolicy: Never volumes: - name: volume persistentVolumeClaim: # References the Hyperdisk ML PVC created earlier. claimName: producer-pvc # Runs only one Pod at any given time. parallelism: 1 # After the Pod runs successfully, the Job is complete. completions: 1 # Max retries on Pod failure. backoffLimit: 4מחליפים את ZONE באזור המחשוב שבו רוצים ליצור את ה-Hyperdisk. אם אתם משתמשים בו עם דוגמת הפריסה, ודאו שזה אזור שיש בו קיבולת של מכונות G2.
מריצים את הפקודה הבאה כדי ליצור את העבודה:
kubectl apply -f producer-job.yamlיכול להיות שיחלפו כמה דקות עד שהעבודה תסתיים ותעתיק את הנתונים לנפח של ה-Persistent Disk. כשפעולת ההקצאה של המשאבים תסתיים, הסטטוס שלה יהיה Complete (הושלם).
כדי לבדוק את ההתקדמות של סטטוס המשימה, מריצים את הפקודה הבאה:
kubectl get job producer-jobאחרי שהעבודה מסתיימת, אפשר לנקות את העבודה על ידי הרצת הפקודה הבאה:
kubectl delete job producer-job
יצירת נפח ReadOnlyMany Hyperdisk ML מ-Google Cloud Hyperdisk קיים
בקטע הזה מוסבר איך ליצור זוג של ReadOnlyMany (ROM) PersistentVolume ו-PersistentVolumeClaim מנפח Hyperdisk קיים ב-Google Cloud. מידע נוסף זמין במאמר שימוש בדיסקים קיימים של אחסון מתמיד כנפחי אחסון מתמיד.
ב-GKE בגרסה 1.30.2-gke.1394000 ואילך, GKE ממיר אוטומטית את מצב הגישה של נפח
READ_WRITE_SINGLEGoogle Cloud Hyperdisk ל-READ_ONLY_MANY.אם אתם משתמשים בנפח Hyperdisk קיים ב-Google Cloud בגרסה קודמת של GKE, אתם צריכים לשנות את מצב הגישה באופן ידני באמצעות הפקודה הבאה:
gcloud compute disks update HDML_DISK_NAME \ --zone=ZONE \ --access-mode=READ_ONLY_MANYמחליפים את הערכים הבאים:
- HDML_DISK_NAME: השם של נפח Hyperdisk ML.
- ZONE: אזור החישוב שבו נוצר נפח האחסון הקיים מראש ב-Google Cloud Hyperdisk.
יוצרים צמד של PersistentVolume ו-PersistentVolumeClaim, עם הפניה לדיסק שאכלסתם קודם.
שומרים את קובץ המניפסט הבא בשם
hdml-static-pv.yaml:apiVersion: v1 kind: PersistentVolume metadata: name: hdml-static-pv spec: storageClassName: "hyperdisk-ml" capacity: storage: 300Gi # The "ReadOnlyMany" access mode allows the volume to be mounted by multiple # nodes for read-only access. accessModes: - ReadOnlyMany # ClaimRef links this PersistentVolume to a PersistentVolumeClaim. claimRef: namespace: default name: hdml-static-pvc csi: driver: pd.csi.storage.gke.io # The unique identifier of the Compute Engine disk resource backing # this volume. volumeHandle: projects/PROJECT/zones/ZONE/disks/DISK_NAME fsType: ext4 readOnly: true # Node affinity ensures that Pod is scheduled in a zone where the volume # is replicated. nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: topology.gke.io/zone operator: In values: - ZONE --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: default name: hdml-static-pvc spec: storageClassName: "hyperdisk-ml" volumeName: hdml-static-pv accessModes: - ReadOnlyMany resources: requests: storage: 300Giמחליפים את הערכים הבאים:
- PROJECT: הפרויקט שבו נוצר אשכול GKE.
- ZONE: האזור שבו נוצר נפח האחסון הקיים מראש ב-Google Cloud Hyperdisk.
- DISK_NAME: השם של נפח האחסון הקיים מראש ב-Google Cloud Hyperdisk.
כדי ליצור את המשאבים PersistentVolume ו-PersistentVolumeClaim, מריצים את הפקודה הבאה:
kubectl apply -f hdml-static-pv.yaml
יצירת נפח Hyperdisk ML מסוג ReadOnlyMany בכמה אזורים מ-VolumeSnapshot
בקטע הזה מוסבר איך ליצור נפח Hyperdisk ML רב-אזורי במצב גישה ReadOnlyMany. משתמשים ב-VolumeSnapshot לתמונת דיסק קיימת של Persistent Disk. למידע נוסף, אפשר לעיין במאמר בנושא גיבוי של אחסון ב-Persistent Disk באמצעות תמונות מצב של נפח האחסון.
כדי ליצור נפח Hyperdisk ML רב-אזורי, פועלים לפי השלבים הבאים:
יצירת VolumeSnapshot של הדיסק
שומרים את קובץ המניפסט הבא בשם
disk-image-vsc.yaml.apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshotClass metadata: name: disk-image-vsc driver: pd.csi.storage.gke.io # The snapshot will be deleted when the "VolumeSnapshot" object is deleted. deletionPolicy: Delete parameters: snapshot-type: imagesכדי ליצור את VolumeSnapshotClass, מריצים את הפקודה הבאה:
kubectl apply -f disk-image-vsc.yamlשומרים את קובץ המניפסט הבא בשם
my-snapshot.yaml. תצטרכו להפנות אל PersistentVolumeClaim שיצרתם קודם במאמר יצירת PersistentVolumeClaim מסוג ReadWriteOnce (RWO).apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshot metadata: name: my-snapshot spec: volumeSnapshotClassName: disk-image-vsc source: # The name of the PersistentVolumeClaim to snapshot. persistentVolumeClaimName: producer-pvcכדי ליצור את VolumeSnapshot, מריצים את הפקודה הבאה:
kubectl apply -f my-snapshot.yamlכשהסטטוס של VolumeSnapshot הוא Ready, מריצים את הפקודה הבאה כדי ליצור את נפח ה-ML של Hyperdisk:
kubectl wait --for=jsonpath='{.status.readyToUse}'=true \ --timeout=300s volumesnapshot my-snapshot
יצירת StorageClass מרובה אזורים
אם רוצים שהעותקים של הנתונים יהיו נגישים ביותר מאזור אחד, צריך לציין את הפרמטר enable-multi-zone-provisioning ב-StorageClass, שיצור דיסקים באזורים שצוינו בשדה allowedTopologies.
כדי ליצור את StorageClass, מבצעים את השלבים הבאים:
שומרים את קובץ המניפסט הבא בשם
hyperdisk-ml-multi-zone.yaml.apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: hyperdisk-ml-multi-zone parameters: type: hyperdisk-ml provisioned-throughput-on-create: "4800Mi" enable-multi-zone-provisioning: "true" provisioner: pd.csi.storage.gke.io allowVolumeExpansion: false reclaimPolicy: Delete volumeBindingMode: Immediate allowedTopologies: - matchLabelExpressions: - key: topology.gke.io/zone values: - ZONE_1 - ZONE_2 mountOptions: - read_ahead_kb=8192מחליפים את ZONE_1, ZONE_2, ..., ZONE_N באזורים שבהם אפשר לגשת לאחסון.
בדוגמה הזו, הערך של volumeBindingMode מוגדר ל-
Immediate, כך ש-GKE יכול להקצות את PersistentVolumeClaim לפני שצרכן כלשהו מפנה אליו.יוצרים את StorageClass באמצעות הפקודה הבאה:
kubectl apply -f hyperdisk-ml-multi-zone.yaml
יצירת PersistentVolumeClaim שמשתמש ב-StorageClass מרובה אזורים
השלב הבא הוא ליצור PersistentVolumeClaim שמפנה אל StorageClass.
GKE משתמש בתוכן של תמונת הדיסק שצוינה כדי להקצות באופן אוטומטי נפח אחסון של Hyperdisk ML בכל אזור שצוין בתמונת המצב.
כדי ליצור את PersistentVolumeClaim, מבצעים את השלבים הבאים:
שומרים את קובץ המניפסט הבא בשם
hdml-consumer-pvc.yaml.kind: PersistentVolumeClaim apiVersion: v1 metadata: name: hdml-consumer-pvc spec: # Specifies that the new PersistentVolumeClaim should be provisioned from the # contents of the volume snapshot named "my-snapshot". dataSource: name: my-snapshot kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io accessModes: - ReadOnlyMany storageClassName: hyperdisk-ml-multi-zone resources: requests: storage: 300Giכדי ליצור את PersistentVolumeClaim, מריצים את הפקודה הבאה:
kubectl apply -f hdml-consumer-pvc.yaml
יצירת פריסה לשימוש בנפח האחסון של Hyperdisk ML
כשמשתמשים ב-Pods עם PersistentVolumes, מומלץ להשתמש בבקר של עומס עבודה (למשל Deployment או StatefulSet).
אם רוצים להשתמש ב-PersistentVolume קיים במצב ReadOnlyMany עם Deployment, אפשר לעיין במאמר שימוש בדיסקים קבועים עם כמה קוראים.
כדי ליצור ולבדוק את הפריסה, פועלים לפי השלבים הבאים:
שומרים את קובץ המניפסט לדוגמה הבא בשם
vllm-gemma-deployment.apiVersion: apps/v1 kind: Deployment metadata: name: vllm-gemma-deployment spec: replicas: 2 selector: # Labels used to select the Pods managed by this Deployment. matchLabels: app: gemma-server template: metadata: labels: app: gemma-server # Labels for AI/GKE integration. ai.gke.io/model: gemma-7b ai.gke.io/inference-server: vllm spec: affinity: # Node affinity ensures Pods run on nodes with L4 GPUs. nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: cloud.google.com/gke-accelerator operator: In values: - nvidia-l4 # Pod anti-affinity prefers scheduling Pods in different zones for # higher availability. podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - gemma-server topologyKey: topology.kubernetes.io/zone containers: - name: inference-server # The container image for the vLLM inference server. image: us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:latest resources: requests: cpu: "2" memory: "25Gi" ephemeral-storage: "25Gi" nvidia.com/gpu: 2 limits: cpu: "2" memory: "25Gi" ephemeral-storage: "25Gi" nvidia.com/gpu: 2 # Command to run the vLLM API server. command: ["python3", "-m", "vllm.entrypoints.api_server"] args: # Specifies the model to load, using an environment variable. - --model=$(MODEL_ID) - --tensor-parallel-size=2 env: # Environment variable to define the model path. - name: MODEL_ID value: /models/gemma-7b volumeMounts: - mountPath: /dev/shm name: dshm # Mount point for the Hyperdisk ML volume containing the model. - mountPath: /models name: gemma-7b volumes: - name: dshm emptyDir: medium: Memory - name: gemma-7b # References the PersistentVolumeClaim for the Hyperdisk ML volume. persistentVolumeClaim: claimName: CLAIM_NAME --- apiVersion: v1 kind: Service metadata: name: llm-service spec: # Selects Pods with the label "app: gemma-server". selector: app: gemma-server # The "ClusterIP" field makes the Service reachable only within the cluster. type: ClusterIP ports: - protocol: TCP port: 8000 targetPort: 8000מחליפים את CLAIM_NAME באחד מהערכים האלה:
-
hdml-static-pvc: אם אתם משתמשים בנפח אחסון של Hyperdisk ML מ-Google Cloud Hyperdisk קיים. -
hdml-consumer-pvc: אם אתם משתמשים בנפח Hyperdisk ML מתמונת דיסק של VolumeSnapshot.
-
מריצים את הפקודה הבאה כדי להמתין עד ששרת ההסקה יהיה זמין:
kubectl wait --for=condition=Available --timeout=700s deployment/vllm-gemma-deploymentכדי לבדוק שהשרת vLLM פועל, מבצעים את הפעולות הבאות:
מריצים את הפקודה הבאה כדי להגדיר העברת נתונים (פורט פורוורדינג) למודל:
kubectl port-forward service/llm-service 8000:8000מריצים את הפקודה
curlכדי לשלוח בקשה למודל:USER_PROMPT="I'm new to coding. If you could only recommend one programming language to start with, what would it be and why?" curl -X POST http://localhost:8000/generate \ -H "Content-Type: application/json" \ -d @- <<EOF { "prompt": "<start_of_turn>user\n${USER_PROMPT}<end_of_turn>\n", "temperature": 0.90, "top_p": 1.0, "max_tokens": 128 } EOF
בדוגמה הבאה אפשר לראות את התשובה של המודל:
{"predictions":["Prompt:\n<start_of_turn>user\nI'm new to coding. If you could only recommend one programming language to start with, what would it be and why?<end_of_turn>\nOutput:\nPython is often recommended for beginners due to its clear, readable syntax, simple data types, and extensive libraries.\n\n**Reasons why Python is a great language for beginners:**\n\n* **Easy to read:** Python's syntax is straightforward and uses natural language conventions, making it easier for beginners to understand the code.\n* **Simple data types:** Python has basic data types like integers, strings, and lists that are easy to grasp and manipulate.\n* **Extensive libraries:** Python has a vast collection of well-documented libraries covering various tasks, allowing beginners to build projects without reinventing the wheel.\n* **Large supportive community:**"]}
שינוי הערך של קריאה מראש
אם יש לכם עומסי עבודה שמבצעים קלט/פלט רציף, יכול להיות שכדאי לכם לשנות את ערך הקריאה מראש. הדבר רלוונטי בדרך כלל להיקש או לעומסי עבודה של אימון שדורשים טעינה של משקלים של מודלים של AI/ML לזיכרון. ברוב עומסי העבודה עם קלט/פלט רציף, יש שיפור בביצועים עם ערך קריאה מראש של 1,024 KB ומעלה.
שינוי הערך של קריאה מראש בכרכים חדשים
כדי לציין את האפשרות הזו, מוסיפים את read_ahead_kb לשדה mountOptions
ב-StorageClass. בדוגמה הבאה אפשר לראות איך משנים את הערך של readahead ל-4096 KB. ההגדרה הזו תחול על PersistentVolumes חדשים שמוקצים באופן דינמי ונוצרים באמצעות hyperdisk-ml StorageClass.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: hyperdisk-ml
parameters:
type: hyperdisk-ml
provisioner: pd.csi.storage.gke.io
allowVolumeExpansion: false
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
mountOptions:
- read_ahead_kb=4096
שינוי הערך של קריאה מראש עבור נפחי אחסון קיימים
בנפחים שהוקצו באופן סטטי או ב-PersistentVolumes קיימים, אפשר לציין את האפשרות הזו על ידי הוספת read_ahead_kb לשדה spec.mountOptions.
בדוגמה הבאה אפשר לראות איך משנים את הערך של readahead ל-4096 KB.
apiVersion: v1
kind: PersistentVolume
name: DISK_NAME
spec:
accessModes:
- ReadOnlyMany
capacity:
storage: 300Gi
csi:
driver: pd.csi.storage.gke.io
fsType: ext4
readOnly: true
# The unique identifier of the Compute Engine disk resource backing this volume.
volumeHandle: projects/PROJECT/zones/ZONE/disks/DISK_NAME
# Node affinity ensures that Pods are scheduled in the zone where the volume exists.
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: topology.gke.io/zone
operator: In
values:
- ZONE
storageClassName: hyperdisk-ml
mountOptions:
- read_ahead_kb=4096
מחליפים את הערכים הבאים:
- DISK_NAME: השם של נפח האחסון הקיים מראש ב-Google Cloud Hyperdisk.
- ZONE: האזור שבו נוצר נפח האחסון הקיים מראש ב-Google Cloud Hyperdisk.
בדיקה והשוואה של ביצועי נפח ה-Hyperdisk ML
בקטע הזה מוסבר איך אפשר להשתמש ב-Flexible I/O Tester (FIO) כדי להשוות את הביצועים של נפחי Hyperdisk ML לצורך קריאת נתונים קיימים . אפשר להשתמש במדדים האלה כדי להעריך את הביצועים של נפח אחסון מסוים עבור עומסי עבודה והגדרות ספציפיים.
שומרים את קובץ המניפסט לדוגמה הבא בשם
benchmark-job.yaml:apiVersion: batch/v1 kind: Job metadata: name: benchmark-job spec: template: # Template for the Pods the Job will create. spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: cloud.google.com/compute-class operator: In values: - "Performance" - matchExpressions: - key: cloud.google.com/machine-family operator: In values: - "c3" containers: - name: fio resources: requests: cpu: "32" image: litmuschaos/fio args: - fio # Specifies the files to use for the benchmark. Multiple files can be separated by colons. - --filename - /models/gemma-7b/model-00001-of-00004.safetensors:/models/gemma-7b/model-00002-of-00004.safetensors:/models/gemma-7b/model-00003-of-00004.safetensors:/models/gemma-7b/model-00004-of-00004.safetensors:/models/gemma-7b/model-00004-of-00004.safetensors # Use non-buffered I/O. - --direct=1 # Set the I/O pattern to read. - --rw=read # Open files in read-only mode. - --readonly # Block size for I/O operations. - --bs=4096k # I/O engine to use. - --ioengine=libaio # Number of I/O units to keep in flight against each file. - --iodepth=8 # Duration of the test in seconds. - --runtime=60 # Number of jobs to run. - --numjobs=1 # Name of the job. - --name=read_benchmark volumeMounts: - mountPath: "/models" name: volume restartPolicy: Never volumes: - name: volume persistentVolumeClaim: claimName: hdml-static-pvc parallelism: 1 completions: 1 backoffLimit: 1מחליפים את CLAIM_NAME בשם של PersistentVolumeClaim (לדוגמה,
hdml-static-pvc).כדי ליצור את המשימה, מריצים את הפקודה הבאה:
kubectl apply -f benchmark-job.yaml.אפשר להשתמש ביומנים של
kubectlכדי לראות את הפלט של הכליfio:kubectl logs benchmark-job-nrk88 -fהפלט אמור להיראות כך:
read_benchmark: (g=0): rw=read, bs=4M-4M/4M-4M/4M-4M, ioengine=libaio, iodepth=8 fio-2.2.10 Starting 1 process read_benchmark: (groupid=0, jobs=1): err= 0: pid=32: Fri Jul 12 21:29:32 2024 read : io=18300MB, bw=2407.3MB/s, iops=601, runt= 7602msec slat (usec): min=86, max=1614, avg=111.17, stdev=64.46 clat (msec): min=2, max=33, avg=13.17, stdev= 1.08 lat (msec): min=2, max=33, avg=13.28, stdev= 1.06 clat percentiles (usec): | 1.00th=[11072], 5.00th=[12352], 10.00th=[12608], 20.00th=[12736], | 30.00th=[12992], 40.00th=[13120], 50.00th=[13248], 60.00th=[13376], | 70.00th=[13504], 80.00th=[13632], 90.00th=[13888], 95.00th=[14016], | 99.00th=[14400], 99.50th=[15296], 99.90th=[22144], 99.95th=[25728], | 99.99th=[33024] bw (MB /s): min= 2395, max= 2514, per=100.00%, avg=2409.79, stdev=29.34 lat (msec) : 4=0.39%, 10=0.31%, 20=99.15%, 50=0.15% cpu : usr=0.28%, sys=8.08%, ctx=4555, majf=0, minf=8203 IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=99.8%, 16=0.0%, 32=0.0%, >=64=0.0% submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0% complete : 0=0.0%, 4=100.0%, 8=0.1%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0% issued : total=r=4575/w=0/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0 latency : target=0, window=0, percentile=100.00%, depth=8 Run status group 0 (all jobs): READ: io=18300MB, aggrb=2407.3MB/s, minb=2407.3MB/s, maxb=2407.3MB/s, mint=7602msec, maxt=7602msec Disk stats (read/write): nvme0n2: ios=71239/0, merge=0/0, ticks=868737/0, in_queue=868737, util=98.72%
מעקב אחרי קצב העברת הנתונים או פעולות הקלט/פלט בשנייה (IOPS) בנפח אחסון של Hyperdisk ML
כדי לעקוב אחר הביצועים שסופקו לנפח Hyperdisk ML, אפשר לעיין במאמר ניתוח של פעולות קלט/פלט בשנייה (IOPS) וקצב העברת נתונים (throughput) שסופקו במסמכי Compute Engine.
כדי לעדכן את קצב העברת הנתונים או את פעולות הקלט/פלט בשנייה של נפח Hyperdisk ML קיים, או כדי לקבל מידע על פרמטרים נוספים של Google Cloud Hyperdisk שאפשר לציין ב-StorageClass, אפשר לעיין במאמר שינוי הביצועים של האחסון באמצעות Google Cloud Hyperdisk.
פתרון בעיות
בקטע הזה מפורטות הנחיות לפתרון בעיות שקשורות לנפחי Hyperdisk ML ב-GKE.
אי אפשר לעדכן את מצב הגישה לדיסק
השגיאה הבאה מתרחשת כשנפח Hyperdisk ML כבר נמצא בשימוש ומצורף לצומת במצב גישה ReadWriteOnce.
AttachVolume.Attach failed for volume ... Failed to update access mode:
failed to set access mode for zonal volume ...
'Access mode cannot be updated when the disk is attached to instance(s).'., invalidResourceUsage
GKE מעדכן באופן אוטומטי את accessMode של נפח Hyperdisk ML מ-READ_WRITE_SINGLE ל-READ_ONLY_MANY, כשהוא נמצא בשימוש על ידי PersistentVolume עם מצב גישה ReadOnlyMany. העדכון הזה מתבצע כשהדיסק מצורף לצומת חדש.
כדי לפתור את הבעיה, צריך למחוק את כל ה-Pods שמפנים לדיסק באמצעות PersistentVolume במצב ReadWriteOnce. ממתינים עד שהדיסק ינותק, ואז יוצרים מחדש את עומס העבודה שמשתמש ב-PersistentVolume במצב ReadOnlyMany.
אי אפשר לצרף את הדיסק במצב READ_WRITE
השגיאה הבאה מציינת ש-GKE ניסה לצרף נפח Hyperdisk ML בREAD_ONLY_MANY מצב גישה למכונת GKE באמצעות מצב גישה ReadWriteOnce.
AttachVolume.Attach failed for volume ...
Failed to Attach: failed cloud service attach disk call ...
The disk cannot be attached with READ_WRITE mode., badRequest
GKE מעדכן באופן אוטומטי את accessMode של נפח Hyperdisk ML מ-READ_WRITE_SINGLE ל-READ_ONLY_MANY, כשהוא נמצא בשימוש על ידי PersistentVolume עם מצב גישה ReadOnlyMany. עם זאת, GKE לא יעדכן אוטומטית את מצב הגישה מ-READ_ONLY_MANY ל-READ_WRITE_SINGLE.
זהו מנגנון בטיחות שמטרתו לוודא שלא מתבצעת כתיבה בטעות בדיסקים רב-אזוריים, כי כתיבה כזו עלולה לגרום לתוכן שונה בדיסקים רב-אזוריים.
כדי לפתור את הבעיה, מומלץ לפעול לפי תהליך העבודה Pre-cache data to a Persistent Disk disk image אם אתם צריכים תוכן מעודכן. אם אתם צריכים שליטה רבה יותר במצב הגישה של נפח האחסון Hyperdisk ML ובהגדרות אחרות, אפשר לעיין במאמר בנושא שינוי ההגדרות של נפח אחסון מסוג Hyperdisk. Google Cloud
חריגה מהמכסה – מכסת תפוקה לא מספיקה
השגיאה הבאה מציינת שלא היה מספיק נפח העברה (throughput) של Hyperdisk ML בזמן הקצאת הדיסק.
failed to provision volume with StorageClass ... failed (QUOTA_EXCEEDED): Quota 'HDML_TOTAL_THROUGHPUT' exceeded
כדי לפתור את הבעיה הזו, אפשר לעיין במאמר מכסות דיסקים כדי לקבל מידע נוסף על מכסת Hyperdisk ועל הגדלת מכסת הדיסקים בפרויקט.
הנחיות נוספות לפתרון בעיות זמינות במאמר שיפור ביצועי האחסון באמצעות Google Cloud Hyperdisk.
המאמרים הבאים
- איך להשתמש ב-GKE Volume Populator כדי להעביר נתונים מ-Cloud Storage לנפח Hyperdisk באופן אוטומטי
- איך מעבירים נפחי Persistent Disk ל-Hyperdisk
- מידע נוסף על מנהל התקן Persistent Disk CSI ב-GitHub