הפעלת עומסי עבודה סובלניים לתקלות בעלויות נמוכות יותר ב-Spot Pods

בדף הזה מוסבר איך להריץ עומסי עבודה עמידים בכשלים בעלויות נמוכות יותר, באמצעות פודים של Spot באשכולות Autopilot של Google Kubernetes Engine ‏ (GKE).

סקירה כללית

באשכולות GKE Autopilot, ‏ Spot Pods הם Pods שפועלים בצמתים שמגובים על ידי VM במודל Spot ב-Compute Engine. המחיר של Spot Pods נמוך יותר מזה של Pods רגילים ב-Autopilot, אבל מערכת GKE יכולה להוציא אותם מהשימוש בכל פעם שנדרשים משאבי מחשוב להפעלת Pods רגילים.

פודים מסוג Spot מתאימים להרצת עומסי עבודה ללא שמירת מצב, באצווה או עמידים בכשלים, בעלויות נמוכות יותר בהשוואה להרצת עומסי העבודה האלה כפודים רגילים. כדי להשתמש ב-Spot Pods באשכולות של Autopilot, צריך לשנות את המניפסט עם מפרט ה-Pod כדי לבקש Spot Pods.

אפשר להריץ Spot Pods בכיתת המחשוב הכללית שמוגדרת כברירת מחדל ב-Autopilot, וגם בכיתות מחשוב ייעודיות שעומדות בדרישות חומרה ספציפיות. מידע על סוגי המחשוב האלה זמין במאמר בנושא סוגי מחשוב ב-Autopilot.

למידע נוסף על התמחור של Pods מסוג Spot באשכולות Autopilot, ראו התמחור של Google Kubernetes Engine.

‫Spot Pods לא נכללים בהסכם רמת השירות של Autopilot.

יתרונות

השימוש ב-Spot Pods באשכולות Autopilot מספק את היתרונות הבאים:

  • מחיר נמוך יותר מאשר הפעלת אותם עומסי עבודה ב-Pods רגילים של Autopilot.
  • מערכת GKE מנהלת באופן אוטומטי את ההתאמה האוטומטית לעומס (automatic scaling) ואת התזמון.
  • ‫GKE מסמן באופן אוטומטי צמתים שמריצים Spot Pods, כדי להבטיח ש-Pods רגילים, כמו עומסי העבודה הקריטיים שלכם, לא יתוזמנו בצמתים האלה. פריסות שמשתמשות ב-Spot Pods מתעדכנות אוטומטית עם toleration תואם.

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

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

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

בקשה לשימוש ב-Spot Pods בעומסי העבודה של Autopilot

כדי לבקש שה-Pods יפעלו כ-Spot Pods, משתמשים בתווית cloud.google.com/gke-spot=true ב-nodeSelector או ב-node affinity במפרט ה-Pod. ‫GKE מקצה אוטומטית צמתים שיכולים להריץ Spot Pods.

אפשר לפנות ולסיים פודים של Spot בכל שלב, למשל אם משאבי המחשוב נדרשים במקום אחר ב- Google Cloud. כשמתרחשת סיום, אפשר להגדיר את השדה terminationGracePeriodSeconds כדי ש-Spot Pods בצומת שמסיים את הפעולה יבקשו תקופת חסד של עד 15 שניות לפני הסיום. הבקשה מאושרת על בסיס מיטב המאמצים.

תקופת החסד המקסימלית שניתנת ל-Spot Pods במהלך הפקעה היא 15 שניות. בקשה של יותר מ-15 שניות ב-terminationGracePeriodSeconds לא תאפשר יותר מ-15 שניות במהלך הקדימות. במקרה של פינוי, הפוד מקבל את האות SIGTERM, וצריך לבצע פעולות כדי להשבית אותו במהלך תקופת החסד.

ב-Autopilot, ‏ GKE גם מסמן אוטומטית את הצמתים שנוצרו להפעלת Spot Pods ומשנה את עומסי העבודה האלה עם הסבילות המתאימה. הכתם מונע תזמון של Pods רגילים בצמתים שמריצים Pods של Spot.

שימוש ב-nodeSelector כדי לדרוש פודים של Spot

אפשר להשתמש ב-nodeSelector כדי לחייב שימוש ב-Spot Pods בפריסה. מוסיפים את התווית cloud.google.com/gke-spot=true לפריסה, כמו בדוגמה הבאה:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    metadata:
      labels:
        app: pi
    spec:
      nodeSelector:
        cloud.google.com/gke-spot: "true"
      terminationGracePeriodSeconds: 15
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

שימוש בהעדפת צומת כדי לבקש Spot Pods

אפשר גם להשתמש בזיקה של צמתים כדי לבקש Spot Pods. התכונה 'זיקה לצומת' מספקת דרך יותר גמישה לבחירת צמתים להרצת עומסי העבודה. לדוגמה, אתם יכולים לשלב כמה קריטריונים לבחירה כדי לקבל שליטה מדויקת יותר על המיקום שבו ה-Pods פועלים. כשמשתמשים בהעדפת צומת כדי לבקש Spot Pods, אפשר לציין את סוג העדפת הצומת שרוצים להשתמש בה, באופן הבא:

  • ‫requiredDuringSchedulingIgnoredDuringExecution: חובה להשתמש ב-Spot Pods.
  • ‫preferredDuringSchedulingIgnoredDuringExecution: כדאי להשתמש ב-Spot Pods על בסיס המאמץ המרבי.

כדי להשתמש בהתאמה של צומת כדי לחייב שימוש ב-Spot Pods בפריסה, מוסיפים את הכלל nodeAffinity הבא למניפסט הפריסה:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    metadata:
      labels:
        app: pi
    spec:
      terminationGracePeriodSeconds: 15
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: cloud.google.com/gke-spot
                operator: In
                values:
                - "true"
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

הגשת בקשה ל-Spot Pods ככל האפשר

כדי להשתמש בהעדפת צומת כדי לבקש Spot Pods על בסיס מיטב המאמצים, משתמשים ב-preferredDuringSchedulingIgnoredDuringExecution. כשמבקשים להשתמש ב-Spot Pods על בסיס העדפה, מערכת GKE מתזמנת את ה-Pods לפי הסדר הבא:

  1. צמתים קיימים שיכולים להריץ פודים של Spot, עם קיבולת זמינה שניתן להקצות.
  2. צמתים רגילים קיימים שיש להם קיבולת זמינה להקצאה.
  3. צמתים חדשים שיכולים להריץ פודים של Spot, אם משאבי המחשוב זמינים.
  4. צמתים סטנדרטיים חדשים.

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

בקשות ל-Pods זמניים שניתנים להפסקה

אשכולות Autopilot תומכים בבקשות לפודים (Pods) שניתנים להפסקה לפני הזמן באמצעות הבורר cloud.google.com/gke-preemptible. ה-Pods שמשתמשים בסלקטור הזה עוברים אוטומטית ל-Spot Pods, והסלקטור משתנה ל-cloud.google.com/gke-spot.

חיפוש ומחיקה של פודים שהשימוש בהם הופסק

במהלך סגירה מסודרת של Pod, ‏ kubelet מקצה סטטוס Failed וסיבה Shutdown ל-Pods שנסגרו. כשמספר ה-Pods שהסתיימו מגיע לסף של 1,000, מנגנון איסוף הזבל מנקה את ה-Pods. אפשר גם למחוק ידנית את ה-Pods של הכיבוי באמצעות הפקודה הבאה:

kubectl get pods --all-namespaces | grep -i shutdown | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n

הפסקת השימוש ב-Spot Pods בעומסי עבודה

אם יש לכם Spot Pods קיימים שאתם רוצים לעדכן כדי שיפעלו כ-Pods רגילים, אתם יכולים להשתמש באחת מהשיטות הבאות:

  • ליצור מחדש את עומס העבודה: מוחקים את הפריסה, מסירים את השורות במניפסט שבוחרות Spot Pods, ואז מחילים את מניפסט הפריסה המעודכן על האשכול.
  • עריכת עומס העבודה: עריכת מפרט הפריסה בזמן שה-Pods פועלים באשכול.

בשתי השיטות האלה, יכול להיות שיהיו שיבושים קלים בעומס העבודה.

יצירה מחדש של עומס העבודה

בשלבים הבאים מוסבר איך למחוק את ה-Deployment הקיים ולהחיל מניפסט עדכונים על האשכול. אפשר להשתמש בשלבים האלה גם לסוגים אחרים של עומסי עבודה ב-Kubernetes, כמו Jobs.

כדי לוודא ש-GKE יציב את ה-Pods המעודכנים בסוג הנכון של צומת, צריך לייצא את המצב הקיים של עומס העבודה משרת ה-API של Kubernetes לקובץ ולערוך את הקובץ הזה.

  1. כותבים את המפרט של עומס העבודה לקובץ YAML:

    kubectl get deployment DEPLOYMENT_NAME -o yaml > DEPLOYMENT_NAME-on-demand.yaml
    

    מחליפים את DEPLOYMENT_NAME בשם הפריסה. עבור סוגים אחרים של עומסי עבודה, כמו Jobs או Pods, משתמשים בשם המשאב המתאים בפקודה kubectl get, כמו kubectl get pod.

  2. פותחים את קובץ ה-YAML בכלי לעריכת טקסט:

    vi DEPLOYMENT_NAME-on-demand.yaml
    
  3. מסירים מהקובץ את nodeSelector ל-Spot Pods ואת ה-toleration ש-GKE הוסיף ל-Spot Pods:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
      # lines omitted for clarity
    spec:
      progressDeadlineSeconds: 600
      replicas: 6
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          pod: nginx-pod
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
        # lines omitted for clarity
        spec:
          containers:
          - image: nginx
            imagePullPolicy: Always
            name: web-server
            resources:
              limits:
                ephemeral-storage: 1Gi
              requests:
                cpu: 500m
                ephemeral-storage: 1Gi
                memory: 2Gi
            securityContext:
              capabilities:
                drop:
                - NET_RAW
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          nodeSelector:
            cloud.google.com/gke-spot: "true"
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext:
            seccompProfile:
              type: RuntimeDefault
          terminationGracePeriodSeconds: 15
          tolerations:
          - effect: NoSchedule
            key: kubernetes.io/arch
            operator: Equal
            value: amd64
          - effect: NoSchedule
            key: cloud.google.com/gke-spot
            operator: Equal
            value: "true"
    status:
      #lines omitted for clarity
    

    כדי לציין ל-GKE שהפודים צריכים לפעול בצמתים על פי דרישה ולא בצמתים מסוג Spot, צריך להסיר גם את ה-toleration וגם את ה-nodeSelector.

  4. שומרים את מניפסט העדכונים.

  5. מוחקים את מניפסט הפריסה ומחילים אותו מחדש על האשכול:

    kubectl replace -f DEPLOYMENT_NAME-on-demand.yaml
    

    משך הפעולה הזו תלוי במספר ה-Pods ש-GKE צריך להפסיק ולנקות.

עריכת עומס העבודה במקום

בשלבים הבאים מוסבר איך לערוך Deployment (פריסה) פעיל במקום כדי לציין ל-GKE שה-Pods צריכים לפעול בצמתים על פי דרישה. אפשר להשתמש בשלבים האלה גם לסוגים אחרים של עומסי עבודה ב-Kubernetes, כמו Jobs.

צריך לערוך את אובייקט עומס העבודה ב-Kubernetes API כי GKE מוסיף אוטומטית סבילות ל-Spot Pods למפרט עומס העבודה במהלך קבלת עומס העבודה.

  1. פותחים את מניפסט עומס העבודה לעריכה בכלי לעריכת טקסט:

    kubectl edit deployment/DEPLOYMENT_NAME
    

    מחליפים את DEPLOYMENT_NAME בשם הפריסה. לסוגים אחרים של עומסי עבודה, כמו משימות או Pods, משתמשים בשם המשאב המתאים בפקודת kubectl edit, כמו kubectl edit pod/POD_NAME.

  2. בכלי לעריכת טקסט, מוחקים את בורר הצמתים או את כלל ההתאמה לצמתים של Spot Pods ואת ההרשאה ש-GKE הוסיף למניפסט, כמו בדוגמה הבאה:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-deployment
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          type: dev
      template:
        metadata:
          labels:
            type: dev
        spec:
          nodeSelector:
            cloud.google.com/gke-spot: "true"
          tolerations:
          - effect: NoSchedule
            key: cloud.google.com/gke-spot
            operator: Equal
            value: "true"
          containers:
          - name: nginx
            image: nginx
            ports:
            - containerPort: 80
    
  3. שומרים את מניפסט העדכונים המעודכן וסוגרים את הכלי לעריכת טקסט. הגדרת האובייקט המעודכנת מציינת ל-GKE שה-Pods צריכים לפעול בצמתים על פי דרישה. ‫GKE יוצר מחדש את ה-Pods כדי למקם אותם בצמתים חדשים על פי דרישה.

איך מוודאים שעומסי העבודה פועלים בצמתים על פי דרישה

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

  • בודקים את עומס העבודה:

    kubectl describe deployment DEPLOYMENT_NAME
    

בפלט לא מופיעה רשומה של cloud.google.com/gke-spot בשדה spec.tolerations.

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