מאגרי קיבולת משפרים את הרספונסיביות והאמינות של עומסי עבודה קריטיים, על ידי ניהול יזום של קיבולת אשכולות פנויה ומצבים מושהים של קיבולת שהוקצתה והוגדרה מראש, באמצעות Kubernetes CapacityBuffer CustomResourceDefinition (CRD). שימוש במאגרי קיבולת מאפשר לכם להגדיר במפורש כמות ספציפית של קיבולת צומת לא מנוצלת בתוך האשכול. הקיבולת השמורה הזו עוזרת לצמצם את זמן התזמון של Pod.
כשצריך להגדיל במהירות עומס עבודה בעדיפות גבוהה, עומס העבודה החדש יכול להשתמש בקיבולת הריקה באופן מיידי בלי לחכות להקצאת צמתים. הגישה הזו מצמצמת את זמן האחזור ומונעת תחרות על משאבים במהלך עליות פתאומיות בביקוש.
בדף הזה מוסבר איך להגדיר מאגרי קיבולת: מאגר רפליקות קבוע, מאגר מגבלות משאבים ומאגר מבוסס-אחוזים.
לפני שמתחילים
לפני שמתחילים, חשוב לוודא שביצעתם את המשימות הבאות:
- מפעילים את Google Kubernetes Engine API. הפעלת Google Kubernetes Engine API
- כדי להשתמש ב-Google Cloud CLI למשימה הזו, מתקינים ואז מאתחלים את ה-CLI של gcloud. אם כבר התקנתם את ה-CLI של gcloud, הריצו את הפקודה
gcloud components updateכדי לקבל את הגרסה העדכנית. יכול להיות שבגרסאות קודמות של ה-CLI של gcloud אי אפשר להריץ את הפקודות שבמסמך הזה.
- יוצרים אשכול GKE או מקבלים גישה לאשכול GKE שעומד בדרישות הגרסה הבאות:
- במאגרים פעילים, צריך להשתמש בגרסה 1.35.2-gke.1842000 ואילך באשכולות Standard ו-Autopilot.
- כדי להשתמש במאגרי נתונים זמניים במצב המתנה, צריך להשתמש בגרסה 1.36.0-gke.2253000 ואילך באשכולות Standard, או בגרסה 1.36.0-gke.2853000 ואילך באשכולות Autopilot עם ComputeClasses בהתאמה אישית.
- מפעילים יצירה אוטומטית של מאגרי צמתים באשכולות הרגילים. באשכולות Autopilot, היצירה האוטומטית של מאגרי צמתים כבר מופעלת. יצירה אוטומטית של מאגרי צמתים היא אופציונלית, אבל מומלצת למאגרים פעילים ונדרשת למאגרים במצב המתנה.
יצירת אובייקטים של Kubernetes שנדרשים מראש
כדי להגדיר CapacityBuffer, צריך מרחב שמות שמכיל את כל האובייקטים הנדרשים (CapacityBuffer עצמו ומשאבים נוספים כמו PodTemplate או עומס עבודה). ה-PodTemplate וה-CapacityBuffer צריכים להיות באותו מרחב שמות. אתם יכולים ליצור מרחב שמות או להשתמש במרחב שמות קיים, כולל מרחב השמות default.
בהתאם לסוג של CapacityBuffer שאתם מגדירים, תצטרכו גם אחת מהאפשרויות הבאות:
- PodTemplate: מגדיר את דרישות המשאבים ליחידה אחת של קיבולת מאגר. ההגדרה שצוינה באובייקט CapacityBuffer מפנה לתבנית Pod.
עומס עבודה: עומס עבודה קיים שאתם מפנים אליו באובייקט CapacityBuffer. במדריך הזה נעשה שימוש באובייקט Deployment כדוגמה לעומס עבודה, אבל מאגרי קיבולת תומכים בכל אחד מסוגי המשאבים הבאים:
- פריסה
- ReplicaSet
- StatefulSet
- ReplicationController
- משימה
CustomResourceDefinitions (CRD) שמטמיעים את משאב המשנה
scale.
בקטע הזה מופיעות דוגמאות לאובייקטים האלה. אם כבר יש לכם עומס עבודה שאתם רוצים להגדיר עם מאגר קיבולת, המשיכו לקטע החלת מאגר קיבולת.
כדי ליצור עומס עבודה לדוגמה ב-Kubernetes:
שומרים את המניפסט הבא בתור
namespace.yaml:apiVersion: v1 kind: Namespace metadata: name: capacity-buffer-example labels: name: capacity-buffer-exampleהמניפסט הזה יוצר מרחב שמות בשם
capacity-buffer-example.אופציונלי: כדי להשתמש במאגרי קיבולת עם ComputeClass בהתאמה אישית, שומרים את המניפסט הבא בתור
custom-compute-class.yaml:apiVersion: cloud.google.com/v1 kind: ComputeClass metadata: name: ccc-example spec: # Buffers are also created according to these priorities priorities: - machineFamily: n4 - machineFamily: n4d - machineFamily: c4 - machineFamily: c4d nodePoolAutoCreation: enabled: trueהמניפסט הזה יוצר
ComputeClassבהתאמה אישית שמגדיר את סדרי העדיפויות של המחשוב לצמתים ש-GKE מקצה, ושולט בהם. מידע נוסף זמין במאמר ComputeClasses בהתאמה אישית.שומרים את המניפסט הבא בתור
buffer-pod-template.yaml:apiVersion: v1 kind: PodTemplate metadata: name: buffer-unit-template namespace: capacity-buffer-example # the namespace must be the same namespace as the CapacityBuffer template: spec: terminationGracePeriodSeconds: 0 containers: - name: buffer-container image: registry.k8s.io/pause:3.9 resources: requests: cpu: "1" memory: "1Gi" limits: cpu: "1" memory: "1Gi" # Optional: Using buffers with a custom ComputeClass / # controls the properties of the provisioned nodes. nodeSelector: cloud.google.com/compute-class: ccc-exampleהמניפסט הזה יוצר
PodTemplateשמגדיר את דרישות המשאבים ליחידה אחת של קיבולת מאגר (1מעבד ו-1Giזיכרון). ההגדרה הזו מציינת את הגודל של יחידות הקיבולת ש-GKE מקצה למאגר הנתונים הזמני. לדוגמה, עם PodTemplate כזה, אם האשכול יוגדל, GKE לא יחשיב צמתים עם פחות ממעבד אחד ו-1Gi של משאבים זמינים כחלק מהמאגר.שומרים את המניפסט הבא בתור
sample-workload-deployment.yaml:apiVersion: apps/v1 kind: Deployment metadata: name: critical-workload-ref namespace: capacity-buffer-example # the namespace must be the same namespace as the CapacityBuffer spec: replicas: 10 selector: matchLabels: app: critical-workload template: metadata: labels: app: critical-workload spec: containers: - name: busybox image: busybox command: ["sleep", "3600"] resources: requests: cpu: 100m # Optional: Using buffers with a custom ComputeClass / # controls the properties of the provisioned nodes. nodeSelector: cloud.google.com/compute-class: ccc-exampleהמניפסט הזה יוצר פריסה לדוגמה עם 10 רפליקות, שהן אובייקט העזר לדוגמה של מאגר מבוסס-אחוזים בקטע הבא.
מחילים את המניפסטים על האשכול:
kubectl apply -f namespace.yaml -f custom-compute-class.yaml -f buffer-pod-template.yaml -f sample-workload-deployment.yamlמוודאים ש-GKE יצר את האובייקטים:
kubectl get podtemplate -n capacity-buffer-example kubectl get deployment critical-workload-ref -n capacity-buffer-exampleהפלט אמור להיראות כך:
NAME AGE buffer-unit-template 1m NAME READY UP-TO-DATE AVAILABLE AGE critical-workload-ref 10/10 10 10 1m
הוספת אזור חיץ לקיבולת
בקטע הזה מפורטות דוגמאות לסוגים השונים של מאגרי קיבולת זמניים שאפשר להחיל על עומסי העבודה.
הגדרת מאגר קבוע של רפליקות
כשמגדירים CapacityBuffer עם רפליקות קבועות, מציינים את המספר המדויק של יחידות המאגר שרוצים על סמך PodTemplate.
כדי ליצור מאגר עם רפליקות קבועות:
שומרים את המניפסט הבא בתור
cb-fixed-replicas.yaml:apiVersion: autoscaling.x-k8s.io/v1beta1 kind: CapacityBuffer metadata: name: fixed-replica-buffer namespace: NAMESPACE spec: podTemplateRef: name: POD_TEMPLATE replicas: 3 provisioningStrategy: "STRATEGY"מחליפים את מה שכתוב בשדות הבאים:
-
NAMESPACE: השם של מרחב השמות, לדוגמהcapacity-buffer-example. -
POD_TEMPLATE: ה-PodTemplate שמגדיר את דרישות המשאבים, לדוגמהbuffer-unit-template. STRATEGY: אסטרטגיית ההקצאה,"buffer.x-k8s.io/active-capacity"(ברירת המחדל) או"buffer.gke.io/standby-capacity".
המניפסט הזה יוצר משאב CapacityBuffer שמפנה ל-PodTemplate כדי לבקש מספר ספציפי של יחידות מאגר.
-
מחילים את המניפסט:
kubectl apply -f cb-fixed-replicas.yamlמוודאים ש-GKE החיל את מאגר הקיבולת:
kubectl get capacitybuffer fixed-replica-buffer -n NAMESPACEהשדה
replicasבסטטוס אמור להציג את הערך3, שמשקף את מספר הרפליקות שהגדרתם במניפסט. בשדהSTATUSאמור להופיע הערךReadyForProvisioning.
הגדרת מאגר זמני למגבלות על משאבים
אתם יכולים להשתמש בשדה limits כדי להגדיר את כמות המשאבים המקסימלית שהמאגר הזמני יכול לצרוך, שמחושבת על סמך הגודל של PodTemplate.
כדי ליצור מאגר למגבלות המשאבים:
שומרים את המניפסט הבא בתור
cb-resource-limits.yaml:apiVersion: autoscaling.x-k8s.io/v1beta1 kind: CapacityBuffer metadata: name: resource-limit-buffer namespace: NAMESPACE spec: podTemplateRef: name: POD_TEMPLATE limits: cpu: "5" memory: "5Gi" provisioningStrategy: "STRATEGY"מחליפים את מה שכתוב בשדות הבאים:
-
NAMESPACE: השם של מרחב השמות, לדוגמהcapacity-buffer-example. -
POD_TEMPLATE: ה-PodTemplate שמגדיר את דרישות המשאבים, לדוגמהbuffer-unit-template. STRATEGY: אסטרטגיית ההקצאה,"buffer.x-k8s.io/active-capacity"(ברירת המחדל) או"buffer.gke.io/standby-capacity".
המניפסט הזה יוצר משאב CapacityBuffer עם מגבלה כוללת של 5 מעבדים וזיכרון בנפח 5GiB. אם אתם משתמשים בדוגמה של PodTemplate מהשלב הקודם, אתם מגדירים כל יחידה כ-
1מעבד (CPU) ו-1Giזיכרון, מה שאמור להוביל ל-5 יחידות מאגר.-
מחילים את המניפסט:
kubectl apply -f cb-resource-limits.yamlמוודאים ש-GKE החיל את מאגר הקיבולת:
kubectl get capacitybuffer resource-limit-buffer -n NAMESPACEבודקים את הסטטוס של CapacityBuffer. בשדה
replicasאמור להופיע ערך שנגזר מהמגבלות שהגדרתם. אם אתם משתמשים בדוגמה של PodTemplate מהקטע הקודם, אתם אמורים לראות5יחידות מאגר, כי זה המספר המקסימלי של יחידות שמתאימות למגבלות שהוגדרו.
הגדרת מאגר נתונים זמני שמבוסס על אחוזים
הגדרת מאגר מבוסס-אחוזים משנה באופן דינמי את גודל המאגר על סמך אחוז מעומס עבודה קיים שניתן להתאמה לעומס. מאגרי קיבולת שמבוססים על אחוזים נתמכים רק באובייקטים של Kubernetes שניתנים להתאמה, שמטמיעים את משאב המשנה של ההתאמה, כמו Deployments, StatefulSets, ReplicaSets או Jobs. אי אפשר להגדיר מאגר מבוסס-אחוזים לתבניות Pod כי אין להן שדה replicas.
ברוב המקרים, כדאי להתחיל עם אסטרטגיות של רפליקות קבועות או מגבלות משאבים, ולא עם מאגרים שמבוססים על אחוזים. כדאי להביא בחשבון את הנקודות הבאות:
- מאגרים שמבוססים על אחוזים פחות מגיבים להגדלות פתאומיות אם עומס העבודה מוגדל למספרים נמוכים או לאפס, כי מרווח הבטיחות פוחת ביחס לפודים הפעילים.
- צומתי המתנה צוברים חיובי מחשוב במהלך תקופת האתחול שלהם לפני ההשעיה. התאמה דינמית של מאגרי ה-standby בהתאם לתנודות בעומס העבודה מבזבזת משאבי מחשוב, ולכן כדאי להשתמש ברפליקות קבועות או במגבלות משאבים למאגרי ה-standby.
- מאגרים מבוססי-אחוזים שימושיים בעיקר למאגרים פעילים בפריסות גדולות, שבהן מספר הרפליקות אף פעם לא קטן.
ב-GKE בגרסה 1.36.3-gke.1244000 ואילך, כדי לשמור על שטח אחסון זמני מינימלי כשעומס העבודה המקושר מצטמצם, מגדירים את השדה replicas יחד עם השדה percentage. GKE משתמש בשדה שמוביל ליותר יחידות מאגר. כדי להגביל את שטח האחסון הזמני, צריך להגדיר גם את השדה limits.
לדוגמה, נניח שיש מאגר עם percentage: 20 ו-replicas: 3 שמפנה לפריסה עם 10 רפליקות. 20% מ-10 רפליקות הם 2, וזה פחות מהערך 3 של replicas, אז GKE מקצה 3 יחידות מאגר. אם הפריסה מתרחבת ל-20 רפליקות, המאגר גדל ל-4 יחידות. מידע נוסף זמין במאמרי העזרה של CapacityBuffer.
כדי ליצור מאגר באחוזים, מבצעים את השלבים הבאים:
שומרים את המניפסט הבא בתור
cb-percentage-based.yaml:apiVersion: autoscaling.x-k8s.io/v1beta1 kind: CapacityBuffer metadata: name: percentage-buffer namespace: NAMESPACE spec: scalableRef: apiGroup: apps kind: Deployment name: SCALABLE_RESOURCE_NAME percentage: 20 provisioningStrategy: "STRATEGY"מחליפים את מה שכתוב בשדות הבאים:
-
NAMESPACE: השם של מרחב השמות. -
SCALABLE_RESOURCE_NAME: השם של המשאב שניתן להתאמה לעומס, לדוגמהcritical-workload-ref. STRATEGY: אסטרטגיית ההקצאה,"buffer.x-k8s.io/active-capacity"(ברירת המחדל) או"buffer.gke.io/standby-capacity".
המניפסט הזה יוצר משאב CapacityBuffer שמבקש שטח אחסון זמני ששווה ל-20% מהרפליקות של המשאב שאליו מתייחסים. אם אתם משתמשים בדוגמה לפריסה מהקטע הקודם, ערך הרפליקה מוגדר ל-
10.-
מחילים את המניפסט:
kubectl apply -f cb-percentage-based.yamlמוודאים ש-GKE החיל את מאגר הקיבולת:
kubectl get capacitybuffer percentage-buffer -n NAMESPACEבודקים את הסטטוס של CapacityBuffer. בשדה
replicasצריך להופיע ערך מחישוב האחוזים. אם אתם משתמשים בדוגמה לפריסה מהקטע הקודם, אתם אמורים לראות2יחידות מאגר, שהן 20% מ-10 הרפליקות שהוגדרו בפריסה.כדי לבדוק את ההתאמה הדינמית לעומס, מגדילים את הפריסה באופן ידני ל-20 רפליקות:
kubectl scale deployment critical-workload-ref -n NAMESPACE --replicas=20הבקר CapacityBuffer מגיב ומגדיל באופן אוטומטי את המאגר ל-4 רפליקות.
התאמה אישית של התנהגות המאגר הזמני במצב המתנה
אתם יכולים להשתמש בהערות כדי להתאים אישית את האופן שבו מאגרי הנתונים הזמניים במצב המתנה מתחילים ומתרעננים.
מוסיפים את ההערות האלה לשדה metadata.annotations של המשאב CapacityBuffer:
-
buffer.gke.io/standby-capacity-init-time: משך הזמן שבו צומת נשאר פעיל אחרי היצירה שלו, לפני ש-GKE משעה אותו. מציינים מחרוזת משך זמן, כמו5mאו1h. ערך ברירת המחדל הוא5m.
buffer.gke.io/standby-capacity-refresh-frequency: התדירות שבה GKE מרענן צמתים מושהים. מציינים מחרוזת של משך זמן, כמו12hאו24h. ערך ברירת המחדל הוא24h.
בדוגמה הבאה מוצג מניפסט עם השדות האופציונליים האלה, שמאפשרים להתאים אישית את ההתנהגות של מאגרי הנתונים הזמניים במצב המתנה:
apiVersion: autoscaling.x-k8s.io/v1beta1
kind: CapacityBuffer
metadata:
name: customized-standby-buffer
namespace: my-namespace
annotations:
buffer.gke.io/standby-capacity-init-time: "15m"
buffer.gke.io/standby-capacity-refresh-frequency: "12h"
spec:
podTemplateRef:
name: buffer-unit-template
replicas: 3
provisioningStrategy: "buffer.gke.io/standby-capacity"
טעינה מראש של תמונות במאגרי נתונים זמניים במצב המתנה
כדי לקצר את זמני ההפעלה של עומסי העבודה כשצומת במצב המתנה ממשיך לפעול, אתם יכולים לטעון מראש קובצי אימג' של קונטיינרים באמצעות DaemonSet. ה-DaemonSet פועל במהלך תקופת ההפעלה לפני שהצומת מושעה.
כדי לטעון מראש תמונות באמצעות DaemonSet:
שומרים את המניפסט הבא בתור
image-puller-daemonset.yaml:apiVersion: apps/v1 kind: DaemonSet metadata: name: image-prefetch-daemonset namespace: NAMESPACE spec: selector: matchLabels: name: image-prefetch template: metadata: labels: name: image-prefetch spec: tolerations: - key: "buffer.gke.io/standby-capacity-node-suspended" operator: "Exists" initContainers: - name: image-puller image: IMAGE_NAME command: ["sh", "-c", "true"] containers: - name: pause image: registry.k8s.io/pause:3.9מחליפים את מה שכתוב בשדות הבאים:
-
NAMESPACE: מרחב השמות של DaemonSet, לדוגמהcapacity-buffer-example. -
IMAGE_NAME: שם התמונה לטעינה מראש, לדוגמהyour-app-image:latest.
המניפסט הזה כולל את הסבילות
buffer.gke.io/standby-capacity-node-suspendedכדי שה-DaemonSet יישאר מתוזמן בצמתים במצב המתנה אחרי ש-GKE משעה אותם.-
מחילים את המניפסט של DaemonSet על האשכול:
kubectl apply -f image-puller-daemonset.yamlמוודאים שה-DaemonSet נוצר:
kubectl get daemonset image-prefetch-daemonset -n NAMESPACEמוודאים שהמאגר הזמני של הקיבולת נוצר ומוכן להקצאה:
kubectl get capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACEבודקים את הסטטוס שלו. בשדה
STATUSאמור להופיע הערךReadyForProvisioning.
מעקב אחרי הסטטוס והביצועים של מאגר הנתונים הזמני של הקיבולת
אתם יכולים לעקוב אחרי הסטטוס והתקינות של מאגרי הקיבולת באמצעות פקודות kubectl ומדדי Cloud Monitoring.
אימות סטטוס המשאב CapacityBuffer
כדי לבדוק את התקינות של מאגרי הקיבולת ולוודא שהם מוכנים לקבל עומסי עבודה, בצעו את הפעולות הבאות:
כדי לקבל את הסטטוס של כל מאגרי הקיבולת באשכול:
kubectl get capacitybuffer -Aבודקים את הסטטוס המפורט, התנאים ויומני האירועים של מאגר נתונים ספציפי:
kubectl describe capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
זיהוי צומתי מאגר המתנה מושעים
מכונות וירטואליות במאגר זמני להמתנה מוקצות מראש, אבל נשמרות במצב מושהה כדי לצמצם את העלויות. אפשר לזהות את הצמתים המושעים האלה כי יש להם תנאי בהתאמה אישית. כדי לבדוק את המכונות של הצמתים שהושעו, מריצים את הפקודה הבאה:
kubectl get nodes -o custom-columns='NAME:.metadata.name,SUSPENDED:.status.conditions[?(@.type=="Suspended")].status'
הסטטוס True מציין שהמכונה הווירטואלית במצב המתנה מושעית. הסטטוס False או <none> מציין צומת פעיל שפועל.
מעקב אחרי הביצועים באמצעות Cloud Monitoring
כדי לעקוב אחרי ההשפעה מקצה לקצה של מאגרי הקיבולת על זמני ההרחבה, אפשר להשתמש בלוחות הבקרה של זמן האחזור בהפעלה במסוף Google Cloud . בתרשימים Pod Startup Latency Distribution ו-Pod First Ready Latency אפשר לעקוב אחרי המדד kubernetes.io/pod/latencies/pod_first_ready, מיצירת ה-Pod ועד שהוא מוכן. אפשר גם לשלוח שאילתות לגבי אירועי Scheduled ב-Cloud Logging כדי למדוד את זמן האחזור של תזמון Pod. הוראות מפורטות מופיעות במאמר מעקב אחרי מדדי זמן האחזור בהפעלה.
הסרת מאגרי קיבולת
אם אתם לא צריכים יותר מאגר קיבולת לעומסי העבודה, מחקו את האובייקט CapacityBuffer. כך מסירים את ה-Pods של ה-placeholder ומאפשרים ל-cluster autoscaler לצמצם את הצמתים.
kubectl delete capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
מחליפים את CAPACITY_BUFFER_NAME בשם של ה-CapacityBuffer שרוצים למחוק.
פתרון בעיות
בקטע הבא מוסבר איך לפתור בעיות נפוצות שקשורות למאגרי קיבולת.
מאגר הקיבולת לא מוכן בגלל מודל החיוב
אם יוצרים CapacityBuffer לעומס עבודה שמשתמש במודל החיוב שמבוסס על Pod (תשלום ל-Pod), מאגר הקיבולת לא יהיה מוכן להקצאה.
כדי לזהות את הבעיה, בודקים את הסטטוס של CapacityBuffer:
kubectl describe capacitybuffer BUFFER_NAME -n NAMESPACE
מחפשים תנאי מסוג ReadyForProvisioning עם סטטוס False.
כדי לפתור את הבעיה, ודאו שה-CapacityBuffer מפנה לעומס עבודה או ל-PodTemplate שתואמים לחיוב מבוסס-צומת.
שגיאות הרשאה במשאבים מותאמים אישית שניתנים להתאמה לעומס
אם מגדירים CapacityBuffer שיעבוד עם אובייקטים מותאמים אישית שניתנים להרחבה (באמצעות השדה scalableRef), יכול להיות שהמידרוג האוטומטי של אשכולות לא יצליח להתאים את המאגר לעומס אם אין לו את ההרשאות הנדרשות. הבעיה הזו מתרחשת רק בגרסאות GKE שקודמות ל-1.36.0-gke.2459000.
כדי לפתור את הבעיה, צריך לתת את ההרשאות הנדרשות באופן ידני על ידי יצירת ClusterRole ו-ClusterRoleBinding, כמו בדוגמה הבאה:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: custom-scale-getter
rules:
- apiGroups: ["api.example.com"]
resources: ["customreplicatedresources/scale"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ca-custom-scale-getter
subjects:
- kind: User
name: "system:cluster-autoscaler"
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: custom-scale-getter
מידע נוסף על הגדרת RBAC זמין במסמכי התיעוד של Kubernetes RBAC.
פודים של מאגר זמני לא מתוזמנים בצמתים שהוקצו על ידי ComputeClasses בהתאמה אישית
אם התלות בהגדרות של CapacityBuffer (לדוגמה, PodTemplate) בוחרת ComputeClass בהתאמה אישית, יכול להיות שתיתקלו בבעיה שבה פודים של מאגר זמני לא מתוזמנים בצמתים שהוקצו לאחרונה. הבעיה הזו גורמת למנגנון המידרוג האוטומטי של האשכול ליצור שוב ושוב מאגרי צמתים וצמתים מיותרים, בזמן שצמתים לא פעילים נמחקים.
הבעיה הזו מתרחשת אם ה-ComputeClass בהתאמה אישית מקצה צמתים עם taints או דרישות ספציפיות של זמן ריצה, ולפודים של המאגר (או ל-PodTemplate שהם מסתמכים עליו) אין tolerations או הגדרות תואמות.
כדי לפתור את הבעיה, צריך לעדכן את ההגדרות של CapacityBuffer ולציין את ה-tolerations, ה-node selectors או ה-runtime classes הנדרשים. לדוגמה, אם התלות בוחרת ComputeClass בהתאמה אישית שמוגדר עם GKE Sandbox, צריך לעדכן את התלות כדי לבצע אחת מהפעולות הבאות:
- צריך לציין את השדה
spec.runtimeClassName: gvisor. - מוסיפים סובלנות מפורשת ל-taint של
sandbox.gke.io/runtime=gvisor:NoSchedule.
מידע נוסף מופיע במאמרי העזרה בנושא ComputeClass בהתאמה אישית.
צומתי מאגר הנתונים הזמני במצב המתנה לא ממשיכים לפעול
יכול להיות שצומתי מאגר הנתונים הזמני במצב המתנה שהושעו לא יופעלו מחדש בגלל אחת מהסיבות הבאות:
- כדי להמשיך צומת המתנה מושהה, צריך קיבולת זמינה של Compute Engine באזור של סוג המכונה של הצומת ודור ספציפי של פלטפורמת המעבד (CPU), כמו בסדרת המכונות E2 או N2. אם לאזור אין מספיק קיבולת מחשוב בשביל ההגדרה המדויקת הזו, הצומת לא ימשיך לפעול. מידע נוסף זמין במאמר מגבלות ההשעיה וההמשך של Compute Engine.
- אם ב-ComputeClass בהתאמה אישית מופעלת העברה פעילה לצמתים בעדיפות גבוהה יותר (
activeMigration.optimizeRulePriority: true) והמכונות הווירטואליות במודל Spot ממוקמות בעדיפות גבוהה יותר ממכונות וירטואליות על פי דרישה, GKE מעביר עם הזמן צמתים במצב המתנה על פי דרישה למכונות וירטואליות במודל Spot. מכונות וירטואליות במודל Spot כפופות יותר למגבלות קיבולת, ואי אפשר להמיר מכונות וירטואליות מושהות במודל Spot למכונות וירטואליות על פי דרישה כשמחדשים את הפעילות שלהן. לכן, המגבלות האלה יכולות למנוע את חידוש הפעילות של צומתי ההמתנה האלה. - המשך הפעילות של הצומת חורג ממכסות Compute Engine של הפרויקט. מידע נוסף זמין במאמר מאגר הקיבולת לא מוקצה בגלל מגבלות המכסה.
כדי לזהות למה צומת במצב המתנה לא חזר לפעול, אתם יכולים לשלוח שאילתה ליומני הביקורת של Compute Engine ב-Logs Explorer כדי לחפש שגיאות מסוג ZONE_RESOURCE_POOL_EXHAUSTED או QUOTA_EXCEEDED בפעולות של compute.instances.resume.
כדי לפתור או לצמצם את הבעיה, נסו אחד או יותר מהפתרונות הבאים:
- להשתמש באשכולות אזוריים כדי שהמידרוג האוטומטי של האשכול יוכל להקצות או להמשיך צמתים בכמה אזורים.
- מגדירים כמה משפחות מכונות ברשימה
spec.prioritiesשל ה-ComputeClass בהתאמה אישית. אם אי אפשר להמשיך את הצמתים שהושעו, הכלי למידרוג אוטומטי של האשכול יכול לחזור ליצירת צמתים חדשים על סמך כלל עדיפות אחר. לצמתים החדשים האלה לוקח יותר זמן להיות מוכנים מאשר לצמתים במצב המתנה שהופעלו מחדש. ההגדרה הזו לא עוזרת לצמתים מושעים להמשיך, כי צומת מושעה יכול להמשיך רק עם סוג המכונה המקורי שלו. - משתמשים ב-ComputeClass בהתאמה אישית (CCC) ייעודי עם מכונות וירטואליות על פי דרישה, או מגדירים את השדה
activeMigration.optimizeRulePriorityלערךfalseב-ComputeClass שבו משתמש מאגר ה-standby. - כדאי לשלב את מאגר הנתונים הזמני במצב המתנה עם מאגר נתונים זמני פעיל קטן, כדי לספוג עליות חדות מיידיות בתנועה.
אי אפשר להקצות מאגר קיבולת בגלל מגבלות המכסה
אם מאגר הקיבולת חורג מהמכסות של Kubernetes ResourceQuotas או של Compute Engine, יכול להיות שהוא יקצה פחות רפליקות מהכמות שביקשתם או לא יצליח להגדיל את המשאבים.
כדי לזהות איזו מכסה מגבילה את המאגר, בודקים אחת או יותר מהמכסות הבאות:
בודקים אם ResourceQuota של Kubernetes במרחב השמות מגביל את המאגר:
kubectl describe capacitybuffer \ CAPACITY_BUFFER_NAME \ -n NAMESPACEבפלט של
status.conditions, מחפשים תנאי שלLimitedByQuotasעם הסטטוסTrue. גם יחידות מאגר פעילות וגם יחידות מאגר במצב המתנה, כולל יחידות שמגובות על ידי צומתי המתנה מושהים, נספרות במגבלות ResourceQuota של מרחב השמות כאילו יחידות ה-Pod של המאגר פועלות. כשהמאגר חורג מהמכסה של מרחב השמות, GKE מגביל את השדהstatus.replicasכך שיתאים למכסה הזמינה.בודקים אם מכסות הפרויקט ב-Compute Engine חוסמות את הקצאת הצמתים. ב-Logs Explorer, מחפשים ביומן
container.googleapis.com/cluster-autoscaler-visibilityאירועים מסוגno.scale.up.nap.quota.exceeded, או מחפשים ביומני הביקורת של Compute Engine שגיאות מסוגQUOTA_EXCEEDED.כשבודקים את המכסות של Compute Engine למאגרי המתנה, צריך לוודא את שתי המכסות הבאות בנוסף למכסות של vCPU וזיכרון:
- צומתי המתנה מושעים שומרים על כתובות ה-IP הפנימיות וכתובות ה-IP החיצוניות שלהם, מה שצורך את מכסת כתובות ה-IP שבשימוש.
- כשמשהים VM במצב המתנה, Compute Engine כותב את הזיכרון של הצומת בדיסק, מה שצורך מכסת דיסק של
Persistent disk standard (GB)באופן יחסי לגודל הזיכרון של הצומת.
כדי לפתור את הבעיה, אתם יכולים לבצע אחת מהפעולות הבאות:
- מגדילים את ה-ResourceQuota של Kubernetes במרחב השמות של המאגר הזמני.
- איך שולחים בקשה לשינוי המכסות ב-Compute Engine
- מקטינים את הערך של
replicas,limitsאוpercentageבמניפסט של CapacityBuffer.
פודים של DaemonSet מפסיקים לקבל נתונים אחרי שצומת במצב המתנה ממשיך לפעול
אחרי שצומת מאגר מושעה במצב המתנה ממשיך לפעול, יכול להיות שפודים של DaemonSet בצומת הזה יפסיקו לקבל נתונים דרך חיבורים ארוכי טווח שנפתחו לפני שהצומת הושעה. ה-Pods לא מתעדים שגיאות ולא מתחברים מחדש.
הבעיה הזו מתרחשת כש-DaemonSet Pod פועל כלקוח לקבלה בלבד, למשל לתגובת HTTP בסטרימינג, לחיבור WebSocket, לאירועים שנשלחים מהשרת או לקריאת gRPC לסטרימינג מהשרת. בזמן שהצומת בהמתנה מושעה, הזמן הקצוב של השרת או של מכשיר רשת ביניים מסתיים והחיבור נסגר. כשהצומת ממשיך לפעול, מקבץ הרשת (network stack) של ה-Pod עדיין מחשיב את החיבור כפתוח. מכיוון שה-Pod לא שולח נתונים, הוא אף פעם לא מזהה שהחיבור נסגר וממתין לנתונים ללא הגבלת זמן.
כדי לפתור את הבעיה, צריך להגדיר את אפליקציית הלקוח ב-DaemonSet Pod לזהות חיבורים סגורים ולהתחבר מחדש, באחת מהדרכים הבאות:
- מגדירים את TCP keepalive בצד הלקוח באפליקציה של ה-Pod (הפעלת keepalive רק בשרת לא שולחת התראה ל-Pod). מידע נוסף על פרמטרים של TCP keepalive זמין במאמר חיבורים במצב חוסר פעילות.
- מפעילים את אפשרות השקע
SO_KEEPALIVEבספריית הלקוח או בסביבת זמן הריצה של השפה, כמוsocket.setKeepAlive(true, initialDelay)ב-Node.js אוnet.Dialer.KeepAliveב-Go. בחלק מסביבות זמן הריצה, האפשרות TCP keepalive מושבתת כברירת מחדל. - הגדירו זמן קצר של חוסר פעילות ב-keepalive (
TCP_KEEPIDLE), למשל כמה שניות, במקום להסתמך על ברירת המחדל של מערכת ההפעלה. - עדכנו את האפליקציה כך שתתפוס את שגיאת החיבור (כמו איפוס החיבור או זמן קצוב לתפוגה) כשבדיקת keepalive נכשלת, ותפתח חיבור חדש.
- מפעילים את אפשרות השקע
- מגדירים בלקוח אותות חיים (heartbeats) ברמת האפליקציה או פסקי זמן לקריאה, כמו מסגרות פינג ופונג של WebSocket או פינגים של gRPC keepalive, ומעדכנים את האפליקציה כך שתתחבר מחדש כשמתרחש פסק זמן.