הקצאה ושימוש באחסון בלוקים גולמיים שמגובה על ידי כונן SSD מקומי

בדף הזה מוסבר איך להקצות אחסון בכונני SSD מקומיים באשכולות של Google Kubernetes Engine ‏ (GKE), ואיך להגדיר עומסי עבודה לצריכת נתונים מאחסון בלוקים גולמיים שמגובה בכונני SSD מקומיים ומחובר לצמתים באשכול.

השימוש באפשרות הזו של SSD מקומי נותן לכם יותר שליטה באחסון הבסיסי, ומאפשר לכם ליצור מטמון משלכם ברמת הצומת בשביל Pods, כדי לשפר את הביצועים של האפליקציות. אפשר גם להתאים אישית את האפשרות הזו על ידי התקנה של מערכת קבצים בדיסקים של Local SSD, באמצעות הפעלה של DaemonSet כדי להגדיר RAID ולפרמט דיסקים לפי הצורך.

למידע נוסף על תמיכה ב-SSD מקומי לגישה לבלוקים גולמיים ב-GKE, קראו את המאמר מידע על כונני SSD מקומיים.

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

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

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

יצירת אשכול או מאגר צמתים עם אחסון בלוקים גולמיים שמגובה ב-SSD מקומי

משתמשים ב-CLI של gcloud עם האפשרות --local-nvme-ssd-block כדי ליצור אשכול עם אחסון בלוקים גולמיים שמגובה ב-SSD מקומי.

הפקודה של ה-CLI של gcloud שאתם מריצים כדי ליצור את האשכול או את מאגר הצמתים תלויה בדור של סדרת המכונות שאליו שייך סוג המכונה שבה אתם משתמשים. לדוגמה, סוגי המכונות N1 ו-N2 שייכים לסדרת מכונות מהדור הראשון והשני, בהתאמה, וסוגי המכונות C3 שייכים לסדרת מכונות מהדור השלישי.

יצירת אשכול עם Local SSD

דור ראשון או שני

אם אתם משתמשים בסוג מכונה מסדרת מכונות מהדור הראשון או השני, אתם יוצרים את האשכול על ידי ציון האפשרות --local-nvme-ssd-block count=NUMBER_OF_DISKS. האפשרות הזו מציינת את מספר דיסקי ה-SSD המקומיים שצריך לצרף לכל צומת. המספר המקסימלי משתנה בהתאם לסוג המכונה ולאזור.

כדי ליצור אשכול:

gcloud container clusters create CLUSTER_NAME \
    --local-nvme-ssd-block count=NUMBER_OF_DISKS \
    --machine-type=MACHINE_TYPE \
    --release-channel CHANNEL_NAME

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

  • ‫CLUSTER_NAME: שם האשכול.
  • ‫NUMBER_OF_DISKS: מספר כונני ה-SSD המקומיים שיוקצו בכל צומת. מספר הדיסקים המקסימלי משתנה בהתאם לסוג המכונה ולאזור.
  • ‫MACHINE_TYPE: סוג המכונה מהדור הראשון או השני שבה רוצים להשתמש. חובה לציין את השדה הזה, כי אי אפשר להשתמש בכונני SSD מקומיים עם סוג ברירת המחדל e2-medium.
  • CHANNEL_NAME: ערוץ הפצה שכולל גרסאות GKE חדשות יותר מ-1.25.3-gke.1800.

דור שלישי או רביעי

אם אתם משתמשים בסוג מכונה מסדרת מכונות מהדור השלישי או הרביעי, השתמשו באפשרות --local-nvme-ssd-block, בלי שדה ספירה, כדי ליצור אשכול. ‫GKE מקצה באופן אוטומטי קיבולת של Local SSD לאשכול, על סמך צורת ה-VM. המספר המקסימלי משתנה בהתאם לסוג המכונה ולאזור.

gcloud container clusters create CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --cluster-version CLUSTER_VERSION \
    --local-nvme-ssd-block

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

  • ‫CLUSTER_NAME: שם האשכול.
  • ‫MACHINE_TYPE: סוג המכונה שבה משתמשים מסדרת מכונות מהדור השלישי או הרביעי.
  • ‫CLUSTER_VERSION: גרסת אשכול GKE שתומכת ב-SSD מקומי בסוגי מכונות מסדרת מכונות מהדור השלישי או הרביעי.

יצירת מאגר צמתים עם Local SSD

דור ראשון או שני

כדי ליצור מאגר צמתים שמשתמש בדיסקים מסוג Local SSD לגישה לבלוקים גולמיים, מריצים את הפקודה הבאה:

gcloud container node-pools create POOL_NAME \
    --cluster=CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --local-nvme-ssd-block count=NUMBER_OF_DISKS

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

  • ‫POOL_NAME: השם של מאגר הצמתים החדש.
  • ‫CLUSTER_NAME: שם האשכול.
  • ‫MACHINE_TYPE: סוג המכונה מהדור הראשון או השני שבה רוצים להשתמש. חובה לציין את השדה הזה, כי אי אפשר להשתמש ב-SSD מקומי עם סוג ברירת המחדל e2-medium.
  • ‫NUMBER_OF_DISKS: מספר כונני ה-SSD המקומיים שיוקצו בכל צומת. מספר הדיסקים המקסימלי משתנה בהתאם לסוג המכונה ולאזור.

דור שלישי או רביעי

אם אתם משתמשים בסוג מכונה מסדרת מכונות מהדור השלישי או הרביעי, השתמשו באפשרות --local-nvme-ssd-block, בלי שדה ספירה, כדי ליצור אשכול:

gcloud container node-pools create POOL_NAME \
    --cluster=CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --node-version NODE_VERSION \
    --local-nvme-ssd-block

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

  • ‫POOL_NAME: השם של מאגר הצמתים החדש.
  • ‫CLUSTER_NAME: שם האשכול.
  • ‫MACHINE_TYPE: סוג המכונה שבה רוצים להשתמש, מסוגי המכונות מהדור השלישי או הרביעי.
  • ‫NODE_VERSION: גרסה של מאגר צמתים ב-GKE שתומכת ב-SSD מקומי בסוגי מכונות מסדרת מכונות מהדור השלישי או הרביעי.

הצמתים במאגר הצמתים נוצרים עם התווית cloud.google.com/gke-local-nvme-ssd=true. כדי לאמת את התוויות, מריצים את הפקודה הבאה:

kubectl describe node NODE_NAME

לכל כונן SSD מקומי שמחובר למאגר הצמתים, מערכת ההפעלה המארחת יוצרת קישור סימבולי (symlink) כדי לגשת לדיסק בתיקייה סידורית, וקישור סימבולי עם מזהה ייחודי אוניברסלי (UUID). לדוגמה, אם יוצרים מאגר צמתים עם שלושה כונני SSD מקומיים באמצעות האפשרות --local-nvme-ssd-block, מערכת ההפעלה המארחת יוצרת את הקישורים הסימבוליים הבאים לדיסקים:

  • /dev/disk/by-id/google-local-ssd-block0
  • /dev/disk/by-id/google-local-ssd-block1
  • /dev/disk/by-id/google-local-ssd-block2

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

  • /dev/disk/by-uuid/google-local-ssds-nvme-block/local-ssd-GENERATED_UUID1
  • /dev/disk/by-uuid/google-local-ssds-nvme-block/local-ssd-GENERATED_UUID2
  • /dev/disk/by-uuid/google-local-ssds-nvme-block/local-ssd-GENERATED_UUID3

כך אפשר לוודא שהגישה לדיסקים תתבצע באמצעות מזהה ייחודי.

גישה לנפחי SSD מקומיים

בדוגמה הבאה אפשר לראות איך ניגשים לאחסון בלוקים גולמיים שמגובה ב-SSD מקומי.

נפחי אחסון מתמיד מקומיים

אפשר לטעון אמצעי אחסון מסוג Local SSD כ-Pods באמצעות PersistentVolumes.

אפשר ליצור PersistentVolumes מ-Local SSD על ידי יצירה ידנית של PersistentVolume, או על ידי הפעלת הקצאה סטטית של נפח אחסון מקומי.

המגבלות של PersistentVolumes מקומיים

  • אובייקטים מקומיים של PersistentVolume לא נמחקים באופן אוטומטי כשצומת נמחק, משודרג, מתוקן או מצומצם אנכית בהתאם לעומס (scale down). מומלץ לסרוק ולמחוק מדי פעם אובייקטים ישנים של Local PersistentVolume שמשויכים לצמתים שנמחקו.

יצירה ידנית של PersistentVolume

אתם יכולים ליצור באופן ידני PersistentVolume לכל כונן SSD מקומי בכל צומת באשכול.

משתמשים בשדה nodeAffinity באובייקט PersistentVolume כדי להפנות ל-SSD מקומי בצומת ספציפי. בדוגמה הבאה מוצג המפרט של PersistentVolume ל-SSD מקומי בצמתים שבהם פועלת מערכת ההפעלה Linux:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: "example-local-pv"
spec:
  capacity:
    storage: 375Gi
  accessModes:
  - "ReadWriteOnce"
  persistentVolumeReclaimPolicy: "Retain"
  storageClassName: "local-storage"
  local:
    path: "/mnt/disks/ssd0"
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: "kubernetes.io/hostname"
          operator: "In"
          values:
          - "gke-test-cluster-default-pool-926ddf80-f166"

בדוגמה הזו, דיסקי ה-SSD המקומיים מוגדרים ידנית ל-RAID ומפורמטים, ואז מותקנים ב-/mnt/disks/ssd0 בצומת gke-test-cluster-default-pool-926ddf80-f166. השדה nodeAffinity משמש להקצאת עומסי עבודה לצמתים עם כונני SSD מקומיים שמוגדרים ידנית ל-RAID. אם יש לכם רק צומת אחד באשכול או אם הגדרתם RAID לכל הצמתים, אין צורך בשדה nodeAffinity.

המפרט התואם של PersistentVolumeClaim נראה כך:

  kind: PersistentVolumeClaim
  apiVersion: v1
  metadata:
    name: ssd-local-claim
  spec:
    accessModes:
    - ReadWriteOnce
    storageClassName: local-storage
    resources:
      requests:
        storage: 37Gi

אם מוחקים את ה-PersistentVolume, צריך למחוק ידנית את הנתונים מהדיסק.

הפעלת המקצה הסטטי של נפח האחסון המקומי

אתם יכולים ליצור PersistentVolumes ל-SSD מקומי באופן אוטומטי באמצעות מקצה סטטי של נפח אחסון מקומי. המקצה הוא DaemonSet שמנהל את הדיסקים המקומיים מסוג SSD בכל צומת, יוצר ומוחק את ה-PersistentVolumes שלהם ומנקה את הנתונים בדיסקים המקומיים מסוג SSD כשה-PersistentVolume משוחרר.

כדי להריץ את מקצה הנפחים הסטטי המקומי:

  1. משתמשים ב-DaemonSet כדי להגדיר את ה-RAID ולפרמט את הדיסקים:

    1. מורידים את המפרט של gke-daemonset-raid-disks.yaml.
    2. פורסים את ה-DaemonSet של דיסקי ה-RAID. ה-DaemonSet מגדיר מערך RAID 0 בכל דיסקי ה-SSD המקומיים ומפרמט את המכשיר למערכת קבצים ext4.

      kubectl create -f gke-daemonset-raid-disks.yaml
      
  2. מורידים את המפרט של gke-nvme-ssd-block-raid.yaml ומשנים את שדות מרחב השמות של המפרט לפי הצורך.

    המפרט כולל את המשאבים הבאים:

    • ServiceAccount של המקצה
    • ‫ClusterRole ו-ClusterRoleBindings להרשאות:
      • יצירה ומחיקה של אובייקטים מסוג PersistentVolume
      • אחזור אובייקטים של צומת
    • ‫ConfigMap עם הגדרות של מקצה משאבים ל-GKE
    • ‫DaemonSet להרצת מקצה המשאבים
  3. פורסים את ה-provisioner:

    kubectl create -f gke-nvme-ssd-block-raid.yaml
    

    אחרי שההקצאה פועלת בהצלחה, היא יוצרת אובייקט PersistentVolume למכשיר ה-SSD המקומי של RAID באשכול.

  4. שומרים את המניפסט הבא של PersistentVolumeClaim בתור provisioner-pvc-example.yaml:

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: PVC_NAME
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 50Gi
      storageClassName: nvme-ssd-block
    

    מחליפים את PVC_NAME בשם של PersistentVolumeClaim.

  5. יוצרים את ה-PersistentVolumeClaim:

    kubectl create -f provisioner-pvc-example.yaml
    
  6. שומרים את המניפסט הבא של Pod בשם provisioner-pod-example.yaml:

    apiVersion: v1
    kind: Pod
    metadata:
      name: POD_NAME
    spec:
      containers:
      - name: "shell"
        image: "ubuntu:14.04"
        command: ["/bin/sh", "-c"]
        args: ["echo 'hello world' > /cache/test.txt && sleep 1 && cat /cache/test.txt && sleep 3600"]
        volumeMounts:
        - mountPath: /cache
          name: local-ssd-storage
      volumes:
      - name: local-ssd-storage
        persistentVolumeClaim:
          claimName: PVC_NAME
    

    מחליפים את POD_NAME בשם של ה-Pod.

  7. יוצרים את ה-Pod:

    kubectl create -f provisioner-pod-example.yaml
    

הפעלת קישור מושהה של אמצעי אחסון

כדי לשפר את התזמון, מומלץ גם ליצור StorageClass עם volumeBindingMode: WaitForFirstConsumer. הפעולה הזו מעכבת את הקישור של PersistentVolumeClaim עד לתזמון ה-Pod, כדי שייבחר Local SSD מצומת מתאים שיכול להריץ את ה-Pod. התזמון המשופר הזה מביא בחשבון בקשות למעבד (CPU) ולזיכרון של Pod, שיוך (affinity) של צומת, שיוך (affinity) ואי-שיוך (anti-affinity) של Pod, ובקשות מרובות של PersistentVolumeClaim, וגם אילו צמתים כוללים כונני SSD מקומיים זמינים, כשבוחרים צומת ל-Pod שניתן להפעלה.

בדוגמה הזו נעשה שימוש במצב קישור נפח מושהה:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: "local-nvme"
provisioner: "kubernetes.io/no-provisioner"
volumeBindingMode: "WaitForFirstConsumer"

כדי ליצור StorageClass עם קישור מושהה, שומרים את המניפסט של ה-YAML בקובץ מקומי ומחילים אותו על האשכול באמצעות הפקודה הבאה:

kubectl apply -f filename

פתרון בעיות

הוראות לפתרון בעיות מפורטות במאמר פתרון בעיות באחסון ב-GKE.

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