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

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

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

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

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

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

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

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

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

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

יצירת אשכול עם 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 מקצה באופן אוטומטי קיבולת של 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 מקומי בסוגי מכונות מסדרת מכונות מהדור השלישי או הרביעי.

יצירת מאגר צמתים עם SSD מקומי

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

כדי ליצור מאגר צמתים שמשתמש בדיסקים מקומיים של 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 מקומי.

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

אפשר לטעון כרכים של SSD מקומיים כ-Pods באמצעות PersistentVolumes.

אפשר ליצור PersistentVolumes מ-Local SSD על ידי יצירה ידנית של PersistentVolume, או על ידי הפעלת local volume static provisioner.

מגבלות של נפחי אחסון מתמיד מקומיים

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

יצירה ידנית של נפח אחסון מתמיד

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

משתמשים בשדה nodeAffinity באובייקט PersistentVolume כדי להפנות אל Local 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.

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

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

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

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

אפשר ליצור באופן אוטומטי PersistentVolumes עבור Local SSD באמצעות כלי ההקצאה הסטטית של נפח אחסון מקומי. ה-provisioner הוא 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
    • קבוצת דימון (Daemon) להרצת ה-provisioner
  3. פורסים את הכלי לניהול הקצאות:

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

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

  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. יוצרים את הפוד:

    kubectl create -f provisioner-pod-example.yaml
    

הפעלה של קישור מושהה של עוצמת הקול

כדי לשפר את התזמון, מומלץ ליצור גם StorageClass עם volumeBindingMode: WaitForFirstConsumer. הפעולה הזו מעכבת את הקישור של PersistentVolumeClaim עד לתזמון של ה-Pod, כדי שמערכת תבחר SSD מקומי מצומת מתאים שיוכל להריץ את ה-Pod. התנהגות התזמון המשופרת הזו מתחשבת בבקשות של מעבד (CPU) וזיכרון של Pod, בקרבה של צומת, בקרבה ובאנטי-קרבה של 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.

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