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

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

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

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

דרישות

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

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

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

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

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

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

  1. הפעלת שיתוף זמן של GPU באשכול GKE.
  2. התקנת מנהלי התקנים של NVIDIA GPU (אם צריך).
  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, שחייב להיות פלטפורמת GPU של NVIDIA, כמו 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, שחייב להיות פלטפורמת GPU של NVIDIA, כמו 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 שמגדיר את מנהלי ההתקנים.

להוראות, ראו התקנת מנהלי התקנים של NVIDIA GPU.

אם אתם מתכננים להשתמש בהקצאת צמתים אוטומטית (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 ומספרcount ה-GPU הפיזיים לצירוף לצומת היה 1. דוגמה נוספת: אם 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: מספר המעבדים הגרפיים הפיזיים שרוצים לצרף לצומת. בדוגמה הזו, משתמשים ב-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 הפיזיים הבסיסיים כדי לשפר את הביצועים ואת מהירות התגובה.
  • אי אפשר להפעיל שיתוף זמן עבור סוגי מכונות G4 שיש להן פחות מ-GPU אחד.

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