שיתוף של מעבדי GPU בין עומסי עבודה באמצעות שיתוף זמן של GPU

בדף הזה מוסבר איך לאפשר לכמה עומסי עבודה (workload) לקבל גישה לחלוקת זמן ב-GPU למאיץ חומרה יחיד מסוג NVIDIA®‎ בצמתים של Google Kubernetes Engine‏ (GKE). באמצעות שיתוף זמן השימוש במעבד הגרפי ב-GKE, אתם יכולים להשתמש במעבדים הגרפיים המצורפים בצורה יעילה יותר ולחסוך בעלויות ההפעלה.

הדף הזה מיועד למפתחים שמתכננים ומפריסים עומסי עבודה באשכולות GKE, ולאדמינים ולמומחי ארכיטקטורה שיוצרים ומנהלים אשכול GKE, מתכננים את התשתית ואת דרישות המשאבים ועוקבים אחרי הביצועים של האשכול. כדי לקבל מידע נוסף על תפקידים נפוצים ועל משימות לדוגמה שאנחנו מתייחסים אליהן ב Google Cloud תוכן, אפשר לעיין במאמר תפקידים נפוצים של משתמשי GKE ומשימות.

לפני שקוראים את הדף הזה, חשוב להכיר את אופן הפעולה של שיתוף זמן ב-GKE, כולל המגבלות והמקרים שבהם כדאי להשתמש בשיתוף זמן ב-GPU.

דרישות

  • גרסת GKE: אפשר להפעיל שיתוף זמן של GPU באשכולות GKE Standard שפועלים בגרסה ‎1.23.7-gke.1400 ואילך של GKE. אפשר להשתמש ב-GPU עם שיתוף זמן באשכולות GKE Autopilot שמופעלת בהם גרסה GKE 1.29.3-gke.1093000 ואילך.
  • סוג ה-GPU: אפשר להפעיל שיתוף זמן של GPU בכל המודלים של NVIDIA GPU.

לפני שמתחילים

לפני שמתחילים, חשוב לוודא שביצעתם את הפעולות הבאות:

  • מפעילים את ממשק ה-API של Google Kubernetes Engine.
  • הפעלת Google Kubernetes Engine API
  • אם רוצים להשתמש ב-CLI של Google Cloud למשימה הזו, צריך להתקין ואז להפעיל את ה-CLI של gcloud. אם התקנתם בעבר את ה-CLI של gcloud, מריצים את הפקודה gcloud components update כדי לקבל את הגרסה העדכנית. יכול להיות שגרסאות קודמות של ה-CLI של gcloud לא יתמכו בהרצת הפקודות שמופיעות במסמך הזה.

הפעלת שיתוף זמן של GPU באשכולות GKE ובמאגרי צמתים

אדמינים של פלטפורמות צריכים להפעיל שיתוף זמן של GPU באשכול GKE Standard לפני שמפתחים יכולים לפרוס עומסי עבודה כדי להשתמש ב-GPU. כדי להפעיל שיתוף זמן של GPU, צריך לבצע את הפעולות הבאות:

  1. הפעלת שיתוף זמן ב-GPU באשכול GKE.
  2. מתקינים דרייברים של מכשיר GPU של NVIDIA (אם נדרש).
  3. מוודאים שמשאבי ה-GPU זמינים בצמתים.

באשכולות Autopilot שמופעלת בהם גרסה 1.29.3-gke.1093000 ואילך, כרטיסי GPU עם שיתוף זמן מופעלים כברירת מחדל. הגדרת שיתוף זמן באשכולות של Autopilot מתבצעת במפרט של עומס העבודה. מידע נוסף זמין בקטע פריסת עומסי עבודה שמשתמשים במעבדי GPU עם שיתוף זמן.

הפעלת שיתוף זמן ב-GPU באשכול GKE Standard

אפשר להפעיל שיתוף זמן של GPU כשיוצרים אשכולות GKE Standard. מאגר הצמתים שמוגדר כברירת מחדל באשכול כולל את התכונה. עדיין צריך להפעיל שיתוף זמן של GPU כשיוצרים ידנית מאגרי צמתים חדשים באותו אשכול.

gcloud container clusters create CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --cluster-version=CLUSTER_VERSION \
    --machine-type=MACHINE_TYPE \
    --accelerator=type=GPU_TYPE,count=GPU_QUANTITY,gpu-sharing-strategy=time-sharing,max-shared-clients-per-gpu=CLIENTS_PER_GPU,gpu-driver-version=DRIVER_VERSION

מחליפים את מה שכתוב בשדות הבאים:

  • CLUSTER_NAME: השם של האשכול החדש.
  • CONTROL_PLANE_LOCATION: המיקום של מישור הבקרה של האשכול ב-Compute Engine. מציינים אזור לאשכולות אזוריים או אזור זמין לאשכולות אזוריים.
  • CLUSTER_VERSION: גרסת GKE למישור הבקרה ולצמתים של האשכול. משתמשים ב-GKE גרסה ‎1.23.7-gke.1400 ואילך. אפשר גם לציין ערוץ הפצה עם גרסת GKE הזו באמצעות הדגל --release-channel=RELEASE_CHANNEL.
  • MACHINE_TYPE: סוג המכונה של Compute Engine עבור הצמתים. מומלץ לבחור סוג מכונה שעבר אופטימיזציה לשימוש במאיץ.
  • GPU_TYPE: סוג ה-GPU, שחייב להיות פלטפורמת NVIDIA GPU, כמו nvidia-tesla-v100.
  • GPU_QUANTITY: מספר המעבדים הגרפיים הפיזיים לצירוף לכל צומת במאגר הצמתים שמוגדר כברירת מחדל.
  • CLIENTS_PER_GPU: המספר המקסימלי של קונטיינרים שיכולים לשתף כל GPU פיזי.
  • DRIVER_VERSION: גרסת הדרייבר של NVIDIA להתקנה. יכול להיות אחת מהאפשרויות הבאות:
    • default: התקנת גרסת ברירת המחדל של הדרייבר לגרסת GKE.
    • latest: התקנת הגרסה האחרונה של מנהל ההתקן שזמינה לגרסת GKE שלכם. האפשרות הזו זמינה רק לצמתים שמשתמשים במערכת הפעלה שמותאמת לקונטיינרים.
    • disabled: דילוג על התקנה אוטומטית של מנהל התקן. חובה להתקין מנהל התקן באופן ידני אחרי שיוצרים את מאגר הצמתים. אם לא מציינים את gpu-driver-version, זו אפשרות ברירת המחדל.

הפעלת שיתוף זמן של GPU במאגר צמתים של GKE

אפשר להפעיל שיתוף זמן של GPU כשיוצרים מאגרים חדשים של צמתים באופן ידני באשכול GKE.

gcloud container node-pools create NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --machine-type=MACHINE_TYPE \
    --accelerator=type=GPU_TYPE,count=GPU_QUANTITY,gpu-sharing-strategy=time-sharing,max-shared-clients-per-gpu=CLIENTS_PER_GPU,gpu-driver-version=DRIVER_VERSION

מחליפים את מה שכתוב בשדות הבאים:

  • NODEPOOL_NAME: השם של מאגר הצמתים החדש.
  • CLUSTER_NAME: שם האשכול, שצריך להריץ GKE בגרסה ‎1.23.7-gke.1400 ואילך.
  • CONTROL_PLANE_LOCATION: המיקום של מישור הבקרה של האשכול ב-Compute Engine. מציינים אזור לאשכולות אזוריים או אזור זמין לאשכולות אזוריים.
  • MACHINE_TYPE: סוג המכונה של Compute Engine עבור הצמתים. מומלץ לבחור סוג מכונה שעבר אופטימיזציה לשימוש במאיץ.
  • GPU_TYPE: סוג ה-GPU, שחייב להיות פלטפורמת NVIDIA GPU, כמו nvidia-tesla-v100.
  • GPU_QUANTITY: מספר המעבדים הגרפיים הפיזיים לצירוף לכל צומת במאגר הצמתים.
  • CLIENTS_PER_GPU: המספר המקסימלי של קונטיינרים שיכולים לשתף כל GPU פיזי.
  • DRIVER_VERSION: גרסת הדרייבר של NVIDIA להתקנה. יכול להיות אחת מהאפשרויות הבאות:

    • default: התקנת גרסת ברירת המחדל של הדרייבר לגרסת GKE.
    • latest: התקנת הגרסה האחרונה של מנהל ההתקן שזמינה לגרסת GKE שלכם. האפשרות הזו זמינה רק לצמתים שמשתמשים במערכת הפעלה שמותאמת לקונטיינרים.
    • disabled: דילוג על התקנה אוטומטית של מנהל התקן. חובה להתקין מנהל התקן באופן ידני אחרי שיוצרים את מאגר הצמתים. אם לא מציינים את gpu-driver-version, זו אפשרות ברירת המחדל.

התקנה של דרייברים של מכשירי NVIDIA GPU

לפני שממשיכים, מתחברים לאשכול על ידי הרצת הפקודה הבאה:

gcloud container clusters get-credentials CLUSTER_NAME

אם בחרתם להשבית את ההתקנה האוטומטית של מנהלי ההתקנים כשיוצרים את האשכול, או אם אתם משתמשים בגרסת GKE מוקדמת יותר מ-1.27.2-gke.1200, אתם צריכים להתקין באופן ידני מנהל התקן תואם של NVIDIA כדי לנהל את חלוקת הזמן של ה-GPU ב-GPU הפיזיים. כדי להתקין את מנהלי ההתקנים, צריך לפרוס DaemonSet של התקנת GKE שמגדיר את מנהלי ההתקנים.

הוראות מפורטות מופיעות במאמר בנושא התקנת דרייברים של מכשירי GPU של NVIDIA.

אם אתם מתכננים להשתמש בהקצאת צמתים אוטומטית (NAP) באשכול, אתם צריכים גם להגדיר הקצאת צמתים אוטומטית (NAP) עם היקפי ההרשאות שמאפשרים ל-GKE להתקין בשבילכם את מנהלי ההתקנים של מכשיר ה-GPU. הוראות מפורטות זמינות במאמר בנושא שימוש בהקצאת משאבים אוטומטית של צמתים עם מעבדי GPU.

אימות משאבי ה-GPU שזמינים בצמתים

כדי לוודא שמספר ה-GPU שמוצג בצמתים תואם למספר שציינתם כשהפעלתם שיתוף זמן של GPU, מתארים את הצמתים:

kubectl describe nodes NODE_NAME

הפלט אמור להיראות כך:

...
Capacity:
  ...
  nvidia.com/gpu:             3
Allocatable:
  ...
  nvidia.com/gpu:             3

בדוגמה הזו, מספר משאבי ה-GPU בצומת הוא 3 כי הערך שצוין עבור max-shared-clients-per-gpu היה 3 ומספר ה-GPU הפיזיים לצירוף לצומת היה 1.count דוגמה נוספת: אם count של מעבדי GPU פיזיים היה 2, הפלט היה מציג 6 משאבי GPU שניתנים להקצאה, שלושה בכל מעבד GPU פיזי.

פריסת עומסי עבודה שמשתמשים בשיתוף זמן של GPU

מפעילים של אפליקציות שמבצעים פריסה של עומסי עבודה ב-GPU יכולים לבחור באפשרות של שיתוף זמן ב-GPU על ידי ציון תוויות הצומת המתאימות ב-nodeSelector במניפסטים שלהם. כשמתכננים את הבקשות, חשוב לעיין במגבלות הבקשות כדי לוודא ש-GKE לא ידחה את הפריסות.

כדי לפרוס עומס עבודה לשימוש בשיתוף זמן של GPU, מבצעים את השלבים הבאים:

  1. מוסיפים nodeSelector למניפסט של עומס העבודה עבור התוויות הבאות:

    • cloud.google.com/gke-gpu-sharing-strategy: time-sharing: בחירת צמתים שמשתמשים בשיתוף זמן של GPU.
    • cloud.google.com/gke-max-shared-clients-per-gpu: "CLIENTS_PER_GPU": בוחר צמתים שמאפשרים למספר מסוים של קונטיינרים לשתף את ה-GPU הבסיסי.
  2. מוסיפים את בקשת משאב ה-GPU‏ nvidia.com/gpu=1 למפרט הקונטיינר ב-spec.containers.resources.limits.

לדוגמה, השלבים הבאים מראים איך לפרוס שלושה Pods למאגר צמתים של שיתוף זמן ב-GPU. ‫GKE מקצה כל קונטיינר לאותו GPU פיזי. הקונטיינרים מדפיסים את ה-UUID של ה-GPU שמצורף לקונטיינר.

  1. שומרים את קובץ המניפסט הבא בשם gpu-timeshare.yaml:

טייס אוטומטי

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: cuda-simple
        spec:
          replicas: 3
          selector:
            matchLabels:
              app: cuda-simple
          template:
            metadata:
              labels:
                app: cuda-simple
            spec:
              nodeSelector:
                cloud.google.com/gke-accelerator: "GPU_TYPE"
                cloud.google.com/gke-gpu-sharing-strategy: "time-sharing"
                cloud.google.com/gke-max-shared-clients-per-gpu: "CLIENTS_PER_GPU"
                cloud.google.com/gke-accelerator-count: "GPU_COUNT"
              containers:
              - name: cuda-simple
                image: nvidia/cuda:11.0.3-base-ubi7
                command:
                - bash
                - -c
                - |
                  /usr/local/nvidia/bin/nvidia-smi -L; sleep 300
                resources:
                  limits:
                    nvidia.com/gpu: 1
      

מחליפים את מה שכתוב בשדות הבאים:

  • GPU_TYPE: סוג ה-GPU.
  • CLIENTS_PER_GPU: מספר עומסי העבודה שישתמשו ב-GPU הזה. בדוגמה הזו, נשתמש ב-3.
  • GPU_COUNT: מספר יחידות ה-GPU הפיזיות לצירוף לצומת. בדוגמה הזו, נשתמש ב-1.

רגילה

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: cuda-simple
        spec:
          replicas: 3
          selector:
            matchLabels:
              app: cuda-simple
          template:
            metadata:
              labels:
                app: cuda-simple
            spec:
              nodeSelector:
                cloud.google.com/gke-gpu-sharing-strategy: "SHARING_STRATEGY"
                cloud.google.com/gke-max-shared-clients-per-gpu: "CLIENTS_PER_GPU"
              containers:
              - name: cuda-simple
                image: nvidia/cuda:11.0.3-base-ubi7
                command:
                - bash
                - -c
                - |
                  /usr/local/nvidia/bin/nvidia-smi -L; sleep 300
                resources:
                  limits:
                    nvidia.com/gpu: 1
      

מחליפים את מה שכתוב בשדות הבאים:

  • SHARING_STRATEGY עם 'שיתוף זמן' כדי לבקש שיתוף זמן עבור ה-GPU.
  • CLIENTS_PER_GPU: מספר עומסי העבודה שישתמשו ב-GPU הזה. בדוגמה הזו, נשתמש ב-3.
  1. החלת המניפסט:

    kubectl apply -f gpu-timeshare.yaml
    
  2. בודקים שכל ה-Pods פועלים:

    kubectl get pods -l=app=cuda-simple
    
  3. כדי לראות את ה-UUID של ה-GPU, בודקים את היומנים של כל Pod:

    kubectl logs POD_NAME
    

    הפלט אמור להיראות כך:

    GPU 0: Tesla V100-SXM2-16GB (UUID: GPU-0771302b-eb3a-6756-7a23-0adcae8efd47)
    
  4. אם לצמתים שלכם מצורף GPU פיזי אחד, צריך לבדוק ביומנים אם יש עוד Pod באותו צומת כדי לוודא שמזהה ה-UUID של ה-GPU זהה:

    kubectl logs POD2_NAME
    

    הפלט אמור להיראות כך:

    GPU 0: Tesla V100-SXM2-16GB (UUID: GPU-0771302b-eb3a-6756-7a23-0adcae8efd47)
    

שימוש בשיתוף זמן של GPU עם מעבדי GPU מרובי-מופעים

אדמינים של פלטפורמות יכולים לשלב בין כמה תכונות של GKE GPU. שיתוף זמן של GPU פועל עם יחידות GPU מרובות מופעים, שמחלקות GPU פיזי יחיד לעד שבעה חלקים. המחיצות האלה מבודדות זו מזו. אפשר להגדיר שיתוף זמן של GPU לכל מחיצה של GPU עם כמה מופעים במקביל.

לדוגמה, אם מגדירים את gpu-partition-size ל-1g.5gb, ה-GPU הבסיסי יפוצל לשבע מחיצות. אם מגדירים גם את max-shared-clients-per-gpu ל-3, כל מחיצה תתמוך בעד שלושה קונטיינרים, כך שיהיו עד 21 מכשירים לשיתוף זמן ב-GPU שזמינים להקצאה ב-GPU הפיזי הזה. כדי להבין איך gpu-partition-size מומר למחיצות בפועל, אפשר לעיין במאמר בנושא מחיצות GPU מרובות מופעים.

כדי ליצור אשכול GPU עם כמה מופעים במקביל שמופעל בו שיתוף זמן של GPU, מריצים את הפקודה הבאה:

טייס אוטומטי

ב-Autopilot, אפשר להשתמש בשיתוף זמן של GPU וב-GPU עם כמה מופעים בו-זמנית באמצעות שני סוגי בוררי הצמתים.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cuda-simple
spec:
  replicas: 7
  selector:
    matchLabels:
      app: cuda-simple
  template:
    metadata:
      labels:
        app: cuda-simple
    spec:
      nodeSelector:
        cloud.google.com/gke-gpu-partition-size: 1g.5gb
        cloud.google.com/gke-gpu-sharing-strategy: time-sharing
        cloud.google.com/gke-max-shared-clients-per-gpu: "3"
        cloud.google.com/gke-accelerator: nvidia-tesla-a100
        cloud.google.com/gke-accelerator-count: "1"
      containers:
      - name: cuda-simple
        image: nvidia/cuda:11.0.3-base-ubi7
        command:
        - bash
        - -c
        - |
          /usr/local/nvidia/bin/nvidia-smi -L; sleep 300
        resources:
          limits:
            nvidia.com/gpu: 1

רגילה

ב-Standard, צריך ליצור אשכול עם כמה מופעים במקביל שמשתפים את זמן השימוש ב-GPU, על ידי הרצת הפקודה הבאה:

gcloud container node-pools create NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --machine-type=MACHINE_TYPE \
    --accelerator=type=nvidia-tesla-a100,count=GPU_QUANTITY,gpu-partition-size=PARTITION_SIZE,gpu-sharing-strategy=time-sharing,max-shared-clients-per-gpu=CLIENTS_PER_GPU,gpu-driver-version=DRIVER_VERSION

מחליפים את PARTITION_SIZE בגודל המחיצה של ה-GPU עם כמה מופעים במקביל שרוצים, למשל 1g.5gb.

מגבלות

  • בשיתוף זמן של GPU,‏ GKE אוכף בידוד של מרחב כתובות, בידוד של ביצועים ובידוד של שגיאות בין קונטיינרים שמשתפים GPU פיזי. עם זאת, מגבלות הזיכרון לא נאכפות במעבדי GPU. כדי להימנע מבעיות של חוסר זיכרון (OOM), צריך להגדיר מגבלות של זיכרון GPU בעומסי העבודה. כדי למנוע בעיות אבטחה, כדאי לפרוס רק עומסי עבודה שנמצאים באותו גבול אמון לשיתוף זמן GPU.
  • כדי למנוע התנהגות לא צפויה במהלך הקצאת הקיבולת, יכול להיות ש-GKE ידחה בקשות מסוימות לשיתוף זמן השימוש ב-GPU. פרטים נוספים זמינים במאמר בנושא בקשות ל-GPU לשיתוף זמן של GPU.
  • המספר המקסימלי של מאגרי תגים שיכולים להשתמש בשיתוף זמן במעבד גרפי פיזי יחיד הוא 48. כשמתכננים את ההגדרה של שיתוף זמן השימוש ב-GPU, כדאי להתחשב בצרכי המשאבים של עומסי העבודה ובקיבולת של מעבדי ה-GPU הפיזיים הבסיסיים, כדי לשפר את הביצועים ואת מהירות התגובה.

המאמרים הבאים