במסמך הזה מוסבר איך לאבחן בעיות ברשת באשכולות של Google Kubernetes Engine (GKE) באמצעות יכולת הצפייה של GKE Dataplane V2, Hubble ו-Cloud Monitoring.
לסקירה כללית של הארכיטקטורה ושיטות מומלצות, קראו את המאמר שיטות מומלצות לתצפית על הרשת.
עץ החלטות לפתרון בעיות ומושגי ליבה
לפני שתעיינו בהליכים, השתמשו במטריצת ההחלטות הבאה כדי לזהות איזו שכבה במקבץ הרשת של GKE כנראה גורמת לבעיה, ועברו לקטע המתאים.
| שאלה לאבחון או תיאור של הבעיה | רמת החשד | ההליך המומלץ |
|---|---|---|
ה-Pods לא מצליחים לפתור דומיינים חיצוניים או שירותי Kubernetes פנימיים (פסקי זמן קצובים של DNS, NXDOMAIN, SERVFAIL). |
רמה 1: Pod ושירות (DNS) | אבחון כשלים בפענוח DNS |
| השירותים לא יכולים לתקשר, יש זמן קצוב לתפוגה של החיבור או שחבילות נתונים נמחקות בין Pods. | רמה 1: Pod ושירות (מדיניות או אובדן מנות) | אבחון של אובדן חבילות וחסימות של NetworkPolicy |
עומס התנועה ברפליקות של עומס העבודה לא אחיד, או שיש שיעור גבוה של איפוסים של TCP (RST) ביומנים של Pods. |
רמה 1: Pod ושירות (איזון עומסים או העברה) | אבחון של חוסר איזון בתנועה ואיפוסים של TCP |
| זמן אחזור כללי, פסקי זמן לסירוגין או הפעלות מחדש של CNI בצמתים. | רמה 2: צומת ו-CNI (ליבה) | מיון לפי זמן אחזור ברמת הצומת וצווארי בקבוק של CNI |
| פודים לא יכולים להגיע למשאבים מחוץ ל-GKE (כמו Cloud SQL, ממשקי API חיצוניים או רשתות VPC אחרות). | רמה 3: VPC וניתוב | בידוד בעיות ב-GKE לעומת בעיות ב-VPC או בקישוריות חיצונית |
| צריך הדמיית נתיב אוטומטית כדי לוודא אם כללי חומת האש, הנתיבים או NetworkPolicies חוסמים את התנועה. | רמה 3: VPC וניתוב (סימולציה) | אבחון הקישוריות באמצעות בדיקות קישוריות |
| צריך לזהות אילו עומסי עבודה שולחים תנועה לאינטרנט ועוברים NAT. | רמה 4: שער חיצוני ועלות | זיהוי תנועת NAT (תעבורת נתונים יוצאת לאינטרנט) |
| עלויות גבוהות של העברת נתונים בין אזורים, או צורך להציג באופן חזותי את המשתמשים שיוצרים הכי הרבה תעבורת נתונים בלי לכתוב שאילתות SQL. | רמה 4: שער חיצוני ועלות | ניתוח העלויות והביצועים של תנועת הנתונים באשכול באמצעות Flow Analyzer |
מושגי ליבה בנושא רשתות
אם אתם חדשים ב-Kubernetes או ברשתות של Google Cloud , חשוב לזכור את מושגי הליבה הבאים:
- eBPF (מסנן חבילות מורחב של ברקלי): טכנולוגיה של מערכת הפעלה שמאפשרת להריץ תוכניות מאובטחות של ניטור לצורכי אבטחה וניתוב ישירות בתוך ליבת Linux. GKE Dataplane V2 משתמש ב-eBPF כדי לנתב חבילות ולאכוף את NetworkPolicies עם תקורה מינימלית של ביצועים.
- הסתרת IP (SNAT): התהליך של כתיבה מחדש של כתובת ה-IP של המקור של חבילת נתונים. כש-Pod של GKE (שיש לו כתובת IP פרטית) מתקשר עם האינטרנט או עם משאבי VPC חיצוניים, GKE מסווה (משכתב) את כתובת ה-IP של ה-Pod לכתובת ה-IP של הצומת, כדי שמערכות חיצוניות יידעו איך לנתב את התשובה.
- מעקב אחרי חיבורים (Conntrack): תכונה של הליבה שעוקבת אחרי כל החיבורים הפעילים לרשת. באשכולות של GKE Dataplane V2, המעקב הזה מפוצל בין שתי טבלאות: טבלת conntrack הרגילה של ליבת Linux (שמשמשת את
ip-masq-agent) וטבלת conntrack שמנוהלת על ידי Cilium ו-GKE Dataplane V2, שמאוחסנת במפת eBPF. אם צומת מטפל ביותר מדי חיבורים בו-זמנית, אחת מטבלאות המעקב האלה יכולה להתמלא (מיצוי conntrack), מה שגורם לצומת להשמיט חבילות חדשות בלי להודיע על כך. - Hubble: מנוע התצפיתיות של GKE Dataplane V2. הוא פועל על גבי eBPF ומספק תצוגה בזמן אמת של זרימת התנועה, חבילות שנמחקו והערכה של NetworkPolicy.
רמה 1: ניטור Pod ו-Service (אפליקציה)
שכבת ה-Pod והשירות כוללת תקשורת רשת בין Pods, שירותים ו-DNS של אשכולות. בעיות בשכבה הזו בדרך כלל מתבטאות בפסקי זמן קצובים של חיבור לאפליקציה, כשלים בתרגום שם (name resolution) או חלוקת עומסים לא אחידה.
אבחון כשלים בפענוח DNS
לפני שפותרים בעיות ב-DNS, צריך לבדוק את היקף האבחון ואת הדרישות המוקדמות:
- תחום המיקוד: תקשורת בין Pods לבין CoreDNS או NodeLocal DNSCache, זמן אחזור של DNS, זמן קצוב לתפוגה של פענוח DNS במעלה הזרם ואימות של FQDN NetworkPolicy.
- דרישות מוקדמות: הפעלת המדדים של GKE Dataplane V2; גישה ל-
kubectl. - תאימות ל-CNI: GKE Dataplane V2 (נתיב נתונים מתקדם) ו-GKE CNI רגיל.
- תיאור הבעיה: ביומני ה-Pod מופיעות השגיאות
dial tcp: lookup <domain>: i/o timeout,NXDOMAINאו זמן אחזור לסירוגין בקריאות ל-API יוצאות. - המטרה: לבדוק אם מקור הכשל ב-DNS הוא בתוך האשכול (
kube-dnsאו רוויה של NodeLocal DNSCache), חסימה של יציאת UDP או TCP 53 על ידי NetworkPolicy, או פגיעה ברשת במעלה הזרם.
שלב 1: בדיקת נגישות בסיסית
לפני שפותרים בעיות בשכבות DNS, צריך לוודא שאפשר להגיע ליעד ישירות באמצעות כתובת ה-IP שלו מתוך ה-Pod המושפע:
# 1. Test raw IP reachability (bypasses DNS entirely)
kubectl exec -it my-pod -n default -- curl -v --connect-timeout 5 http://10.240.0.10:8080
# 2. Test domain resolution
kubectl exec -it my-pod -n default -- curl -v --connect-timeout 5 http://my-service.default.svc.cluster.local:8080
- אם קישור דרך IP מצליח אבל החיבור לדומיין נכשל: הבעיה מבודדת לשכבת פענוח ה-DNS. עוברים לשלב 2.
- אם שתי הבדיקות נכשלות: הבעיה היא בניתוב או באכיפת המדיניות ברמת הרשת. עוברים לקטע אבחון של אובדן חבילות וחסימות של NetworkPolicy.
בדיקה אם יש אכלוס מראש של DNS ב-NetworkPolicy FQDN
אם באשכול שלכם נעשה שימוש ב-NetworkPolicies שמבוססות על FQDN (FQDNNetworkPolicy), ודאו ששם הדומיין מותר באופן מפורש. אם Pod שולח שאילתה לדומיין חיצוני שלא מאוכלס מראש במטמון של שרת ה-proxy ל-DNS של GKE Dataplane V2, או שלא מותר לפי המדיניות, GKE Dataplane V2 חוסם את תעבורת הנתונים היוצאת לכתובת ה-IP שנפתרה:
# Verify whether UDP or TCP port 53 egress is permitted in the Pod's namespace
kubectl get networkpolicy -n default -o yaml | grep -A 5 -B 2 "port: 53"
שלב 2: בדיקת מדדי DNS ב-Cloud Monitoring
ב-GKE, מדדי ה-DNS המובנים מוצגים ב-Cloud Monitoring עם הקידומת kubernetes.io/networking/dns/.
כדי לבדוק את מדדי ה-DNS ב-Cloud Monitoring:
- במסוף Google Cloud , נכנסים לדף Cloud Monitoring > Dashboards.
- בוחרים את מרכז הבקרה המוגדר מראש GKE DNS Observability - Cluster View (או עוברים אל Metrics Explorer ומסננים לפי
kubernetes.io/networking/dns/). - בודקים את האותות העיקריים הבאים (ב-NodeLocal DNSCache, מחליפים את
kubednsב-node_local_dnsבנתיב המדד):
| שם המדד | סף האזהרה | שורש הבעיה |
|---|---|---|
kubernetes.io/networking/dns/kubedns/max_concurrent_rejected_request_count |
> 0 | הגעת למגבלת השאילתות בו-זמנית. kube-dns או NodeLocal DNSCache מבטלים שאילתות. |
kubernetes.io/networking/dns/kubedns/dns_request_latencies |
p99 > 100ms | זמן אחזור ארוך מקצה לקצה של פענוח DNS ב-kube-dns או ב-NodeLocal DNSCache. |
kubernetes.io/networking/dns/kubedns/forwarding_request_latencies |
p99 > 100ms | זמן אחזור או רוויה של שרת DNS במעלה הזרם. |
רצף טריאז' של ביצועי DNS וזמן קצוב לתפוגה
כדי לאבחן זמן אחזור של DNS, אי מציאה במטמון וזמנים קצובים לתפוגה במעלה הזרם, צריך לפעול לפי רצף השלבים הבא:
- בדיקת שיעור המציאות במטמון (cache hit): שאילתה ל-
kubernetes.io/networking/dns/kubedns/dns_cache_request_count(או ל-node_local_dns/dns_cache_request_count) מקובצת לפי התוויתcache_status. אם הערך שלcache_status="hit"נמוך והערך שלcache_status="miss"גבוה, יכול להיות שהאפליקציות שולחות שאילתות שהן לא FQDN (למשלmy-serviceבמקוםmy-service.default.svc.cluster.local), מה שגורם למעבר בנתיב החיפוש בכל הרשומות ב-/etc/resolv.conf. - בדיקת זמן האחזור במעלה הזרם: ערך גבוה של
forwarding_request_latenciesמצביע על בעיות בשרת ה-DNS במעלה הזרם (לדוגמה, DNS מקומי של הארגון שאליו מגיעים דרך Cloud Interconnect או Cloud VPN, או מגבלות של Cloud DNS). ביקורת על שינויים בהתאמה אישית של DNS: בודקים את ה-ConfigMaps של
kube-dnsבהתאמה אישית כדי לאתר הגדרות שגויות של סטאבים או העברות במעלה הזרם:kubectl get configmap kube-dns -n kube-system -o yaml
שלב 3: סטרימינג של תנועת DNS בזמן אמת באמצעות Hubble CLI
משתמשים בשם הסודי של כלי העזר של Hubble CLI כדי לבדוק בקשות ותשובות של DNS בשידור חי, שמועברות בסטרימינג מהקרנל של הצומת:
# 1. Ensure the helper alias is set in your terminal session
alias gke-hubble="kubectl exec -it -n gke-managed-dpv2-observability deployment/hubble-relay -c hubble-cli -- hubble"
# 2. Observe live DNS (Port 53) traffic for a specific Pod
gke-hubble observe --pod default/my-pod --port 53
שלב 4: מאמתים את התיקון
אם היו דחיות של שאילתות בו-זמניות, צריך להחיל את NodeLocal DNSCache כדי לספוג חיפושי DNS בתדירות גבוהה ישירות בצומת, בלי להגיע למגבלות של kube-dns ברמת האשכול:
# Verify NodeLocal DNSCache DaemonSet is running
kubectl get daemonset node-local-dns -n kube-system
אבחון של אובדן חבילות וחסימות של NetworkPolicy
לפני שבודקים את דחיות המדיניות והחבילות שנמחקו, צריך לבדוק את היקף האבחון ואת הדרישות המוקדמות:
- תחום התמקדות: ירידה בתנועה בין אובייקטים של Pod או בין אובייקטים של Pod ו-Service, אכיפת NetworkPolicy, סיבות לירידה ב-eBPF של הליבה.
- דרישות מוקדמות: הפעלה של GKE Dataplane V2 Flow Observability; הגדרה של רישום ביומן של NetworkPolicy.
- תאימות ל-CNI: רק GKE Dataplane V2.
- התופעה: ניסיונות החיבור של האפליקציה נכשלים עם השגיאה
Connection timed outאוConnection reset by peer. - המטרה: לאתר את הסיבה המדויקת להשמטת החבילות ב-NetworkPolicy או ב-eBPF, בלי לבצע שינויים במדיניות האבטחה בשיטת ניסוי וטעייה.
שלב 1: מעקב אחר מדדי הירידה של Hubble
כש-GKE Dataplane V2 משמיט חבילה, הוא פולט את המדד hubble_drop_total עם תיוג של סיבת ההשמטה והמטא-נתונים של המקור והיעד. כדי לעקוב אחרי מדדי הנפילה של Hubble, מבצעים את הפעולות הבאות:
אם עדיין לא עשיתם את זה, פורסים משאב של השירות המנוהל של Google Cloud ל-Prometheus
PodMonitoringכדי לאסוף מדדים של Hubble:apiVersion: monitoring.googleapis.com/v1 kind: PodMonitoring metadata: name: hubble-metrics namespace: gke-managed-dpv2-observability spec: selector: matchLabels: k8s-app: cilium endpoints: - port: hubble-metrics interval: 30sכדי לראות את הירידות לפי סיבה, מריצים את השאילתה הבאה ב-Cloud Monitoring > Metrics Explorer:
sum by (reason) (rate(hubble_drop_total[5m])) > 0הסבר על קודי
reasonהנפוצים:-
Policy denied: מדיניות NetworkPolicy של Kubernetes חוסמת את החיבור באופן מפורש או משתמע. CT: Map insertion failed: טבלת מעקב החיבורים (conntrack) מלאה.-
Unsupported L3 protocol: חבילת נתונים שהיא לא IPv4 או IPv6, או כותרת פגומה.
-
שלב 2: בדיקת היומנים של NetworkPolicy ב-Cloud Logging
רישום ביומן של NetworkPolicy מייצא יומני JSON מובְנים לכל ההחלטות לגבי המדיניות. כדי לשלוח שאילתה ליומני NetworkPolicy ב-Cloud Logging:
- במסוף Google Cloud , נכנסים לדף Cloud Logging > Logs Explorer.
מריצים את השאילתה הבאה:
resource.type="k8s_node" log_name:"projects/PROJECT_ID/logs/events" jsonPayload.connection.verdict="DENY" jsonPayload.src.pod_name="my-source-pod"בודקים את המטען הייעודי (payload) של ה-JSON:
-
jsonPayload.drop_reason: הסיבה שבגללה החבילה נמחקה. -
jsonPayload.policies: רשימה של כללי NetworkPolicy שנבדקו. אם מוחזרת רשימה ריקה עם פסיקתDENY, מרחב השמות פועל במצב דחייה כברירת מחדל, ואף מדיניות לא מאפשרת את התנועה.
-
אם לא מופיעים יומני NetworkPolicy, צריך לוודא שהרישום ביומן מופעל במשאב המותאם אישית NetworkLogging של האשכול. לדוגמה, בודקים שהשדה spec.cluster.deny.log מוגדר ל-true:
kubectl get networklogging default -o yaml
שלב 3: מעקב אחרי חבילות שנזרקו בזמן אמת באמצעות Hubble CLI
אפשר להעביר בסטרימינג חבילות שנמחקו בזמן אמת באמצעות Hubble CLI כדי לבדוק אותן:
gke-hubble observe --verdict DROPPED --namespace default --follow
פלט לדוגמה:
TIMESTAMP SOURCE DESTINATION TYPE VERDICT
10:14:22.102 default/frontend default/backend:80 to-stack DROPPED (Policy denied by NetworkPolicy: backend-deny-all)
הפלט מציין את ה-NetworkPolicy המדויק שחוסם את התנועה (backend-deny-all).
שלב 4: בודקים אם יש ניצול יתר של conntrack
אם הסיבה להסרה היא CT: Map insertion failed:
בודקים את יומן הפעילות של הסוכן של GKE Dataplane V2 כדי לראות אם טבלת conntrack בניצול מלא:
kubectl logs -n kube-system daemonset/anetd -c cilium-agent --tail=100 | grep "Conntrack table full"בודקים את הגודל המקסימלי של טבלת ה-conntrack בצומת המושפע:
kubectl exec -it -n kube-system daemonset/anetd -c cilium-agent -- cilium status --all-controllers | grep -i conntrackאם טבלת conntrack מלאה, צריך להרחיב אופקית את עומסי העבודה על פני יותר צמתים או להפחית את קצב החיבורים מ-Pods של לקוחות.
אבחון חוסר איזון בתנועה ואיפוסים של TCP
לפני שפותרים בעיות של חוסר איזון בתנועה ואיפוסים של חיבורים, צריך לבדוק את היקף האבחון ואת הדרישות המוקדמות:
- תחום המיקוד: חוסר איזון בעומסים, כשלים בלחיצת היד של TCP, ניתוק פתאומי של החיבור.
- דרישות מוקדמות: הפעלת המדדים של GKE Dataplane V2.
- תאימות ל-CNI: GKE Dataplane V2.
- התופעה: רפליקות מסוימות של Pod מקבלות תנועה מוגזמת, ואחרות נשארות במצב חוסר פעילות. אפליקציות הלקוח מתעדות ביומן את השגיאות
connection reset by peerאוbroken pipe. - המטרה: להבין אם חוסר האיזון בתנועה נגרם בגלל חיבורים דביקים בשכבת התעבורה (שכבה 4 של OSI, TCP) או בשכבת האפליקציה (שכבה 7 של OSI, HTTP/2 או gRPC), ולזהות את המקור של חבילות ה-TCP RST.
שלב 1: השוואה בין זרימת התנועה ברמת ה-Pod
כדי לבדוק אם התנועה מפוזרת באופן שווה בין הרפליקות:
ב-Cloud Monitoring, שולחים שאילתה לגבי מספר תזרימי התעבורה הנכנסת בכל ה-Pods ב-Deployment:
sum by (pod) (rate(pod_flow_ingress_flows_count{destination_workload="my-service"}[5m]))הערכת חלוקת התנועה בין ה-Pods. אם Pod אחד מקבל את רוב התנועה, צריך לבדוק אם יש שימוש חוזר בחיבור או סשנים דביקים:
- gRPC או HTTP/2: חיבורי TCP לטווח ארוך גורמים לכל הבקשות לעבור ב-TCP stream אחד ל-Pod אחד בקצה העורפי. ניתוב של שירות Kubernetes בשכבת התעבורה (שכבה 4 של OSI, TCP) לא יכול לאזן בקשות בתוך חיבור HTTP/2 קיים.
- ClientIP Session Affinity: בודקים אם השירות מוגדר עם
sessionAffinity: ClientIP. - שירותים ללא ממשק משתמש: יכול להיות שהלקוחות יפתרו את ה-DNS פעם אחת וישמרו במטמון את כתובת ה-IP היחידה באופן קבוע.
שלב 2: ניתוח מדדי איפוס TCP
איפוסים של TCP (RST) מסיימים את החיבורים באופן מיידי. הם נשלחים על ידי ליבת מערכת ההפעלה כשנקודת קצה מקבלת חבילה ליציאה לא ידועה, או כשאפליקציה סוגרת חיבור עם נתונים שלא נקראו במאגר הנתונים הזמני.
מריצים את שאילתת ה-MQL הבאה ב-Cloud Monitoring:
fetch prometheus_target
| metric 'prometheus.googleapis.com/hubble_tcp_flags_total/counter'
| filter (metric.flag == 'RST')
| align rate(1m)
| every 1m
| group_by [metric.source, metric.destination, metric.traffic_direction], sum(val())
בודקים את תוצאות השאילתה כדי לזהות את מקור האיפוס:
- Outgoing RST (traffic_direction=
egress): ה-Pod המקומי יוצר את האיפוס. בודקים אם אפליקציית ה-Pod קורסת, מגיעה למגבלת החיבורים או דוחה את החיבור באופן פעיל. - Incoming RST (traffic_direction=
ingress): המחשב המרוחק (מסד נתונים חיצוני, API או Pod מרוחק) שלח את האיפוס. בודקים את התקינות של שרת היעד ואת המצבים של חומת האש.
שלב 3: שידור חי של איפוסים של TCP
משתמשים ב-Hubble CLI כדי לתעד את לחיצת היד של האיפוס בזמן אמת:
gke-hubble observe --type trace --verdict FORWARDED --tcp-flags RST --namespace default
שלב 4: תיקון ופעולות לביצוע
כדי לפתור את הבעיה, בצעו את השלבים הבאים בהתאם לסיבה לחוסר האיזון בתנועה או לאיפוסים של ה-TCP:
- לשמירת החיבור בשכבת האפליקציה (שכבה 7 של OSI) או ב-gRPC:
- פורסים את Cloud Service Mesh כדי להפעיל איזון עומסים ברמת הבקשה בשכבת האפליקציה (שכבה 7 של OSI).
- מגדירים מגבלות חיבור בצד הלקוח או זמן קצוב לתפוגה של keep-alive (לדוגמה,
MAX_CONNECTION_AGEו-MAX_CONNECTION_AGE_GRACEשל gRPC) כדי לאלץ חידוש תקופתי של החיבור.
- לשיוך כתובת IP של שירות: מסירים את
service.spec.sessionAffinity, אלא אם מצב האפליקציה מחייב זאת. - לשמירת DNS במטמון של שירות ללא ממשק משתמש: ודאו שסביבות זמן הריצה של האפליקציה (כמו JVM
networkaddress.cache.ttl) לא שומרות במטמון תוצאות DNS ללא הגבלת זמן. - במקרה של גלישת תור של בקשות ממתינות באפליקציה: כשתור ההאזנה של האפליקציה מלא, ליבת Linux משמיטה חבילות SYN נכנסות או שולחת TCP RST. להרחיב אופקית את הרפליקות של Pod או להגדיל את ה-backlog של האזנה לאפליקציה (
somaxconn).
רמה 2: ניראות של צומת ו-CNI (ליבה)
שכבת הצומת ו-CNI כוללת את ליבת ה-Linux של המארח, תוכניות eBPF וממשקי רשת של הצומת. צווארי בקבוק בשכבה הזו משפיעים על כל עומסי העבודה שפועלים בצומת המושפע.
בדיקת תקינות המערכת: זיהוי תיקונים לא מורשים של anetd
GKE Dataplane V2 פועל כ-DaemonSet מנוהל (anetd) במרחב השמות kube-system. ב-Cloud Logging, אתם יכולים לשלוח שאילתות ליומני הביקורת של Kubernetes כדי לזהות אם משתמשים לא מורשים או סקריפטים אוטומטיים תיקנו או הפעילו מחדש את anetd:
protoPayload.methodName="io.k8s.core.v1.daemonsets.patch" OR
protoPayload.methodName="io.k8s.core.v1.daemonsets.update"
protoPayload.resourceName="namespaces/kube-system/daemonsets/anetd"
אם מזוהה תיקון לא מורשה, צריך להחזיר את DaemonSet להגדרת ברירת המחדל או להפעיל יצירה מחדש של מאגר צמתים כדי לשחזר את המצב המנוהל.
מיון בעיות שקשורות לזמן אחזור ברמת הצומת ולצווארי בקבוק ב-CNI
לפני שמאבחנים את זמן האחזור ברמת הצומת ואת צווארי הבקבוק בקרנל, צריך לבדוק את היקף האבחון ואת הדרישות המוקדמות:
- תחום המיקוד: זמן האחזור של ליבת המארח, חבילות שנזרקות בממשק של המכונה הווירטואלית, רוויה של סוכן eBPF ב-GKE Dataplane V2, מיצוי של conntrack.
- דרישות מוקדמות: הפעלת מדדי VM של Compute Engine, גישה ל-
kubectl. - תאימות ל-CNI: GKE Dataplane V2 ו-GKE CNI רגיל.
- התופעה: בתעבורת הנתונים בין צמתים יש עליות חדות בזמן האחזור או ירידות אקראיות, אבל תעבורת הנתונים בתוך הצומת תקינה.
- המטרה: להבחין בין הגבלת רוחב פס של רשת ה-VM המארחת, השמטות של ליבת Linux וצווארי בקבוק ברמת ה-CNI.
שלב 1: הבחנה בין בעיות מחוץ ל-GKE לבין בעיות בתוך GKE
מריצים את בדיקת הבסיס של המכונה הווירטואלית ב-Compute Engine: פורסים מכונה וירטואלית נפרדת ב-Compute Engine באותה רשת משנה של VPC כמו הצמתים באשכול GKE. בודקים את הקישוריות מה-VM ליעד.
- אם במכונה הווירטואלית העצמאית יש את אותן בעיות של אובדן חבילות או זמן אחזור: הבעיה נמצאת מחוץ ל-GKE (חומות אש של VPC, Cloud NAT, Cloud Interconnect או השרת החיצוני). עוברים לקטע בידוד בעיות ב-GKE לעומת בעיות ב-VPC או בקישוריות חיצונית.
- אם המכונה הווירטואלית העצמאית מתקשרת כרגיל, אבל ה-Pods של GKE נכשלים: הבעיה היא בתוך GKE (ברמת הצומת eBPF, conntrack או CNI). עוברים לשלב 2.
שלב 2: הבחנה בין בעיות באפליקציה לבין בעיות בשכבת הצומת ובשכבת ה-CNI
כדי לבדוק אם מקור זמן האחזור הוא באפליקציה או בצומת ובשכבת ה-CNI, מבצעים את הפעולות הבאות:
בדיקת רוויית המשאבים של האפליקציה: מוודאים שהצומת לא חווה ויסות של המעבד (CPU) או לחץ על הזיכרון, שמעכבים את עיבוד החבילות במרחב המשתמש:
kubectl top nodes kubectl top pods -n defaultבדיקת מספר ה-conntrack של ליבת Linux: בודקים את מספר ה-conntrack הפעילים במארח:
# On a node where you have debugging access cat /proc/sys/net/netfilter/nf_conntrack_count cat /proc/sys/net/netfilter/nf_conntrack_maxאם
nf_conntrack_countמתקרב ל-nf_conntrack_max, ליבת המארח משמיטה חבילות TCP SYN חדשות.
שלב 3: אימות של אובדן חבילות ברמת המכונה הווירטואלית באמצעות נתוני הטלמטריה של Compute Engine
Google Cloud Compute Engine מייצא ל-Cloud Monitoring מדדים של ממשק הרשת ברמת המכונה הווירטואלית.
ב-Cloud Monitoring > Metrics Explorer, שולחים את השאילתה:
sum by (drop_reason) (rate(compute_googleapis_com:instance_network_dropped_packets_count[5m]))
FQ_CODEL_DROP: חבילת הנתונים נמחקה בגלל רוויה בתור של Fair Queuing או CoDel (חריגה ממגבלת רוחב הפס של תעבורת הנתונים היוצאת של המכונה הווירטואלית).-
FIREWALL_RULE_DROP: החבילה נמחקה על ידי כלל חומת אש של VPC. -
RATE_LIMIT_DROP: החבילה נמחקה כי המכונה הווירטואלית חרגה ממכסת החבילות לשנייה (PPS) של ממשק הרשת.
שלב 4: חקירת חבילות שנזרקו ברמת הליבה באמצעות eBPF
אם המדדים ברמת ה-VM לא מראים חבילות שנמחקו, אבל עדיין יש מחיקה של חבילות בפודים של GKE, צריך לבדוק את הסוכן של GKE Dataplane V2 (anetd) כדי לראות אם יש מחיקות במפת ה-eBPF:
kubectl logs -n kube-system daemonset/anetd -c cilium-agent --tail=200 | grep -i "drop"
מחפשים את ct-map-insertion-failed או את fib-lookup-failed.
רמה 3: ניראות של VPC וניתוב (רשת בענן)
שכבת הניתוב של VPC והענן מחברת בין צומתי GKE לבין שירותי Google Cloud אחרים, רשתות מקומיות והאינטרנט. כשלים בשלב הזה נובעים בדרך כלל מכללי חומת האש של ה-VPC, מנתיבים בהתאמה אישית או מהגדרות של שערים.
בידוד בעיות ב-GKE לעומת בעיות ב-VPC או בקישוריות חיצונית
לפני שמבודדים בעיות ברשת החיצונית מכשלים בתוך האשכול, צריך לבדוק את היקף האבחון ואת הדרישות המוקדמות:
- תחום התמקדות: בידוד הגבולות בין הניתוב הפנימי של Kubernetes לבין הניתוב בענן של VPC.
- דרישות מוקדמות: ה-CLI של gcloud, הרשאות ליצירת בדיקות קישוריות.
- תאימות ל-CNI: כל האשכולות.
- הבעיה: Pods לא מצליחים להתחבר למשאב חיצוני (לדוגמה, Cloud SQL, API מקומי או נקודת קצה של צד שלישי).
- המטרה: לזהות במהירות אם אובדן החבילות מתרחש בצומת GKE או בתוך ה-VPC או הרשת החיצונית. Google Cloud
שלב 1: בדיקת בסיס של מכונה וירטואלית ב-Compute Engine
כדי לפרוס מכונה וירטואלית בסיסית ולבדוק אם הבעיה נמשכת מחוץ ל-GKE:
פורסים מכונה וירטואלית זמנית של Compute Engine באותו תחום ובאותה תת-רשת של VPC כמו מאגר הצמתים של GKE:
gcloud compute instances create gke-baseline-tester \ --zone=us-central1-a \ --subnet=gke-subnet \ --machine-type=e2-microמתחברים למכונה באמצעות SSH ובודקים את הקישוריות ליעד:
curl -v --connect-timeout 5 https://api.example.comהערכת התוצאה:
- אם המכונה הווירטואלית ב-Compute Engine לא מצליחה להתחבר: הבעיה היא ב-VPC או ברשת החיצונית (כללי חומת אש, טבלאות ניתוב, מיצוי כתובות IP ב-Cloud NAT או הוספת כתובות IP חיצוניות לרשימת ההיתרים).
- אם המכונה הווירטואלית של Compute Engine מתחברת בהצלחה: הבעיה היא ב-GKE (חסימת תעבורת נתונים יוצאת על ידי NetworkPolicy, Pod CIDR לא מוסווה או DNS ברמת הקונטיינר).
שלב 2: הרצת בדיקת קישוריות לפי דרישה
מריצים בדיקה של Google Cloud Connectivity Tests מה-VM של הצומת ליעד:
gcloud network-management connectivity-tests create test-node-to-dest \
--source-instance=projects/PROJECT_ID/zones/us-central1-a/instances/gke-baseline-tester \
--destination-ip-address=203.0.113.10 \
--destination-port=443 \
--protocol=TCP \
--round-trip
בודקים את התוצאה במסוף Google Cloud כדי לזהות אם כלל של חומת האש ב-VPC או נתיב גורמים לירידה בנפח התנועה.
אבחון הקישוריות באמצעות בדיקות קישוריות
בדיקות קישוריות מדמות נתיבי חבילות במשאבים של GKE ו-VPC בלי לשלוח תנועה בזמן אמת. הסימולציה הזו בודקת את הרזולוציה של Service ClusterIP-to-Pod DNAT, את כללי הכניסה והיציאה של GKE Dataplane V2 NetworkPolicy ואת הסתרת ה-IP של הצומת (SNAT). לפני שמריצים סימולציות אוטומטיות של נתיבים, חשוב לבדוק את היקף האבחון ואת הדרישות המוקדמות:
- תחום התמקדות: סימולציה אוטומטית של נתיב סטטי לפודים, לשירותים, ל-NetworkPolicies ולמסלולי VPC ב-GKE.
- דרישות מוקדמות: הפעלה של Network Intelligence Center והפעלה של Network Management API.
- תאימות ל-CNI: GKE Dataplane V2 (ניתוח משופר).
- תיאור הבעיה: ניתוקי קישוריות לא מוסברים, כשכל ההגדרות נראות תקינות בבדיקה ידנית.
- המטרה: לדמות ולעקוב באופן סטטי אחרי כל נתיב החבילה מהמקור של Pod ליעד, ולזהות את שורת המדיניות המדויקת שגורמת לניתוק.
תרחיש א': בדיקה אם GKE NetworkPolicy חוסמת את איסוף המדדים
כשמגרדים מדדים מפודים במרחב שמות מאובטח, יכול להיות שהמדיניות NetworkPolicy שמוגדרת כברירת מחדל לדחייה תחסום את האספנים של השירות המנוהל של Google Cloud ל-Prometheus:
gcloud network-management connectivity-tests create test-gmp-to-pod \
--source-ip-address=10.0.0.15 \
--destination-gke-pod=projects/PROJECT_ID/locations/LOCATION/clusters/CLUSTER_NAME/k8s/namespaces/prod/pods/backend-pod \
--destination-port=8080 \
--protocol=TCP \
--round-trip
בודקים את המעקב לבדיקה במסוף Google Cloud . אם הבדיקה מסתיימת בשלב GKE Network Policy evaluation עם DROP, צריך להוסיף כלל כניסה כדי לאפשר תנועה מה-Pods של ה-collector.
תרחיש ב': בדיקת הנגישות לשירות GKE
הדמיה של יכולת הגעה ממכונה וירטואלית של לקוח לשירות Kubernetes פנימי:
gcloud network-management connectivity-tests create test-vm-to-service \
--source-instance=projects/PROJECT_ID/zones/us-central1-a/instances/client-vm \
--destination-ip-address=10.96.0.100 \
--destination-port=80 \
--protocol=TCP \
--round-trip
המעקב המדומה מציג:
- התאמה של מסלול VPC.
- אישור תעבורת נתונים נכנסת ויוצאת בחומת האש של VPC.
- הגעה לצומת GKE.
- DNAT של שירות לכתובת ה-IP של Pod לקצה העורפי.
- הערכה של Ingress NetworkPolicy ב-Pod לקצה העורפי.
תרחיש ג': אבחון בעיות בתעבורת נתונים יוצאת מה-Pod לאינטרנט
כשה-Pods לא יכולים להגיע ל-API חיצוני באינטרנט:
יוצרים בדיקה מה-Pod לכתובת ה-IP הציבורית החיצונית (למשל
8.8.8.8):gcloud network-management connectivity-tests create test-pod-to-internet \ --source-gke-pod=projects/PROJECT_ID/locations/LOCATION/clusters/CLUSTER_NAME/k8s/namespaces/prod/pods/app-pod \ --destination-ip-address=8.8.8.8 \ --destination-port=53 \ --protocol=UDP \ --round-tripבודקים את נקודת ההורדה:
- Dropped at NetworkPolicy: ל-Pod חסרה מדיניות NetworkPolicy של תעבורה יוצאת שמאפשרת תעבורת נתונים אל
0.0.0.0/0. - Dropped at VPC Firewall: כלל של חומת אש ב-VPC דוחה תעבורת נתונים יוצאת מתת-הרשת של הצומת.
- Dropped at Cloud NAT or Route: לתת-הרשת אין נתיב ברירת מחדל לשער האינטרנט, או ש-Cloud NAT לא מוגדר לתת-הרשת.
- Dropped at NetworkPolicy: ל-Pod חסרה מדיניות NetworkPolicy של תעבורה יוצאת שמאפשרת תעבורת נתונים אל
רמה 4: ניראות של שער חיצוני ועלות (אינטרנט ו-NAT)
שכבת השער החיצוני מנהלת את תעבורת הנתונים היוצאת ליעדים באינטרנט הציבורי דרך Cloud NAT או שערים חיצוניים. התצפיתיות ברמה הזו עוזרת לזהות עומסי עבודה עם תעבורת נתונים יוצאת גבוהה ולשלוט בעלויות של העברת הנתונים.
זיהוי תנועת NAT (תעבורה יוצאת לאינטרנט)
לפני שמנתחים את תעבורת הנתונים היוצאת באינטרנט וב-NAT, צריך לבדוק את היקף האבחון ואת הדרישות המוקדמות:
- תחום התמקדות: תעבורת נתונים יוצאת, ניצול יציאות של Cloud NAT, עלויות של העברת נתונים חיצוניים.
- דרישות מוקדמות: הפעלת GKE Dataplane V2 Flow Observability.
- תאימות ל-CNI: GKE Dataplane V2.
- תיאור הבעיה: שגיאות של מיצוי יציאות ב-Cloud NAT או עלויות גבוהות באופן בלתי צפוי של תעבורת נתונים לאינטרנט.
- המטרה: לזהות אילו אובייקטים ספציפיים של Pod ו-Service ב-GKE מעבירים תנועה לנקודות קצה חיצוניות באינטרנט.
שלב 1: הבנת המושגים "to-stack" ו-"world" ב-GKE Dataplane V2
ב-GKE Dataplane V2:
-
world: מייצג כל יעד מחוץ לאשכול GKE ומחוץ ל-VPC (האינטרנט הציבורי). -
to-stack: מייצג חבילות שעוברות מממשק veth של מאגר eBPF למקבץ הרשת (network stack) של המארח ב-Linux, כדי לעבור הסתרת IP (SNAT) לפני שהן מגיעות ל-Cloud NAT.
שלב 2: סטרימינג וסינון של תנועת NAT באמצעות Hubble CLI
מעבירים בסטרימינג תנועת אינטרנט יוצאת בזמן אמת שמקורה באשכול:
# Stream egress flows heading to external internet ("world")
gke-hubble observe \
--traffic-direction egress \
--verdict FORWARDED \
--to-identity world \
--follow
פלט לדוגמה:
TIMESTAMP SOURCE DESTINATION TYPE VERDICT
10:25:01.120 default/worker-pod 142.250.190.46:443 to-stack FORWARDED
כדי לזהות את הגורמים העיקריים לתעבורת נתונים יוצאת, אפשר גם להעביר את פלט ה-JSON של Hubble אל jq כדי לספור את תזרימי הנתונים היוצאים החיצוניים לפי Pod:
timeout 60s gke-hubble observe \
--traffic-direction egress \
--verdict FORWARDED \
--to-identity world \
-o json | jq -r '.flow.source.namespace + "/" + .flow.source.pod_name' | sort | uniq -c | sort -nr | head -n 10
שלב 3: מעקב אחרי תנועה חיצונית באמצעות מדדים
ב-Cloud Monitoring, עוקבים אחרי נפח התנועה החיצונית:
fetch prometheus_target
| metric 'prometheus.googleapis.com/pod_flow_egress_flows_count/counter'
| filter (metric.destination_identity == 'world')
| align rate(1m)
| every 1m
| group_by [metric.source_workload, metric.source_namespace], sum(val())
ניתוח העלויות והביצועים של תנועת הנתונים באשכול באמצעות Flow Analyzer
לפני שיוצרים תצוגה חזותית של זרימת התנועה ושל העלויות בין אזורים, צריך לבדוק את היקף האבחון ואת הדרישות המוקדמות:
- תחום המיקוד: עלויות של העברת נתונים בין אזורים, המשתמשים העיקריים, חשיפה לתנועה בין צמתים בלי שאילתות SQL.
- דרישות מוקדמות: יומני זרימה של VPC מופעלים עם
INCLUDE_ALL_METADATA, הרשאות גישה בתוך הצומת מופעלות, Observability Analytics מופעל בקטגוריית היומנים. - תאימות ל-CNI: כל האשכולות.
- התופעה: חיובים גבוהים על העברת נתונים בין אזורים בחשבונות החודשיים שלGoogle Cloud .
- המטרה: לזהות באופן חזותי אילו עומסי עבודה ב-GKE יוצרים תנועה בין אזורים, ולבצע אופטימיזציה של המיקום בלי לשלוח שאילתות ליומנים גולמיים.
דרישות מוקדמות
כדי להשתמש ב-Flow Analyzer ב-GKE:
- יומני זרימה של VPC: צריך להפעיל אותם ברשת המשנה של האשכול באמצעות
metadata="INCLUDE_ALL_METADATA". - Intranode Visibility: צריך להפעיל את התכונה הזו באשכול כדי שתעבורת הנתונים בין pod ל-pod תיחשף לצינור עיבוד הנתונים של רישום ביומן של תעבורת נתונים ב-VPC.
- ניתוח נתוני יומן: כדי להשתמש ב-Observability Analytics, צריך לשדרג את הקטגוריה
_Defaultב-Cloud Logging.
שלב 1: זיהוי ה-GKE top talkers ב-Flow Analyzer
כדי להציג עומסי עבודה בנפח גבוה ב-Flow Analyzer:
- נכנסים לדף Flow Analyzer במסוף Google Cloud .
- לוחצים על Source bucket ובוחרים את קטגוריית היומנים שבה נמצאים יומני התנועה. אם לא ניתבתם אותם למקום אחר, זהו הקטגוריה _Default.
- בקטע Traffic aggregation, בוחרים באפשרות Source - Destination.
- מגדירים את טווח התאריכים של חלון הניתוח.
- בקטע Organize flows by, בוחרים את השדות של Pod או עומס העבודה ב-GKE.
- לוחצים על הפעלת שאילתה חדשה. בתרשים Highest data flows מוצגים עומסי העבודה שבהם מועברים הכי הרבה נתונים.
שלב 2: ניתוח עלויות התנועה בין אזורים
תנועה בין אזורים כרוכה בחיובים על העברת נתונים. כדי לאתר עומסי עבודה שמועברים בין אזורים:
- בקטע Organize flows by, בוחרים את השדות של אזור המקור ואזור היעד.
- לוחצים על Run new query וקוראים את הטבלה All data flows. שורות שבהן אזור המקור ואזור היעד שונים מייצגות את התנועה בין אזורים. המסננים של Flow Analyzer תואמים לערכים, כך שאי אפשר לסנן לפי "לא שווה". במקום זאת, צריך להשוות בין זוגות האזורים בתוצאות.
- מרחיבים את זוג האזורים עם נפח התעבורה הגבוה כדי לראות את עומסי העבודה ב-GKE במקור וביעד.
תיקון:
- להטמיע את
topologySpreadConstraintsאו אתpodAffinityב-Kubernetes כדי למקם שירותים שמתקשרים ביניהם באותו אזור זמינות. - מפעילים את ניתוב מבוסס-טופולוגיה (
service.kubernetes.io/topology-mode: Auto) בשירות כדי לשמור את התנועה באזור המקור.
שלב 3: מעבר ל-Observability Analytics (לשאילתות SQL מתקדמות)
ב-Flow Analyzer, לוחצים על View in Log Analytics כדי להריץ שאילתות SQL על נתוני התנועה.
שאילתת ה-SQL הבאה מחשבת את הפודים המובילים שמתקשרים בין אזורים:
SELECT
JSON_VALUE(json_payload.src_gke_details.pod.workload.workload_name) AS src_workload,
JSON_VALUE(json_payload.dest_gke_details.pod.workload.workload_name) AS dest_workload,
JSON_VALUE(json_payload.src_instance.zone) AS src_zone,
JSON_VALUE(json_payload.dest_instance.zone) AS dest_zone,
SUM(CAST(JSON_VALUE(json_payload.bytes_sent) AS INT64)) / 1024 / 1024 / 1024 AS total_gb_sent
FROM
`PROJECT_ID.global._Default._AllLogs`
WHERE
log_name LIKE '%vpc_flows%'
AND timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
AND JSON_VALUE(json_payload.src_instance.zone) != JSON_VALUE(json_payload.dest_instance.zone)
GROUP BY
1, 2, 3, 4
ORDER BY
total_gb_sent DESC
LIMIT 20;
תקציר בנושא שאילתות והפניות ל-CLI של Hubble
Hubble CLI מעביר בסטרימינג ומסנן נתונים של זרימת רשת בזמן אמת ישירות ממאגר הנתונים הזמני (ring buffer) של ליבת GKE Dataplane V2.
הגדרה: יצירת כתובת אימייל חלופית לעזרה
מכיוון ש-Hubble פועל בתוך מישור הבקרה של האשכול, צריך להגדיר כינוי למעטפת כדי להריץ פקודות של Hubble בלי לפרוס קבצים בינאריים מקומיים:
alias gke-hubble="kubectl exec -it -n gke-managed-dpv2-observability deployment/hubble-relay -c hubble-cli -- hubble"
מתכוני סינון נפוצים
| פתרון בעיות שקשורות למטרות עסקיות | פקודת Hubble CLI |
|---|---|
| צפייה בכל החבילות שנמחקו בזמן אמת בכל האשכול | gke-hubble observe --verdict DROPPED --follow |
| העברת כל התנועה של Pod ספציפי בכל מרחב שמות | gke-hubble observe --pod default/my-pod --follow |
| סינון תנועה בין שני מרחבי שמות ספציפיים | gke-hubble observe --from-namespace frontend --to-namespace backend |
| בידוד התנועה ביציאה ספציפית (כמו יציאה 80) | gke-hubble observe --port 80 |
| בדיקת שאילתות ותשובות של DNS בזמן אמת | gke-hubble observe --port 53 |
| צפייה באיפוסים של TCP בזמן אמת (חבילות RST) | gke-hubble observe --type trace --verdict FORWARDED --tcp-flags RST |
| העברת כל תנועת הנתונים היוצאת שמיועדת לאינטרנט הציבורי | gke-hubble observe --traffic-direction egress --to-identity world |
| בדיקת תנועה בשכבת האפליקציה של HTTP (שכבה 7 של OSI) | gke-hubble observe --protocol http |
סינון מתקדם עם שלילה (--not)
אתם יכולים להחריג תנועה תקינה או תנועה בנפח גבוה כדי להתמקד בחריגות:
# Observe drops, but exclude internal kube-system health probes and DNS
gke-hubble observe \
--verdict DROPPED \
--not --namespace kube-system \
--not --port 53
עיצוב הפלט ושילוב jq
כדי לעבד רשומות של תהליכים באופן פרוגרמטי, צריך להפיק פלט בפורמט JSON:
# Extract only source, destination, and drop reason from the last 100 flows
gke-hubble observe --verdict DROPPED -o json --last 100 | \
jq -r '[.time, .flow.source.pod_name, .flow.destination.pod_name, .flow.drop_reason_desc] | @tsv'
מגבלות
כשמשתמשים ב-Hubble CLI לפתרון בעיות בזמן אמת, חשוב לזכור את המגבלות הטכניות הבאות:
- מאגר נתונים זמני מקומי בצומת: תזרימי Hubble מאוחסנים במאגר נתונים בזיכרון בכל צומת בנפרד. באירועים עם נפח תעבורת נתונים גבוה, יומני תנועה ישנים יותר מוחלפים תוך שניות. כדי לבצע ניתוח היסטורי, הסתמכו על רישום ביומן של NetworkPolicy ועל יומני זרימה של VPC ב-Cloud Logging.
- אין OR לוגי מובנה: דגלי Hubble CLI מעריכים כמה ארגומנטים באמצעות AND לוגי. כדי לחפש כמה תנאים (כמו יציאה 80 או יציאה 443), מריצים פקודות נפרדות או מסננים את פלט ה-JSON באמצעות
jq.
המאמרים הבאים
- שיטות מומלצות לתצפיתיות ברשת
- פתרון בעיות ברשת ב-GKE
- פתרון בעיות קישוריות באשכול
- מידע על ניראות ב-GKE Dataplane V2
- פתרון בעיות בנתונים ב-Flow Analyzer