בדף הזה מוסבר איך לפתור בעיות בתזמן של Kubernetes (kube-scheduler) ב-Google Distributed Cloud.
מערכת Kubernetes תמיד מתזמנת את ה-Pods לאותה קבוצת צמתים
השגיאה הזו יכולה להופיע בכמה דרכים שונות:
ניצול לא מאוזן של האשכול. אפשר לבדוק את ניצול האשכול לכל צומת באמצעות הפקודה
kubectl top nodes. בדוגמה הבאה, שהיא מוגזמת, אפשר לראות שימוש מוגבר בצמתים מסוימים:NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% XXX.gke.internal 222m 101% 3237Mi 61% YYY.gke.internal 91m 0% 2217Mi 0% ZZZ.gke.internal 512m 0% 8214Mi 0%יותר מדי בקשות. אם מתזמנים הרבה Pods בבת אחת לאותו צומת, וה-Pods האלה שולחים בקשות HTTP, יכול להיות שהצומת יוגבל על ידי הגבלת קצב. השגיאה הנפוצה שהשרת מחזיר בתרחיש הזה היא
429 Too Many Requests.השירות לא זמין. לדוגמה, שרת אינטרנט שמארח צומת תחת עומס גבוה עשוי להשיב לכל הבקשות עם שגיאות
503 Service Unavailableעד שהעומס עליו יפחת.
כדי לבדוק אם יש לכם Pods שתמיד מתוזמנים לאותם צמתים, מבצעים את השלבים הבאים:
מריצים את פקודת
kubectlהבאה כדי לראות את הסטטוס של ה-Pods:kubectl get pods -o wide -n defaultכדי לראות את ההפצה של ה-Pods בין הצמתים, בודקים את העמודה
NODEבפלט. בדוגמת הפלט הבאה, כל ה-Pods מתוזמנים באותו הצומת:NAME READY STATUS RESTARTS AGE IP NODE nginx-deployment-84c6674589-cxp55 1/1 Running 0 55s 10.20.152.138 10.128.224.44 nginx-deployment-84c6674589-hzmnn 1/1 Running 0 55s 10.20.155.70 10.128.226.44 nginx-deployment-84c6674589-vq4l2 1/1 Running 0 55s 10.20.225.7 10.128.226.44
לפודים יש מספר תכונות שמאפשרות לכוונן את התנהגות התזמון שלהם. התכונות האלה כוללות אילוצי פיזור טופולוגיה וכללי אנטי-אפיניות. אפשר להשתמש באחת מהתכונות האלה או בשילוב שלהן. הדרישות
שאתם מגדירים מחוברות באמצעות הפונקציה AND על ידי kube-scheduler.
יומני המתזמן לא נשמרים ברמת הפירוט של היומנים שמוגדרת כברירת מחדל. אם אתם צריכים את יומני המתזמן לפתרון בעיות, אתם יכולים לבצע את השלבים הבאים כדי לתעד את יומני המתזמן:
הגברת רמת הפירוט של הרישום ביומן:
עורכים את הפריסה
kube-scheduler:kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG edit deployment kube-scheduler \ -n USER_CLUSTER_NAMESPACEמוסיפים את הדגל
--v=5בקטעspec.containers.command:containers: - command: - kube-scheduler - --profiling=false - --kubeconfig=/etc/kubernetes/scheduler.conf - --leader-elect=true - --v=5
אחרי שמסיימים לפתור את הבעיות, מאפסים את רמת הפירוט בחזרה לרמת ברירת המחדל:
עורכים את הפריסה
kube-scheduler:kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG edit deployment kube-scheduler \ -n USER_CLUSTER_NAMESPACEמגדירים את רמת הפירוט בחזרה לערך ברירת המחדל:
containers: - command: - kube-scheduler - --profiling=false - --kubeconfig=/etc/kubernetes/scheduler.conf - --leader-elect=true
מגבלות על פיזור הטופולוגיה
אפשר להשתמש באילוצים של פיזור טופולוגי כדי לפזר את ה-Pods באופן שווה בין הצמתים בהתאם לzones, regions, node או לטופולוגיה אחרת שהוגדרה בהתאמה אישית.
במניפסט לדוגמה הבא מוצג Deployment שמפיץ רפליקות באופן שווה בין כל הצמתים שאפשר לתזמן באמצעות אילוצי הפצה טופולוגיים:
apiVersion: apps/v1
kind: Deployment
metadata:
name: topology-spread-deployment
labels:
app: myapp
spec:
replicas: 30
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
topologySpreadConstraints:
- maxSkew: 1 # Default. Spreads evenly. Maximum difference in scheduled Pods per Node.
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule # Default. Alternatively can be ScheduleAnyway
labelSelector:
matchLabels:
app: myapp
matchLabelKeys: # beta in 1.27
- pod-template-hash
containers:
# pause is a lightweight container that simply sleeps
- name: pause
image: registry.k8s.io/pause:3.2
כשמשתמשים באילוצים של פיזור טופולוגי, חשוב לקחת בחשבון את הנקודות הבאות:
labels.app: myappשל ה-Pod תואם לlabelSelectorשל האילוץ.- הערך
topologyKeyמצייןkubernetes.io/hostname. התווית הזו מצורפת באופן אוטומטי לכל הצמתים ומאוכלסת בשם המארח של הצומת. - ההגדרה
matchLabelKeysמונעת מפריסות של גרסאות חדשות להתחשב ב-Pods של גרסאות ישנות כשמחשבים איפה לתזמן Pod. התוויתpod-template-hashמאוכלסת באופן אוטומטי על ידי פריסה.
אנטי-זיקה של Pod
Pod anti-affinity מאפשרת להגדיר אילוצים לגבי האפשרות למקם Pods באותו צומת.
במניפסט לדוגמה הבא מוצג Deployment שמשתמש בשיטה למניעת קרבה כדי להגביל את העותקים ל-Pod אחד לכל צומת:
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-affinity-deployment
labels:
app: myapp
spec:
replicas: 30
selector:
matchLabels:
app: myapp
template:
metadata:
name: with-pod-affinity
labels:
app: myapp
spec:
affinity:
podAntiAffinity:
# requiredDuringSchedulingIgnoredDuringExecution
# prevents Pod from being scheduled on a Node if it
# does not meet criteria.
# Alternatively can use 'preferred' with a weight
# rather than 'required'.
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp
# Your nodes might be configured with other keys
# to use as `topologyKey`. `kubernetes.io/region`
# and `kubernetes.io/zone` are common.
topologyKey: kubernetes.io/hostname
containers:
# pause is a lightweight container that simply sleeps
- name: pause
image: registry.k8s.io/pause:3.2
בדוגמה הזו של פריסה מצוינות 30 רפליקות, אבל המערכת תרחיב את הפריסה רק למספר הצמתים שזמינים באשכול.
כשמשתמשים בתכונה Pod anti-affinity, צריך להתחשב בשיקולים הבאים:
labels.app: myappשל ה-Pod תואם לlabelSelectorשל האילוץ.- הערך
topologyKeyמצייןkubernetes.io/hostname. התווית הזו מצורפת באופן אוטומטי לכל הצמתים ומאוכלסת בשם המארח של הצומת. אתם יכולים להשתמש בתוויות אחרות אם האשכול תומך בהן, כמוregionאוzone.
משיכת תמונות של קונטיינרים מראש
אם אין אילוצים אחרים, כברירת מחדל kube-scheduler מעדיף לתזמן Pods על Nodes שכבר הורידו אליהם את קובץ אימג' של קונטיינר. ההתנהגות הזו עשויה להיות רלוונטית באשכולות קטנים יותר ללא הגדרות תזמון אחרות, שבהם אפשר להוריד את התמונות בכל צומת. עם זאת, מומלץ להסתמך על הרעיון הזה רק כמוצא אחרון. פתרון טוב יותר הוא להשתמש ב-nodeSelector, במגבלות של פיזור טופולוגי או בזיקה / אנטי-זיקה. מידע נוסף זמין במאמר בנושא הקצאת Pods לצמתים.
אם רוצים לוודא שקובצי האימג' של הקונטיינרים נמשכים מראש לכל הצמתים, אפשר להשתמש ב-DaemonSet כמו בדוגמה הבאה:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: prepulled-images
spec:
selector:
matchLabels:
name: prepulled-images
template:
metadata:
labels:
name: prepulled-images
spec:
initContainers:
- name: prepulled-image
image: IMAGE
# Use a command the terminates immediately
command: ["sh", "-c", "'true'"]
containers:
# pause is a lightweight container that simply sleeps
- name: pause
image: registry.k8s.io/pause:3.2
אחרי שה-Pod נמצא במצב Running בכל הצמתים, פורסים מחדש את ה-Pods כדי לבדוק אם הקונטיינרים מפוזרים עכשיו באופן שווה בין הצמתים.
המאמרים הבאים
לקבלת עזרה נוספת, אפשר לפנות אל Cloud Customer Care.
אפשר גם לעיין במאמר קבלת תמיכה לקבלת מידע נוסף על מקורות מידע לתמיכה, כולל:
- דרישות לפתיחת בקשת תמיכה.
- כלים שיעזרו לכם לפתור בעיות, כמו יומנים ומדדים.
- רכיבים, גרסאות ותכונות נתמכים של Google Distributed Cloud ל-VMware (תוכנה בלבד).