השתמש ב-`etcdctl snapshot save` עם אישורי ה-TLS המתאימים (`--cacert`, `--cert`, `--key`) ונקודת הקצה.
למה: etcd מאחסן את מצב האשכול כולו. יצירת תמונת מצב ישירה היא הדרך המקובלת לגבות אותו. באשכול kubeadm, TLS מופעל, ולכן אישורים הם חובה עבור `etcdctl` לצורך אימות.
השתמש ב-`etcdctl snapshot restore` לספריית נתונים חדשה. לאחר מכן, עדכן את קובץ המניפסט של ה-pod הסטטי `etcd.yaml` כדי שיצביע על ספריית הנתונים החדשה (`--data-dir` volume mount) והפעל מחדש את ה-kubelet.
למה: שחזור יוצר ספריית נתונים חדשה. יש לעדכן את קובץ המניפסט של ה-pod הסטטי כדי להשתמש בנתונים חדשים אלה, אחרת etcd יופעל עם ספריית הנתונים הישנה (או הריקה).
1. ב-Control Plane: שדרג את `kubeadm`, הרץ `kubeadm upgrade plan`, ולאחר מכן `kubeadm upgrade apply`. 2. בכל Worker Node: בצע `kubectl drain`, שדרג את `kubelet`, הפעל מחדש את שירות ה-kubelet, בצע `kubectl uncordon`.
למה: התהליך הוא רב-שלבי ורציף. `kubeadm` משדרג רק את רכיבי ה-Control Plane; יש לשדרג את `kubelet` ידנית בכל צומת. ריקון צמתים (Draining nodes) מבטיח שעומסי עבודה יפונו בבטחה לפני תחזוקה.
השתמש ב-`kubeadm certs check-expiration` כדי להציג תאריכי תפוגה. השתמש ב-`kubeadm certs renew all` (או לרכיבים ספציפיים) כדי לחדש אותם. הפעל מחדש את ה-pods של ה-Control Plane לאחר החידוש.
למה: אישורים שנוצרו על ידי kubeadm תקפים לשנה. חידוש הוא משימת תחזוקה נפוצה. יש להפעיל מחדש את רכיבי ה-Control Plane כדי לטעון את האישורים החדשים.
רכיב Control Plane (לדוגמה, API server) צריך להיות מוגדר או מופעל מחדש.
שנה את קובץ המניפסט של הרכיב ב-/etc/kubernetes/manifests/. ה-kubelet בצומת יזהה אוטומטית את השינוי ויפעיל מחדש את ה-pod.
למה: רכיבי Control Plane ב-kubeadm פועלים כ-static pods, המנוהלים ישירות על ידי ה-kubelet, ולא על ידי ה-API server. כל הניהול מתבצע באמצעות קבצי מניפסט בספרייה המנוטרת.
הגדר בקרות גישה למשתמשים או ליישומים.
השתמש ב-`Role` וב-`RoleBinding` עבור הרשאות בתחום ה-namespace. השתמש ב-`ClusterRole` וב-`ClusterRoleBinding` עבור הרשאות כלל-אשכוליות.
למה: זוהי ההפרדה הבסיסית ב-RBAC. `Role` קשור תמיד ל-namespace, בעוד ש-`ClusterRole` יכול להעניק גישה למשאבים שאינם קשורים ל-namespace (כמו nodes) או למשאבים בכל ה-namespaces.
חשבון שירות (service account) צריך לגשת למשאבים בכל ה-namespaces.
צור `ClusterRole` המגדיר את ההרשאות. צור `ClusterRoleBinding` כדי להעניק את ה-ClusterRole הספציפי ל-`ServiceAccount`.
למה: אף על פי ש-ServiceAccount הוא namespaced, `ClusterRoleBinding` יכול להעניק לו הרשאות כלל-אשכוליות. `RoleBinding` יעניק הרשאות רק בתוך ה-namespace של ה-RoleBinding עצמו.
שירותים ורשתות
חשוף יישום לתעבורה חיצונית ללא Load Balancer מבוסס ענן.
השתמש בשירות מסוג `type: NodePort`. זה חושף את השירות בפורט סטטי (טווח ברירת מחדל: 30000-32767) בכתובת ה-IP של כל צומת.
למה: NodePort היא דרך פשוטה להכניס תעבורה חיצונית לאשכול. היא פחות יקרה ואינה תלוית פלטפורמה בהשוואה ל-`type: LoadBalancer`, אך דורשת מלקוחות לדעת כתובת IP של צומת.
חשוף מספר שירותי HTTP/S תחת כתובת IP אחת, עם ניתוב מבוסס-מארח או מבוסס-נתיב.
פרוס Ingress Controller (לדוגמה, NGINX). צור משאבי `Ingress` המגדירים כללי ניתוב ממארחים/נתיבים ל-`Services` בקצה האחורי.
למה: Ingress הוא משאב Kubernetes הסטנדרטי לניתוב L7. הוא דורש בקר נפרד כדי ליישם בפועל את לוגיקת הניתוב. זה מפריד את כללי הניתוב מיישום ה-proxy.
אבטח namespace על ידי מניעת כל תעבורת Ingress כברירת מחדל.
צור `NetworkPolicy` אשר בוחר את כל ה-pods (`podSelector: {}`) ומציין כלל Ingress ריק (`ingress: []`).
למה: ברגע ש-pod נבחר על ידי כל NetworkPolicy, כל תעבורה שלא אושרה במפורש נמנעת. מדיניות הבוחרת את כל ה-pods עם כלל Ingress ריק יוצרת למעשה חומת אש "מנע הכל" עבור ה-namespace.
אפשר ל-pods ב-namespace "frontend" לגשת ל-pods ב-namespace "backend".
ב-namespace "backend", צור NetworkPolicy. בכלל `ingress.from`, השתמש ב-`namespaceSelector` כדי להתאים תוויות (labels) על משאב ה-`Namespace` "frontend".
למה: `podSelector` פועל רק בתוך ה-namespace של המדיניות. כדי לאפשר תעבורה מ-namespaces אחרים, עליך להשתמש ב-`namespaceSelector`. זה דורש תיוג (labeling) של אובייקטי ה-`Namespace` עצמם.
יישום צריך להתחבר לשירות אחר בתוך האשכול.
השתמש בשם ה-DNS הפנימי של השירות: `<service-name>.<namespace>.svc.cluster.local`. אם באותו namespace, `<service-name>` מספיק.
למה: Kubernetes מספק גילוי שירות יציב מבוסס DNS באמצעות CoreDNS. זה מפריד בין יישומים לבין כתובות IP ספציפיות של pods, שהן ארעיות.
יישום Stateful (לדוגמה, מערך רפליקות של מסד נתונים) דורש זהות רשת ישירה עבור כל pod.
צור `Service` מסוג headless (`clusterIP: None`) עבור ה-`StatefulSet`. זה מספק רשומות DNS A ייחודיות עבור כל pod (לדוגמה, `pod-0.my-service.my-ns...`).
למה: שירות headless אינו מאזן עומסים. במקום זאת, הוא מספק רשומות DNS עבור כל pod, ומאפשר ללקוחות להתחבר למופעים ספציפיים, דבר חיוני לבחירת מנהיג או גילוי עמיתים במערכות stateful.
שירות הפונה כלפי חוץ צריך לראות את כתובת ה-IP המקורית של הלקוח לצורך רישום לוגים או סינון מבוסס IP.
הגדר `externalTrafficPolicy: Local` בשירות ה-`NodePort` או ה-`LoadBalancer`.
למה: מדיניות ה-`Cluster` המוגדרת כברירת מחדל מטשטשת את IP הלקוח באמצעות SNAT. `Local` מונע קפיצת רשת נוספת זו על ידי ניתוב תעבורה רק ל-pods בצומת שקיבל את התעבורה, ובכך משמר את IP המקור.
עומסי עבודה ותזמון
מקם pods יחד או פזר אותם למען ביצועים או זמינות גבוהה.
השתמש ב-`podAffinity` כדי לתזמן pods באותו צומת/אזור כמו pods ספציפיים אחרים. השתמש ב-`podAntiAffinity` כדי למנוע את תזמונם יחד.
למה: זה מספק בקרת תזמון מתקדמת יותר מאשר affinity ברמת הצומת. Anti-affinity עם `requiredDuringScheduling...` חיוני לפיזור רפליקות של שירות על פני צמתים או אזורים עבור HA.
הקצה צמתים לעומסי עבודה ספציפיים או מנע מעומסי עבודה מסוימים לרוץ עליהם.
החל `taint` על צומת (לדוגמה, `gpu=true:NoSchedule`). הוסף `toleration` תואם ל-pods שאמורים להיות מורשים לרוץ על אותו צומת.
למה: Taints דוחים pods, בעוד tolerations מאפשרים להם. זהו המנגנון העיקרי להקצאת צמתים. אפקט `NoExecute` יפנה pods שכבר פועלים שאין להם את ה-toleration.
פרוס סוכן ניטור או רישום לוגים בכל צומת באשכול.
השתמש ב-`DaemonSet`. הוא מבטיח שעותק של ה-pod ירוץ על כל צומת התואם את קריטריוני התזמון שלו.
למה: DaemonSet תוכנן בדיוק למטרה זו. הוא נפרס אוטומטית לצמתים חדשים ומטפל בניהול pods ברמת הצומת, דבר שיהיה קשה עם Deployment.
הרץ משימת אצווה חד-פעמית או משימה מתוזמנת חוזרת.
השתמש ב-`Job` עבור משימה הפועלת פעם אחת עד לסיומה. השתמש ב-`CronJob` כדי ליצור Jobs בלוח זמנים חוזר (לדוגמה, גיבויים ליליים).
למה: Jobs מבטיחים ש-pods יפעלו עד למספר השלמות שצוין. CronJobs הם בקר ברמה גבוהה יותר המנהל Jobs בהתבסס על לוח זמנים של cron.
עדכן יישום לגרסה חדשה ללא זמן השבתה (downtime).
השתמש ב-`Deployment` עם אסטרטגיית `RollingUpdate` המוגדרת כברירת מחדל. הגדר `maxSurge` ו-`maxUnavailable` כדי לשלוט במהירות העדכון ובזמינות.
למה: עדכוני Rolling מחליפים בהדרגה pods ישנים בחדשים, ומבטיחים שהשירות יישאר זמין. `maxUnavailable` מבטיח שמספר מינימלי של pods פועל, בעוד ש-`maxSurge` מאפשר חריגה ממספר הרפליקות הרצוי כדי לזרז את הפריסה.
ודא ש-pods מקבלים משאבים מובטחים ואינם צורכים משאבים מוגזמים בצומת.
הגדר `resources.requests` (CPU/זיכרון) כדי להבטיח מינימום לתזמון. הגדר `resources.limits` כדי למנוע מ-container לחרוג מכמות מסוימת.
למה: Requests משמשים את המתזמן למיקום ומבטיחים משאבים. Limits נאכפים על ידי ה-kubelet וזמן הריצה של ה-container; חריגה ממגבלת הזיכרון גורמת ל-OOMKill.
פרוס יישום stateful הדורש מזהי רשת יציבים וייחודיים ואחסון קבוע לכל רפליקה.
השתמש ב-`StatefulSet` עם `volumeClaimTemplate`. זה יוצר `PersistentVolumeClaim` ייחודי עבור כל pod, ומבטיח שהנתונים יצורפו מחדש לאותה זהות של ה-pod בעת הפעלה מחדש.
למה: StatefulSets מספקים שמות pods יציבים (לדוגמה, `web-0`, `web-1`) ו-PVC ייחודי וקבוע עבור כל אחד. זה חיוני ליישומים המסתמכים על זהות ואחסון יציבים.
אחסון
ספק אחסון קבוע ליישום ללא הקצאת נפחים מראש.
צור `StorageClass` המגדיר provisioner אחסון. לאחר מכן, צור `PersistentVolumeClaim` (PVC) המבקש אחסון מאותה מחלקה. `PersistentVolume` (PV) יוקצה באופן דינמי.
למה: זה מפריד בין יישומים לבין תשתית האחסון הבסיסית. מפתחים מבקשים אחסון באמצעות PVCs, ומנהל האשכול מגדיר כיצד אחסון זה מוקצה באמצעות StorageClasses.
שלוט במה שקורה ל-volume קבוע לאחר מחיקת ה-claim שלו.
הגדר `persistentVolumeReclaimPolicy` ב-PV או ב-StorageClass. `Delete` מוחק אוטומטית את האחסון הבסיסי. `Retain` משאיר את ה-volume והנתונים שלמים, הדורש ניקוי ידני.
למה: `Retain` היא האפשרות הבטוחה ביותר עבור נתוני ייצור, מכיוון שהיא מונעת אובדן נתונים מקרי. `Delete` נוחה עבור סביבות ארעיות או פיתוח. ברירת המחדל תלויה ב-provisioner.
הגדר כיצד volume יכול להיות מותקן על ידי pods.
השתמש ב-`accessModes`: `ReadWriteOnce` (RWO) לכתיבה-קריאה בצומת יחיד, `ReadOnlyMany` (ROX) לקריאה בלבד בצמתים מרובים, `ReadWriteMany` (RWX) לכתיבה-קריאה בצמתים מרובים.
למה: מצב הגישה חייב להיות נתמך על ידי ספק האחסון הבסיסי. אי התאמה בין צרכי היישום (לדוגמה, צורך ב-RWX) לבין יכולות האחסון (תמיכה רק ב-RWO) היא גורם נפוץ ל-PVCs במצב Pending.
הזרק קבצי תצורה או נתונים רגישים ל-pod.
התקן `ConfigMap` או `Secret` כ-volume. כל מפתח באובייקט הנתונים הופך לקובץ בנתיב ההתקנה.
למה: זוהי הדרך הסטנדרטית לספק תצורה ל-pods. היא מאפשרת לנהל תצורה כאובייקט Kubernetes ולעדכן אותה באופן עצמאי מתמונת ה-pod.
יישום זקוק ליותר שטח אחסון ב-volume הקבוע הקיים שלו.
ודא של-`StorageClass` יש `allowVolumeExpansion: true`. ערוך את ה-`PVC` כדי לבקש גודל גדול יותר ב-`spec.resources.requests.storage`.
למה: הרחבת volume היא תכונה הניתנת לבחירה. ה-StorageClass חייבת לאפשר אותה במפורש, ומנהל ה-CSI הבסיסי חייב לתמוך בה. ייתכן שיהיה צורך להפעיל מחדש את ה-pod כדי שגודל מערכת הקבצים ישתנה.
פתרון תקלות
pod תקוע במצב `Pending` ואינו מתוזמן.
הרץ `kubectl describe pod <pod-name>`. בדוק את קטע ה-`Events` עבור הודעות מהמתזמן.
למה: פקודת ה-`describe` היא הכלי העיקרי לכך. היא תציג סיבות כגון "Insufficient cpu/memory", "node(s) had taints the pod didn't tolerate", או "didn't match node selector".
pod מופעל ונכשל שוב ושוב, עם סטטוס `CrashLoopBackOff`.
1. `kubectl logs <pod-name> --previous` כדי לראות את הלוגים מה-container שקרס. 2. `kubectl describe pod <pod-name>` כדי לבדוק את קוד היציאה והסיבה.
למה: `CrashLoopBackOff` פירושו שהיישום בתוך ה-container יוצא. הלוגים מהמופע הקודם (`--previous`) חיוניים, מכיוון שה-container הנוכחי אולי עדיין לא רשם שום דבר שימושי. קוד היציאה יכול גם להצביע על סוג השגיאה.
pod נכשל בהפעלה עם סטטוס `ImagePullBackOff` או `ErrImagePull`.
`kubectl describe pod <pod-name>` כדי לראות את הודעת האירוע. ודא ששם התמונה וה-tag נכונים. עבור registries פרטיים, ודא ש-`imagePullSecrets` מוגדר ושה-secret תקף.
למה: זוהי בעיה ב-registry או בשם התמונה, לא בעיה ביישום. סיבות נפוצות הן שגיאות כתיב, tags שגויים, או כשל באימות מול registry פרטי.
לצומת יש סטטוס `NotReady`.
התחבר ב-SSH לצומת המושפע. בדוק את סטטוס שירות ה-kubelet עם `systemctl status kubelet`. צפה בלוגים שלו עם `journalctl -u kubelet`.
למה: ה-`kubelet` הוא הסוכן האחראי על דיווח מצב תקינות הצומת. אם הוא מושבת או אינו יכול לתקשר עם ה-API server, הצומת יסומן כ-NotReady. הלוגים שלו הם המקום הראשון לבדוק.
שירות קיים, אך התעבורה אינה מגיעה ל-pods בקצה האחורי.
1. `kubectl describe svc <service-name>` וודא שה-`Selector` תואם את תוויות ה-pod. 2. `kubectl get endpoints <service-name>` וודא שהוא מפרט את כתובות ה-IP הנכונות של ה-pods. אם לא, התוויות אינן תואמות.
למה: הקישור בין שירות ל-Pods שלו הוא ה-label selector. אם ה-selector שגוי או ל-pods אין את התוויות הנכונות, אובייקט ה-Endpoints יהיה ריק, ולשירות לא תהיה לאן לנתב תעבורה.
Pods אינם מסוגלים לפתור שמות שירותים או שמות מארחים חיצוניים.
1. בדוק אם CoreDNS pods פועלים ב-`kube-system`. 2. בדוק את לוגי CoreDNS. 3. הרץ pod אבחון (לדוגמה, `busybox`) והשתמש ב-`nslookup` כדי לבדוק פתרון מתוך האשכול.
למה: DNS הוא תלות קריטית באשכול. כשלים מתחקות בדרך כלל לפריסת CoreDNS עצמה, לתצורה שלה (ב-ConfigMap), או למדיניות רשת החוסמת תעבורת DNS בפורט UDP/TCP 53.
יש להוריד צומת לא מקוון לצורך תחזוקה.
ראשית, `kubectl cordon <node-name>` כדי לסמן אותו כבלתי ניתן לתזמון. לאחר מכן, `kubectl drain <node-name> --ignore-daemonsets` כדי לפנות בבטחה את כל ה-pods של המשתמשים.
למה: `cordon` מונע תזמון של pods חדשים. `drain` מכבד את PodDisruptionBudgets ומפנה pods בחן. `--ignore-daemonsets` נדרש מכיוון ש-DaemonSet pods אינם ניתנים לפינוי.
זהה אילו pods או nodes צורכים את מירב ה-CPU או הזיכרון.
השתמש ב-`kubectl top pods` וב-`kubectl top nodes`. זה דורש ש-`metrics-server` יהיה פרוס באשכול.
למה: `kubectl top` מספק תצוגה מהירה, בזמן אמת, של צריכת משאבים, חיונית לזיהוי יישומים רעבים למשאבים או לחץ על משאבי הצומת.
pod נמצא במצב `Terminating` במשך זמן רב ואינו מוסר.
מחק בכוח את ה-pod עם `kubectl delete pod <pod-name> --grace-period=0 --force`.
למה: זה יכול לקרות אם finalizer תקוע או שה-kubelet אינו יכול לנקות משאבים. מחיקה בכוח מסירה את ה-pod משרת ה-API באופן מיידי, אך יש להשתמש בה כמוצא אחרון מכיוון שהיא עלולה להשאיר משאבים יתומים בצומת.