אם אתם מפעילים אפליקציות באשכולות רגילים, kube-dns הוא ספק ה-DNS שמוגדר כברירת מחדל ועוזר לכם להפעיל גילוי שירותים ותקשורת. במאמר הזה מוסבר איך לנהל DNS באמצעות kube-dns, כולל הארכיטקטורה, ההגדרה ושיטות מומלצות לאופטימיזציה של פעולות ה-DNS בסביבת GKE.
המסמך הזה מיועד למפתחים, לאדמינים ולאדריכלים שאחראים על ניהול DNS ב-GKE. למידע על תפקידים ומשימות נפוצים ב- Google Cloud, אפשר לעיין במאמר תפקידים ומשימות נפוצים של משתמשי GKE.
לפני שמתחילים, חשוב להכיר את השירותים של Kubernetes ואת המושגים הכלליים של DNS.
הסבר על ארכיטקטורה של kube-dns
kube-dns פועל בתוך אשכול GKE כדי לאפשר פענוח DNS בין Pods לבין Services.
הדיאגרמה הבאה מציגה כיצד ה-Pods מקיימים אינטראקציה עם שירות kube-dns:
רכיבים עיקריים
kube-dns כולל את הרכיבים העיקריים הבאים:
-
kube-dnsPods: ה-Pods האלה מריצים את תוכנת השרתkube-dns. כמה רפליקות של ה-Pods האלה פועלות במרחב השמותkube-system, והן מספקות זמינות גבוהה ויתירות. kube-dnsשירות: שירות Kubernetes מסוגClusterIP, שמקבץ את ה-Pods וחושף אותם כנקודת קצה יציבה אחת.kube-dnsClusterIPפועל כשרת DNS עבור האשכול, והפודים משתמשים בו כדי לשלוח שאילתות DNS. kube-dnsתומך בעד 1,000 נקודות קצה לכל שירות ללא ממשק משתמש.-
kube-dns-autoscaler: ה-Pod הזה משנה את מספר העותקים המשוכפלים שלkube-dnsבהתאם לגודל האשכול, שכולל את מספר הצמתים וליבות ה-CPU. הגישה הזו עוזרת להבטיח ש-kube-dnsיוכל להתמודד עם עומסים משתנים של שאילתות DNS.
פענוח DNS פנימי
כש-Pod צריך לפתור שם DNS בדומיין של האשכול, כמו myservice.my-namespace.svc.cluster.local, מתרחש התהליך הבא:
- הגדרת ה-DNS של ה-Pod:
kubeletבכל צומת מגדיר את קובץ/etc/resolv.confשל ה-Pod. בקובץ הזה נעשה שימוש ב-kube-dnsשל שירותClusterIPכשרת השמות. - שאילתת DNS: ה-Pod שולח שאילתת DNS ל
kube-dnsService. - פתרון שמות:
kube-dnsמקבל את השאילתה. הוא מחפש את כתובת ה-IP המתאימה ברשומות ה-DNS הפנימיות שלו ומגיב ל-Pod. - תקשורת: ה-Pod משתמש בכתובת ה-IP שזוהתה כדי לתקשר עם שירות היעד.
פענוח DNS חיצוני
כש-Pod צריך לפתור שם DNS חיצוני, או שם שנמצא מחוץ לדומיין של האשכול, kube-dns פועל כמפענח רקורסיבי. הוא מעביר את השאילתה לשרתי DNS במעלה הזרם שהוגדרו בקובץ ConfigMap. אפשר גם להגדיר פותרים בהתאמה אישית לדומיינים ספציפיים, שנקראים גם דומיינים מסוג stub. ההגדרה הזו מכוונת את kube-dns להעביר בקשות לדומיינים האלה לשרתי DNS ספציפיים במעלה הזרם.
הגדרת DNS של Pod
ב-GKE, סוכן kubelet בכל צומת מגדיר את הגדרות ה-DNS של ה-Pods שפועלים בצומת הזה.
הגדרת הקובץ /etc/resolv.conf
כש-GKE יוצר Pod, סוכן kubelet משנה את הקובץ /etc/resolv.conf של ה-Pod. הקובץ הזה מגדיר את שרת ה-DNS לפתרון שמות ומציין דומיינים לחיפוש. כברירת מחדל, kubelet מגדיר את ה-Pod להשתמש בשירות ה-DNS הפנימי של האשכול, kube-dns, כשרת השמות שלו. הוא גם מאכלס את דומייני החיפוש בקובץ. דומייני החיפוש האלה מאפשרים לכם להשתמש בשמות לא מלאים בשאילתות DNS. לדוגמה, אם הפוד מבצע שאילתה לגבי myservice, Kubernetes מנסה קודם לפתור את myservice.default.svc.cluster.local, אחר כך את myservice.svc.cluster.local ואז את הדומיינים האחרים מהרשימה search.
בדוגמה הבאה מוצגת הגדרת ברירת מחדל של /etc/resolv.conf:
nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local c.my-project-id.internal google.internal
options ndots:5
הקובץ הזה כולל את הערכים הבאים:
-
nameserver: מגדיר אתClusterIPשל שירותkube-dns. -
search: מגדיר את דומייני החיפוש שמצורפים לשמות לא מלאים במהלך חיפושי DNS. -
options ndots:5: הגדרת ערך הסף שלפיו GKE קובע אם שם הוא שם מוגדר במלואו. שם נחשב מוגדר במלואו אם יש בו חמש נקודות או יותר.
הגדרת ה-DNS של פודים שהוגדרו עם ההגדרה hostNetwork: true עוברת בירושה מהמארח, והם לא שולחים שאילתות ישירות אל kube-dns.
התאם אישית את kube-dns
kube-dns מספק פענוח DNS חזק כברירת מחדל. אתם יכולים להתאים את ההתנהגות שלו לצרכים ספציפיים, כמו שיפור היעילות של הרזולוציה או שימוש בשרתי DNS מועדפים. כדי להגדיר גם דומיינים מסוג stub וגם שרתי שמות במעלה הזרם, צריך לשנות את kube-dns ConfigMap במרחב השמות kube-system.
שינוי של kube-dns ConfigMap
כדי לשנות את kube-dns ConfigMap, מבצעים את הפעולות הבאות:
פותחים את ConfigMap לעריכה:
kubectl edit configmap kube-dns -n kube-systemבקטע
data, מוסיפים את השדותstubDomainsו-upstreamNameservers:apiVersion: v1 kind: ConfigMap metadata: labels: addonmanager.kubernetes.io/mode: EnsureExists name: kube-dns namespace: kube-system data: stubDomains: | { "example.com": [ "8.8.8.8", "8.8.4.4" ], "internal": [ # Required if your upstream nameservers can't resolve GKE internal domains "169.254.169.254" # IP of the metadata server ] } upstreamNameservers: | [ "8.8.8.8", # Google Public DNS "1.1.1.1" # Cloudflare DNS ]שומרים את ה-ConfigMap.
kube-dnsטוען מחדש את ההגדרה באופן אוטומטי.
דומיינים מסוג Stub
דומיינים מסוג Stub מאפשרים להגדיר פותרים מותאמים אישית של DNS לדומיינים ספציפיים. כש-Pod שולח שאילתה לשם בדומיין stub, kube-dns מעביר את השאילתה למפענח ה-DNS שצוין במקום להשתמש במנגנון ברירת המחדל שלו לפתרון.
אתם כוללים קטע stubDomains בkube-dns ConfigMap.
בסעיף הזה מצוינים הדומיין ושרתי השמות המתאימים של ה-upstream.
kube-dns ואז מעביר שאילתות לשמות בדומיין הזה לשרתים המיועדים. לדוגמה, אפשר לנתב את כל שאילתות ה-DNS עבור internal.mycompany.com אל 192.168.0.10, ולהוסיף את "internal.mycompany.com": ["192.168.0.10"] אל stubDomains.
כשמגדירים מפענח DNS מותאם אישית לדומיין stub, כמו example.com, kube-dns מעביר את כל בקשות תרגום השם של הדומיין הזה, כולל תת-דומיינים כמו *.example.com, לשרתים שצוינו.
שרתי שמות במעלה הזרם
אתם יכולים להגדיר את kube-dns כך שישתמש בשרתי שמות בהתאמה אישית במעלה הזרם כדי לפתור שמות של דומיינים חיצוניים. ההגדרה הזו מורה ל-kube-dns להעביר את כל בקשות ה-DNS, מלבד הבקשות לדומיין הפנימי של האשכול (*.cluster.local), לשרתי ה-upstream המיועדים. יכול להיות ששרתי ה-DNS המותאמים אישית שלכם לא יוכלו לפתור דומיינים פנימיים כמו metadata.internal ו-*.google.internal. אם מפעילים את איחוד הזהויות של עומסי עבודה ל-GKE או שיש עומסי עבודה שתלויים בדומיינים האלה, צריך להוסיף דומיין stub ל-internal ב-ConfigMap. משתמשים ב-169.254.169.254, כתובת ה-IP של שרת המטא-נתונים, כמפענח ה-DNS של דומיין ה-stub הזה.
ניהול פריסה מותאמת אישית של kube-dns
ב-GKE רגיל, התהליך kube-dns פועל כפריסה. פריסה kube-dns בהתאמה אישית מאפשרת לכם, כאדמינים של האשכול, לשלוט בפריסה ולהתאים אותה לצרכים שלכם, במקום להשתמש בפריסה שמוגדרת כברירת מחדל ב-GKE.
סיבות לפריסה בהתאמה אישית
כדאי לשקול פריסה מותאמת אישית של kube-dns מהסיבות הבאות:
- הקצאת משאבים: כוונון עדין של משאבי המעבד והזיכרון עבור
kube-dnsPods כדי לבצע אופטימיזציה של הביצועים באשכולות עם נפח תנועה גבוה של DNS. - גרסת התמונה: אפשר להשתמש בגרסה ספציפית של התמונה
kube-dnsאו לעבור לספק DNS חלופי כמו CoreDNS. - הגדרה מתקדמת: התאמה אישית של רמות הרישום ביומן, מדיניות האבטחה והתנהגות של שמירת DNS במטמון.
התאמה אוטומטית לעומס (autoscaling) לפריסות בהתאמה אישית
ה-kube-dns-autoscaler המובנה פועל עם פריסת kube-dns שמוגדרת כברירת מחדל.
אם יוצרים פריסה מותאמת אישית kube-dns, המערכת המובנית להתאמת קנה מידה אוטומטית לא מנהלת אותה. לכן, צריך להגדיר קנה מידה אוטומטי נפרד שמוגדר במיוחד למעקב אחרי מספר העותקים של הפריסה המותאמת אישית ולהתאמת המספר הזה.
בשיטה הזו צריך ליצור ולפרוס הגדרה משלכם של מידרוג אוטומטי באשכול.
כשמנהלים Deployment (פריסה) בהתאמה אישית, האחריות על כל הרכיבים שלה מוטלת על המשתמש, למשל שמירה על עדכניות של תמונת ה-מידרוג אוטומטי. שימוש ברכיבים לא עדכניים עלול לגרום לירידה בביצועים או לכשלים ב-DNS.
הוראות מפורטות להגדרה ולניהול של פריסה משלכם של kube-dns
kube-dns מופיעות במאמר הגדרה של פריסת kube-dns בהתאמה אישית.
פתרון בעיות
למידע על פתרון בעיות ב-kube-dns, אפשר לעיין בדפים הבאים:
- לקבלת עצות לגבי
kube-dnsב-GKE, אפשר לעיין במאמר פתרון בעיות ב-kube-dnsב-GKE. - לקבלת עצות כלליות לגבי אבחון בעיות DNS ב-Kubernetes, אפשר לעיין במאמר ניפוי באגים ברזולוציית DNS.
אופטימיזציה של פענוח DNS
בקטע הזה מתוארות בעיות נפוצות ושיטות מומלצות לניהול DNS ב-GKE.
המגבלה של dnsConfig דומיינים לחיפוש ב-Pod
ב-Kubernetes, מספר הדומיינים של חיפוש DNS מוגבל ל-32. אם מנסים להגדיר יותר מ-32 דומיינים לחיפוש ב-dnsConfig של Pod, kube-apiserver לא ייצור את ה-Pod ותופיע שגיאה דומה לזו:
The Pod "dns-example" is invalid: spec.dnsConfig.searches: Invalid value: []string{"ns1.svc.cluster-domain.example", "my.dns.search.suffix1", "ns2.svc.cluster-domain.example", "my.dns.search.suffix2", "ns3.svc.cluster-domain.example", "my.dns.search.suffix3", "ns4.svc.cluster-domain.example", "my.dns.search.suffix4", "ns5.svc.cluster-domain.example", "my.dns.search.suffix5", "ns6.svc.cluster-domain.example", "my.dns.search.suffix6", "ns7.svc.cluster-domain.example", "my.dns.search.suffix7", "ns8.svc.cluster-domain.example", "my.dns.search.suffix8", "ns9.svc.cluster-domain.example", "my.dns.search.suffix9", "ns10.svc.cluster-domain.example", "my.dns.search.suffix10", "ns11.svc.cluster-domain.example", "my.dns.search.suffix11", "ns12.svc.cluster-domain.example", "my.dns.search.suffix12", "ns13.svc.cluster-domain.example", "my.dns.search.suffix13", "ns14.svc.cluster-domain.example", "my.dns.search.suffix14", "ns15.svc.cluster-domain.example", "my.dns.search.suffix15", "ns16.svc.cluster-domain.example", "my.dns.search.suffix16", "my.dns.search.suffix17"}: must not have more than 32 search paths.
השגיאה הזו מוחזרת מ-kube-apiserver בתגובה לניסיון ליצור Pod. כדי לפתור את הבעיה, צריך להסיר מנתיבי החיפוש הנוספים את ההגדרה.
מגבלת nameservers בשרת במעלה הזרם עבור kube-dns
kube-dns מגביל את מספר הערכים של upstreamNameservers לשלושה. אם תגדירו יותר משלושה, Cloud Logging יציג שגיאה דומה לזו:
Invalid configuration: upstreamNameserver cannot have more than three entries (value was &TypeMeta{Kind:,APIVersion:,}), ignoring update
בתרחיש הזה, kube-dns מתעלם מההגדרה upstreamNameservers וממשיך להשתמש בהגדרה הקודמת התקינה. כדי לפתור את הבעיה, צריך להסיר את upstreamNameservers הנוסף מ-kube-dns ConfigMap.
הגדלת הקיבולת kube-dns
באשכולות רגילים, אפשר להשתמש בערך נמוך יותר עבור nodesPerReplica
כדי ליצור יותר תרמילי kube-dns Pod כשצמתים באשכול עוברים שינוי גודל. מומלץ מאוד להגדיר ערך מפורש לשדה max כדי לוודא שהמכונה הווירטואלית (VM) של מישור הבקרה של GKE לא תהיה עמוסה מדי בגלל המספר הגדול של פודים kube-dns שעוקבים אחרי Kubernetes API.
אפשר להגדיר את הערך של השדה max למספר הצמתים באשכול.
אם באשכול יש יותר מ-500 צמתים, צריך להגדיר את הערך של השדה max ל-500.
אפשר לשנות את מספר העותקים של kube-dns על ידי עריכת kube-dns-autoscaler ConfigMap.
kubectl edit configmap kube-dns-autoscaler --namespace=kube-system
הפלט אמור להיראות כך:
linear: '{"coresPerReplica":256, "nodesPerReplica":16,"preventSinglePointFailure":true}'
מספר העותקים המשוכפלים של kube-dns מחושב באמצעות הנוסחה הבאה:
replicas = max( ceil( cores * 1/coresPerReplica ) , ceil( nodes * 1/nodesPerReplica ) )
kube-dns
כדי להגדיל את קצב ההעלאה, משנים את הערך בשדה nodesPerReplica לערך קטן יותר ומוסיפים ערך בשדה max.
linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"preventSinglePointFailure":true}'
ההגדרה הזו יוצרת Pod אחד לכל שמונה צמתים באשכול.kube-dns ב-cluster עם 24 צמתים יש 3 עותקים וב-cluster עם 40 צמתים יש 5 עותקים. אם גודל האשכול עולה על 120 צמתים, מספר העותקים של kube-dns לא יעלה על 15, שהוא הערך של השדה max.
כדי להבטיח רמת זמינות בסיסית של DNS באשכול, צריך להגדיר מספר מינימלי של עותקים משוכפלים בשדה kube-dns.
הפלט של kube-dns-autoscaler ConfigMap עם השדה min שמוגדר אמור להיראות כך:
linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"min": 5,"preventSinglePointFailure":true}'
שיפור הזמנים של חיפושי DNS
יש כמה גורמים שיכולים לגרום לזמן אחזור ארוך בחיפושי DNS או לכשלים ברזולוציית DNS עם ספק kube-dns שמוגדר כברירת מחדל. יכול להיות שבאפליקציות יופיעו השגיאות האלה בתור שגיאות getaddrinfo EAI_AGAIN, שמצביעות על כשל זמני בפתרון שמות. הסיבות האפשריות:
- חיפושי DNS תכופים בעומס העבודה.
- צפיפות גבוהה של Pods לכל צומת.
- הפעלת
kube-dnsבמכונות וירטואליות מסוג Spot או במכונות וירטואליות שניתן לקטוע את הפעולה שלהן, מה שעלול להוביל למחיקה לא צפויה של צמתים. - נפח שאילתות גבוה שחורג מהקיבולת של מופע
dnsmasqב-Podkube-dns. ב-GKE בגרסה 1.31 ואילך, יש מגבלה של 200 חיבורי TCP בו-זמניים למופעkube-dnsיחיד. ב-GKE בגרסה 1.30 ומגרסאות קודמות, יש מגבלה של 20 חיבורי TCP בו-זמניים למופעkube-dnsיחיד.
כדי לשפר את זמני החיפוש ב-DNS:
- מומלץ להימנע מהרצת רכיבי מערכת קריטיים כמו
kube-dnsבמכונות וירטואליות מסוג Spot או במכונות וירטואליות שניתנות להפסקת פעולה. יוצרים לפחות מאגר צמתים אחד עם מכונות וירטואליות רגילות, ללא מכונות וירטואליות מסוג Spot או מכונות וירטואליות זמניות. כדי לוודא שעומסי עבודה קריטיים מתוזמנים בצמתים האמינים האלה, אפשר להשתמש ב-taints וב-tolerations. - מפעילים את NodeLocal
DNSCache. NodeLocal
DNSCache שומר במטמון את תשובות ה-DNS ישירות בכל צומת, וכך מקטין את זמן האחזור ואת העומס על שירות
kube-dns. אם מפעילים את NodeLocal DNSCache ומשתמשים במדיניות רשת עם כללי ברירת מחדל של דחייה, צריך להוסיף מדיניות שתאפשר לעומסי עבודה לשלוח שאילתות DNS לקבוצות ה-Pod שלnode-local-dns. - הרחבת המינוי
kube-dns. - צריך לוודא שהאפליקציה משתמשת בפונקציות שמבוססות על
dns.resolve*ולא בפונקציות שמבוססות עלdns.lookup, כיdns.lookupהיא סינכרונית. - משתמשים בשמות דומיין שמוגדרים במלואם (FQDN), לדוגמה,
https://google.com./במקוםhttps://google.com/.
יכול להיות שיהיו כשלים בפענוח DNS במהלך שדרוגים של אשכולות GKE, בגלל שדרוגים מקבילים של רכיבי מישור הבקרה, כולל kube-dns.
בדרך כלל, הכשלים האלה משפיעים על אחוז קטן של צמתים. חשוב לבדוק היטב את השדרוגים של האשכולות בסביבה שאינה סביבת ייצור לפני שמחילים אותם על אשכולות בסביבת ייצור.
מוודאים שאפשר לגלות את השירות
kube-dns יוצר רק רשומות DNS לשירותים שיש להם נקודות קצה. אם לשירות אין נקודות קצה, kube-dns לא יוצר רשומות DNS עבור השירות הזה.
ניהול פערים ב-TTL של DNS
אם kube-dns מקבל תשובת DNS ממפענח DNS במעלה הזרם עם TTL גדול או אינסופי, הוא שומר את ערך ה-TTL הזה. ההתנהגות הזו עלולה ליצור חוסר התאמה בין הערך שנשמר במטמון לבין כתובת ה-IP בפועל.
ב-GKE, הבעיה הזו נפתרת בגרסאות ספציפיות של מישור הבקרה, כמו 1.21.14-gke.9100 ואילך או 1.22.15-gke.2100 ואילך. בגרסאות האלה מוגדר ערך TTL מקסימלי של 30 שניות לכל תגובת DNS עם ערך TTL גבוה יותר. ההתנהגות הזו דומה ל-NodeLocal DNSCache.
הצגת המדדים של kube-dns
אפשר לאחזר מדדים לגבי שאילתות DNS באשכול ישירות מ-Pods kube-dns.
איתור ה-Pods במרחב השמות
kube-system:kube-dnskubectl get pods -n kube-system --selector=k8s-app=kube-dnsהפלט אמור להיראות כך:
NAME READY STATUS RESTARTS AGE kube-dns-548976df6c-98fkd 4/4 Running 0 48m kube-dns-548976df6c-x4xsh 4/4 Running 0 47mבוחרים אחד מה-Pods ומגדירים העברת פורטים כדי לגשת למדדים מתוך ה-Pod הזה:
- Port
10055חושףkube-dnsמדדים. - Port
10054חושףdnsmasqמדדים.
מחליפים את
POD_NAMEבשם של ה-Pod שבחרתם.POD_NAME="kube-dns-548976df6c-98fkd" # Replace with your pod name kubectl port-forward pod/${POD_NAME} -n kube-system 10055:10055 10054:10054הפלט אמור להיראות כך:
Forwarding from 127.0.0.1:10054 -> 10054 Forwarding from 127.0.0.1:10055 -> 10055- Port
בסשן חדש של מסוף, משתמשים בפקודה
curlכדי לגשת לנקודות הקצה של המדדים.# Get kube-dns metrics curl http://127.0.0.1:10055/metrics # Get dnsmasq metrics curl http://127.0.0.1:10054/metricsהפלט ייראה בערך כך:
kubedns_dnsmasq_errors 0 kubedns_dnsmasq_evictions 0 kubedns_dnsmasq_hits 3.67351e+06 kubedns_dnsmasq_insertions 254114 kubedns_dnsmasq_max_size 1000 kubedns_dnsmasq_misses 3.278166e+06
המאמרים הבאים
- קראו סקירה כללית על DNS באשכול ב-GKE.
- במאמר DNS for Services and Pods (מערכת DNS לשירותים ול-Pods) מוסבר באופן כללי איך משתמשים ב-DNS באשכולות Kubernetes.
- איך מגדירים NodeLocal DNSCache
- איך מגדירים פריסה מותאמת אישית של kube-dns