פתרון בעיות באשכולות של Autopilot

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

בדף הזה אפשר לאבחן ולפתור בעיות נפוצות שקשורות ספציפית לאשכולות של Autopilot. תוכלו למצוא הנחיות לפתרון בעיות ביצירת אשכולות שמונעות הקצאת משאבים לאשכול, בעיות בהרחבת משאבים כמו שגיאות out of resources ובעיות ספציפיות לעומסי עבודה כמו שגיאות באחסון זמני או Pods שנתקעו במצב Pending.

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

בעיות באשכול

אי אפשר ליצור אשכול: לא נרשמו צמתים

הבעיה הבאה מתרחשת כשמנסים ליצור אשכול Autopilot עם חשבון שירות IAM שמושבת או שאין לו את ההרשאות הנדרשות. יצירת האשכול נכשלת עם הודעת השגיאה הבאה:

All cluster resources were brought up, but: only 0 nodes out of 2 have registered.

כדי לפתור את הבעיה:

  1. בודקים אם חשבון השירות שמוגדר כברירת מחדל ב-Compute Engine או חשבון השירות המותאם אישית ב-IAM שרוצים להשתמש בו מושבתים:

    gcloud iam service-accounts describe SERVICE_ACCOUNT
    

    מחליפים את SERVICE_ACCOUNT בכתובת האימייל בחשבון השירות, לדוגמה my-iam-account@my-first-project.s3ns.iam.gserviceaccount.com.

    אם חשבון השירות מושבת, הפלט דומה לזה:

    disabled: true
    displayName: my-service-account
    email: my-service-account@my-project.s3ns.iam.gserviceaccount.com
    ...
    
  2. אם חשבון השירות מושבת, צריך להפעיל אותו:

    gcloud iam service-accounts enable SERVICE_ACCOUNT
    

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

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member "serviceAccount:SERVICE_ACCOUNT" \
    --role roles/container.defaultNodeServiceAccount

מרחב שמות נתקע במצב Terminating (הפסקת פעולה) כשיש באשכול 0 צמתים

הבעיה הבאה מתרחשת כשמוחקים מרחב שמות באשכול אחרי שהאשכול מצטמצם לאפס צמתים. רכיב metrics-server לא יכול לקבל את הבקשה למחיקת מרחב השמות כי יש לו אפס עותקים.

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

kubectl describe ns/NAMESPACE_NAME

מחליפים את NAMESPACE_NAME בשם של מרחב השמות.

הפלט שיתקבל:

Discovery failed for some groups, 1 failing: unable to retrieve the complete
list of server APIs: metrics.k8s.io/v1beta1: the server is currently unable to
handle the request

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

בעיות בהתאמת הגודל

הגדלת הקיבולת של הצומת נכשלה: יש סיכון שה-Pod לא יתוזמן

הבעיה הבאה מתרחשת כשרישום ביומן של יציאה טורית מושבת בCloud de Confiance by S3NS פרויקט. באשכולות GKE Autopilot נדרש רישום ביומן של יציאה טורית כדי לנפות באגים בבעיות בצמתים בצורה יעילה. אם רישום ביומן של יציאה טורית מושבת, Autopilot לא יכול להקצות צמתים להרצת עומסי העבודה.

הודעת השגיאה ביומן האירועים של Kubernetes דומה להודעה הבאה:

LAST SEEN   TYPE      REASON          OBJECT                          MESSAGE
12s         Warning   FailedScaleUp   pod/pod-test-5b97f7c978-h9lvl   Node scale up in zones associated with this pod failed: Internal error. Pod is at risk of not being scheduled

יכול להיות שהרישום ביומן של היציאה הטורית מושבת ברמת הארגון באמצעות מדיניות ארגונית שמאלצת את האילוץ compute.disableSerialPortLogging. אפשר גם להשבית את הרישום ביומן ביציאה הטורית ברמת הפרויקט או ברמת המכונה הווירטואלית (VM).

כדי לפתור את הבעיה:

  1. צריך לבקש מהאדמין של מדיניות הארגון Cloud de Confiance by S3NS להסיר את האילוץ compute.disableSerialPortLogging בפרויקט עם אשכול Autopilot.
  2. אם אין לכם מדיניות ארגונית שמחייבת את האילוץ הזה, נסו להפעיל את הכתיבה ליומן של היציאה הטורית במטא-נתונים של הפרויקט. כדי לבצע את הפעולה הזו נדרשת הרשאת IAM‏ compute.projects.setCommonInstanceMetadata.

הגדלת הקיבולת של הצומת נכשלה: אין מספיק משאבים ב-GCE

הבעיה הבאה מתרחשת כשעומסי העבודה שלכם דורשים יותר משאבים מאלה שזמינים לשימוש באזור או בתחום של Compute Engine. יכול להיות שה-Pods יישארו במצב Pending.

  • בודקים את האירועים ב-Pod:

    kubectl events --for='pod/POD_NAME' --types=Warning
    

    מחליפים את RESOURCE_NAME בשם של משאב ב-Kubernetes בהמתנה. לדוגמה pod/example-pod.

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

    LAST SEEN         TYPE            REASON                  OBJECT                   Message
    19m               Warning         FailedScheduling        pod/example-pod          gke.io/optimize-utilization-scheduler  0/2 nodes are available: 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.
    14m               Warning         FailedScheduling        pod/example-pod          gke.io/optimize-utilization-scheduler  0/2 nodes are available: 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.
    12m (x2 over 18m) Warning         FailedScaleUp           cluster-autoscaler       Node scale up in zones us-central1-f associated with this pod failed: GCE out of resources. Pod is at risk of not being scheduled.
    34s (x3 over 17m) Warning         FailedScaleUp           cluster-autoscaler       Node scale up in zones us-central1-b associated with this pod failed: GCE out of resources. Pod is at risk of not being scheduled.
    

כדי לפתור את הבעיה, נסו את הפתרונות הבאים:

  • פריסת ה-Pod באזור או באזור אחר. אם ל-Pod יש הגבלה אזורית, כמו בורר טופולוגיה, צריך להסיר את ההגבלה אם אפשר. הוראות מפורטות מופיעות במאמר בנושא מיקום של פודים של GKE באזורים ספציפיים.
  • יוצרים אשכול באזור אחר ומנסים שוב לפרוס את האפליקציה.
  • אפשר לנסות להשתמש בסוג אחר של מכונת חישוב. בדרך כלל יש יותר משאבים זמינים בסוגי מכונות קטנים יותר ב-Compute Engine, שמשמשים כבסיס לסוגי מחשוב. לדוגמה, סוג המכונה שמוגדר כברירת מחדל ב-Autopilot הוא בעל הזמינות הגבוהה ביותר. רשימה של מחלקות מחשוב וסוגי המכונות התואמים מופיעה במאמר מתי כדאי להשתמש במחלקות מחשוב ספציפיות.
  • אם אתם מריצים עומסי עבודה של GPU, יכול להיות שה-GPU המבוקש לא יהיה זמין במיקום הצומת שלכם. נסו לפרוס את עומס העבודה במיקום אחר או לבקש סוג אחר של GPU.

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

הגדלת הקיבולת של הצמתים נכשלת: חריגה ממגבלת המשאבים של ה-Pod

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

הודעת השגיאה ביומנים דומה להודעה הבאה:

    "napFailureReasons": [
            {
              "messageId": "no.scale.up.nap.pod.zonal.resources.exceeded",
              ...

השגיאה הזו מתייחסת לאירוע noScaleUp, שבו הקצאת משאבים אוטומטית של צומת לא הקצתה אף קבוצת צמתים ל-Pod באזור.

אם נתקלתם בשגיאה הזו, כדאי לבדוק את הדברים הבאים:

בעיות בעומס העבודה

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

מערכת GKE לא תיצור Pod אם בקשות האחסון הזמני של ה-Pod חורגות מהמקסימום של 10GiB ב-Autopilot ב-GKE בגרסה 1.28.6-gke.1317000 ואילך.

כדי לאבחן את הבעיה הזו, צריך לתאר את בקרת עומס העבודה, כמו Deployment או Job:

kubectl describe CONTROLLER_TYPE/CONTROLLER_NAME

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

  • ‫CONTROLLER_TYPE: סוג בקר עומס העבודה, כמו replicaset או daemonset. רשימה של סוגי בקרי העומס מופיעה במאמר ניהול עומסי עבודה.
  • ‫CONTROLLER_NAME: השם של עומס העבודה התקוע.

אם ה-Pod לא נוצר כי הבקשה לאחסון זמני חורגת מהמקסימום, הפלט ייראה כך:

# lines omitted for clarity

Events:

{"[denied by autogke-pod-limit-constraints]":["Max ephemeral-storage requested by init containers for workload '' is higher than the Autopilot maximum of '10Gi'.","Total ephemeral-storage requested by containers for workload '' is higher than the Autopilot maximum of '10Gi'."]}

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

חלקים של פוד תקועים במצב 'בהמתנה'

יכול להיות ש-Pod ייתקע במצב Pending אם תבחרו צומת ספציפי לשימוש ב-Pod, אבל סכום בקשות המשאבים ב-Pod וב-DaemonSets שצריכים לפעול בצומת יעלה על הקיבולת המקסימלית שניתנת להקצאה של הצומת. יכול להיות שהסטטוס של ה-Pod יהיה Pending והוא יישאר לא מתוזמן.

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

אפשר גם לנסות לתזמן את DaemonSets לפני שתזמנו את הפודים הרגילים של עומס העבודה.

ביצועים לא אמינים של עומס עבודה באופן עקבי בצומת ספציפי

בגרסה 1.24 של GKE ואילך, אם עומסי העבודה בצומת מסוים חווים שיבושים, קריסות או התנהגות לא אמינה דומה באופן עקבי, אתם יכולים להודיע ל-GKE על הצומת הבעייתי באמצעות בידוד שלו באמצעות הפקודה הבאה:

kubectl drain NODE_NAME --ignore-daemonsets

מחליפים את NODE_NAME בשם של הצומת הבעייתי. אפשר להריץ את הפקודה kubectl get nodes כדי למצוא את שם הצומת.

‫GKE מבצע את הפעולות הבאות:

  • מפנה עומסי עבודה קיימים מהצומת ומפסיק את התזמון של עומסי עבודה בצומת הזה.
  • יצירה מחדש אוטומטית של עומסי עבודה שהוצאו מהזיכרון ומנוהלים על ידי בקר, כמו Deployment או StatefulSet, בצמתים אחרים.
  • מפסיק את כל עומסי העבודה שנותרו בצומת ומתקן או יוצר מחדש את הצומת לאורך זמן.
  • אם אתם משתמשים ב-Autopilot, ‏ GKE משבית ומחליף את הצומת באופן מיידי ומתעלם מכל תקציב הפרעות שהוגדר ל-Pod.

תזמון של פודים באשכולות ריקים נמשך יותר זמן מהצפוי

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

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

בודקים אם ה-Pods ממתינים לצמתים חדשים:

  1. תאר את הפודקאסט שלך שממתין לבדיקה:

    kubectl describe pod POD_NAME
    

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

  2. בודקים את הקטע Events בפלט. אם ה-Pod ממתין לצמתים חדשים, הפלט אמור להיראות כך:

    Events:
      Type     Reason            Age   From                                   Message
      ----     ------            ----  ----                                   -------
      Warning  FailedScheduling  11s   gke.io/optimize-utilization-scheduler  no nodes available to schedule pods
      Normal   TriggeredScaleUp  4s    cluster-autoscaler                     pod triggered scale-up: [{https://www.googleapis.com/compute/v1/projects/example-project/zones/example-zone/instanceGroups/gk3-example-cluster-pool-2-9293c6db-grp 0->1 (max: 1000)} {https://www.googleapis.com/compute/v1/projects/example-project/zones/example-zone/instanceGroups/gk3-example-cluster-pool-2-d99371e7-grp 0->1 (max: 1000)}]
    

    האירוע TriggeredScaleUp מציין שהאשכול מתרחב מאפס צמתים למספר הצמתים שנדרשים להפעלת עומס העבודה שפרסתם.

תזמון של System Pods באשכולות ריקים נכשל

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

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

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

  1. בודקים אם יש צמתים באשכול:

    kubectl get nodes
    

    הפלט שמתקבל הוא הבא, שמציין שלקלאסטר אין צמתים:

    No resources found
    
  2. בודקים את הסטטוס של ה-Pods במערכת:

    kubectl get pods --namespace=kube-system
    

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

    NAME                                                       READY   STATUS    RESTARTS   AGE
    antrea-controller-horizontal-autoscaler-6d97f7cf7c-ngfd2   0/1     Pending   0          9d
    egress-nat-controller-84bc985778-6jcwl                     0/1     Pending   0          9d
    event-exporter-gke-5c5b457d58-7njv7                        0/2     Pending   0          3d5h
    event-exporter-gke-6cd5c599c6-bn665                        0/2     Pending   0          9d
    konnectivity-agent-694b68fb7f-gws8j                        0/2     Pending   0          3d5h
    konnectivity-agent-7d659bf64d-lp4kt                        0/2     Pending   0          9d
    konnectivity-agent-7d659bf64d-rkrw2                        0/2     Pending   0          9d
    konnectivity-agent-autoscaler-5b6ff64fcd-wn7fw             0/1     Pending   0          9d
    konnectivity-agent-autoscaler-cc5bd5684-tgtwp              0/1     Pending   0          3d5h
    kube-dns-65ccc769cc-5q5q7                                  0/5     Pending   0          3d5h
    kube-dns-7f7cdb9b75-qkq4l                                  0/5     Pending   0          9d
    kube-dns-7f7cdb9b75-skrx4                                  0/5     Pending   0          9d
    kube-dns-autoscaler-6ffdbff798-vhvkg                       0/1     Pending   0          9d
    kube-dns-autoscaler-8b7698c76-mgcx8                        0/1     Pending   0          3d5h
    l7-default-backend-87b58b54c-x5q7f                         0/1     Pending   0          9d
    metrics-server-v1.31.0-769c5b4896-t5jjr                    0/1     Pending   0          9d
    
  3. בודקים למה סטטוס ה-Pods של המערכת הוא Pending:

    kubectl describe pod --namespace=kube-system SYSTEM_POD_NAME
    

    מחליפים את SYSTEM_POD_NAME בשם של Pod במערכת מתוך הפלט של הפקודה הקודמת.

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

    ...
    Events:
    Type     Reason            Age                       From               Message
    ----     ------            ----                      ----               -------
    Warning  FailedScheduling  4m35s (x27935 over 3d5h)  default-scheduler  no nodes available to schedule pods
    ...
    

    בפלט, הערך no nodes available to schedule pods בשדה Message של האירוע FailedScheduling מציין שלא בוצע תזמון של ה-Pod של המערכת כי האשכול ריק.

הגישה לצמתים הבסיסיים אסורה באשכול GKE Autopilot. לכן, צריך להריץ את כלי השירות tcpdump מתוך Pod ואז להעתיק אותו באמצעות הפקודה kubectl cp. אם בדרך כלל מריצים את כלי השירות tcpdump מתוך Pod באשכול GKE Autopilot, יכול להיות שתופיע השגיאה הבאה:

    tcpdump: eth0: You don't have permission to perform this capture on that device
    (socket: Operation not permitted)

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

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: tcpdump
  name: tcpdump
spec:
  containers:
  - image: nginx
    name: nginx
    resources:
      limits:
        cpu: 500m
        ephemeral-storage: 1Gi
        memory: 2Gi
      requests:
        cpu: 500m
        ephemeral-storage: 1Gi
        memory: 2Gi
    securityContext:
      capabilities:
        # This section drops NET_RAW to mitigate security vulnerabilities
        drop:
        - NET_RAW

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

  1. מוסיפים את היכולת NET_RAW לקטע securityContext במפרט ה-YAML של ה-Pod:

    securityContext:
      capabilities:
        add:
        - NET_RAW
    
  2. הפעלת tcpdump מתוך Pod:

    tcpdump port 53 -w packetcap.pcap
    tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
    
  3. משתמשים בפקודה kubectl cp כדי להעתיק אותו למכונה המקומית לצורך ניתוח נוסף:

    kubectl cp POD_NAME:/PATH_TO_FILE/FILE_NAME/PATH_TO_FILE/FILE_NAME
    
  4. משתמשים ב-kubectl exec כדי להריץ את הפקודה tcpdump כדי לבצע תיעוד של חבילות נתונים ברשת ולהפנות את הפלט:

    kubectl exec -it POD_NAME -- bash -c "tcpdump port 53 -w -" > packet-new.pcap
    

לא ניתן להפעיל Pods בצומת בגלל כשל ב-NRI RunPodSandbox

במקרים נדירים, צומת Autopilot בכיתות מחשוב של ברירת מחדל, מאוזן, הרחבה אופקית, autopilot ו-autopilot-spot יכול להיכנס למצב שבו פודים של המערכת, כמו anetd, ופודים של משתמשים שהוקצו לצומת, לא יכולים לעבור למצב פעיל. אם anetd לא יכול לעבור למצב פעיל, סימן שהרשת של ה-Pod פגומה חלקית או לגמרי בצומת. מצב השגיאה הזה מופעל רק במהלך שדרוגים מסוימים של מישור הבקרה של האשכול.

אם אתם מבחינים בבעיה, אתם יכולים לצמצם אותה בצומת מסוים באמצעות ההליך לצמצום בעיות בביצועים של עומסי עבודה לא אמינים בצומת ספציפי.

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

  • ‫1.35: כל גרסאות התיקון
  • ‫1.34: 1.34.1-gke.3899000 ואילך
  • ‫1.33: גרסה 1.33.5-gke.2392000 ואילך

אם אתם חושדים שצומת נמצא במצב השגיאה הזה, אתם יכולים לאשר את המצב הזה באופן הבא:

  1. מאתרים את ה-Pod efficiency-daemon שפועל בצומת החשוד:

    DAEMON_POD_NAME=$(kubectl get pods \
      --namespace kube-system \
      --selector k8s-app=efficiency-daemon \
      --field-selector spec.nodeName=NODE_NAME \
      --output custom-columns=":metadata.name" \
      --no-headers)
    echo $DAEMON_POD_NAME
    

    אם אין efficiency-daemon pod בצומת, הצומת לא מושפע מהבעיה הספציפית הזו.

  2. בודקים אם יש שגיאות ספציפיות מ-efficiency-daemon Pod:

    kubectl logs -n kube-system $DAEMON_POD_NAME | grep "connect: operation not permitted" | wc -l
    

    אם הפלט גדול מ-10, סביר מאוד שהצומת מושפע מהבעיה הזו.

אם הודעת השגיאה הבאה מופיעה שוב ושוב באירועים של Pod עבור Pod שהוקצה לצומת, סימן שהבעיה משפיעה על הצומת: Failed to create pod sandbox: rpc error: code = Unknown desc = NRI RunPodSandbox failed: rpc error: code = Unknown desc = internal error: reconciliation failed.

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