הגדרה של NodeLocal DNSCache

במאמר הזה מוסבר איך להשתמש ב-NodeLocal DNSCache כדי להפחית את זמן האחזור של חיפוש DNS ולשפר את הביצועים של האפליקציה באשכול Google Kubernetes Engine ‏ (GKE).

‫NodeLocal DNSCache הוא תוסף ל-GKE שמשפר את הביצועים של DNS על ידי הפעלת מטמון DNS ישירות בכל צומת של אשכול כ-DaemonSet. כש-Pods שולחים בקשת DNS, הבקשה עוברת קודם למטמון המקומי באותו צומת. טיפול בבקשות באופן מקומי מצמצם באופן משמעותי את הזמן הממוצע לחיפוש DNS ומפחית את העומס על ספק ה-DNS המרכזי של האשכול, כמו kube-dns או Cloud DNS for GKE. הסבר מפורט על ארכיטקטורת DNS והיתרונות של NodeLocal DNSCache זמין במאמר מידע על איתור שירותים.

באשכולות GKE Autopilot, ‏ NodeLocal DNSCache מופעל כברירת מחדל, ואי אפשר להשבית אותו. באשכולות GKE Standard שפועלת בהם גרסה 1.34.1-gke.3720000 ואילך, NodeLocal DNSCache מופעל כברירת מחדל, אבל אפשר להשבית אותו.

המסמך הזה מיועד למשתמשי GKE, כולל מפתחים, אדמינים וארכיטקטים. מידע נוסף על תפקידים נפוצים ומשימות לדוגמה ב- Google Cloudזמין במאמר תפקידים נפוצים של משתמשי GKE ומשימות.

במסמך הזה אנחנו יוצאים מנקודת הנחה שאתם מכירים את הנושאים הבאים:

ארכיטקטורה

‫NodeLocal DNSCache הוא תוסף ל-GKE שאפשר להפעיל בנוסף ל-kube-dns.

‫GKE מטמיע את NodeLocal DNSCache כ-DaemonSet שמפעיל מטמון DNS בכל צומת באשכול.

כש-Pod שולח בקשת DNS, הבקשה מועברת למטמון ה-DNS שפועל באותו צומת כמו ה-Pod. אם אי אפשר ליצור רזולוציית DNS מהבקשה במטמון, המטמון מעביר את הבקשה לאחד מהמקומות הבאים, בהתאם ליעד של השאילתה ולספק ה-DNS שהוגדר:

  • kube-dns: כל השאילתות לגבי דומיין ה-DNS של האשכול (cluster.local) מועברות אל kube-dns. ה-Pods של node-local-dns משתמשים ב-kube-dns-upstream Service כדי לגשת ל-Pods של kube-dns.
  • דומיינים מותאמים אישית או שרתי שמות במעלה הזרם: השאילתות מועברות ישירות מ-Pods של NodeLocal DNSCache.
  • Cloud DNS: כל השאילתות האחרות מועברות לשרת המטא-נתונים המקומי שפועל באותו צומת שממנו הגיעה השאילתה. שרת המטא-נתונים המקומי ניגש ל-Cloud DNS.

הנתיב של בקשת DNS, כפי שמתואר בפסקה הקודמת.

כשמפעילים את NodeLocal DNSCache באשכול קיים, מערכת GKE יוצרת מחדש את כל הצמתים באשכול שמריצים GKE בגרסה 1.15 ואילך, בהתאם לתהליך שדרוג הצמתים.

אחרי ש-GKE יוצר מחדש את הצמתים, הוא מוסיף להם באופן אוטומטי את התווית addon.gke.io/node-local-dns-ds-ready=true. אסור להוסיף את התווית הזו לצמתי האשכול באופן ידני.

היתרונות של NodeLocal DNSCache

היתרונות של NodeLocal DNSCache:

  • קיצור הזמן הממוצע של חיפוש DNS
  • חיבורים מ-Pods למטמון המקומי שלהם לא יוצרים רשומות בטבלת conntrack. ההתנהגות הזו מונעת ניתוקים ודחיות של חיבורים שנגרמים בגלל מיצוי של טבלת מעקב החיבורים ותנאי מירוץ.
  • אפשר להשתמש ב-NodeLocal DNSCache עם Cloud DNS for GKE.
  • שאילתות DNS לכתובות URL חיצוניות (כתובות URL שלא מפנות למשאבי אשכול) מועברות ישירות לשרת המטא-נתונים המקומי ועוקפות את kube-dns.
  • מטמון ה-DNS המקומי בוחר באופן אוטומטי דומיינים מסוג stub ושרתי שמות במעלה הזרם שצוינו בקטע הוספה של פותרים מותאמים אישית לדומיינים מסוג stub.

דרישות ומגבלות

  • ‫NodeLocal DNSCache צורך משאבי מחשוב בכל צומת של האשכול.
  • ‫NodeLocal DNSCache לא נתמך במאגרי צמתים של Windows Server.
  • כדי להשתמש ב-NodeLocal DNSCache, צריך GKE בגרסה 1.15 ואילך.
  • הגישה של NodeLocal DNSCache אל kube-dns Pods מתבצעת באמצעות TCP.
  • ‫NodeLocal DNSCache ניגש אל upstreamServers ואל stubDomains באמצעות TCP ו-UDP בגרסאות GKE 1.18 ואילך. צריך להיות אפשר להגיע לשרת ה-DNS באמצעות TCP ו-UDP.
  • רשומות DNS נשמרות במטמון לתקופות הבאות:
    • הזמן לחיות (TTL) של הרשומה, או 30 שניות אם ה-TTL גדול מ-30 שניות.
    • 5 שניות אם תגובת ה-DNS היא NXDOMAIN.
  • רכיבי ה-Pod של NodeLocal DNSCache מאזינים ביציאות 53,‏ 9253,‏ 9353 ו-8080 בצמתים. אם מריצים עוד hostNetwork Pod או מגדירים hostPorts עם הפורטים האלה, NodeLocal DNSCache נכשל ומתרחשות שגיאות DNS. תת-חבילות של NodeLocal DNSCache לא משתמשות במצב hostNetwork כשהן משתמשות ב-GKE Dataplane V2 ולא משתמשות ב-Cloud DNS for GKE.
  • מטמון ה-DNS המקומי פועל רק במאגרי צמתים שמריצים GKE מגרסה 1.15 ואילך. אם מפעילים את NodeLocal DNSCache באשכול עם צמתים שמריצים גרסאות קודמות, הפודים בצמתים האלה משתמשים ב-kube-dns.

לפני שמתחילים

לפני שמתחילים, חשוב לוודא שביצעתם את הפעולות הבאות:

  • מפעילים את ממשק ה-API של Google Kubernetes Engine.
  • הפעלת Google Kubernetes Engine API
  • אם רוצים להשתמש ב-CLI של Google Cloud למשימה הזו, צריך להתקין ואז להפעיל את ה-CLI של gcloud. אם התקנתם בעבר את ה-CLI של gcloud, מריצים את הפקודה gcloud components update כדי לקבל את הגרסה העדכנית. יכול להיות שגרסאות קודמות של ה-CLI של gcloud לא יתמכו בהרצת הפקודות שמופיעות במסמך הזה.
  • מוודאים שיש לכם אשכול קיים של Autopilot או Standard. אם אתם צריכים כזה, צריך ליצור אשכול Autopilot. באשכולות Autopilot, ‏ NodeLocal DNSCache מופעל כברירת מחדל ואי אפשר לבטל את ההגדרה שלו.

הפעלת NodeLocal DNSCache

בגרסאות 1.34.1-gke.3720000 ואילך, NodeLocal DNSCache מופעל כברירת מחדל באשכולות Standard. אם האשכול שלכם הוא בגרסה מוקדמת יותר מ-1.34.1-gke.3720000, אתם יכולים להשתמש ב-CLI של Google Cloud כדי להפעיל את NodeLocal DNSCache באשכולות חדשים או קיימים. אפשר גם להשתמש במסוףGoogle Cloud כדי להפעיל את NodeLocal DNSCache רק באשכולות חדשים.

gcloud

כדי להפעיל את NodeLocal DNSCache באשכול קיים, משתמשים בדגל --update-addons עם הארגומנט NodeLocalDNS=ENABLED:

gcloud container clusters update CLUSTER_NAME \
    --location=COMPUTE_LOCATION \
    --update-addons=NodeLocalDNS=ENABLED

מחליפים את מה שכתוב בשדות הבאים:

המסוף

כדי להפעיל את NodeLocal DNSCache באשכול חדש, מבצעים את השלבים הבאים:

  1. נכנסים לדף Google Kubernetes Engine במסוף Google Cloud .

    מעבר אל Kubernetes clusters

  2. לוחצים על השם של האשכול שרוצים לשנות.

  3. בקטע רישות, בשדה ספק DNS, לוחצים על עריכת ספק DNS.

  4. מסמנים את תיבת הסימון Enable NodeLocal DNSCache (הפעלת NodeLocal DNSCache).

  5. לוחצים על שמירת השינויים.

השינוי הזה מחייב ליצור מחדש את הצמתים, מה שעלול לשבש את עומסי העבודה הפעילים. פרטים על השינוי הספציפי הזה מופיעים בשורה המתאימה בטבלה שינויים ידניים שיוצרים מחדש את הצמתים באמצעות אסטרטגיית שדרוג צמתים, בהתאם למדיניות התחזוקה. מידע נוסף על עדכוני צמתים זמין במאמר תכנון שיבושים בעדכון צמתים.

מוודאים ש-NodeLocal DNSCache מופעל

כדי לוודא ש-NodeLocal DNSCache פועל, אפשר להציג את רשימת ה-Pods:node-local-dns

kubectl get pods -n kube-system -o wide | grep node-local-dns

הפלט אמור להיראות כך:

node-local-dns-869mt    1/1   Running   0   6m24s   10.128.0.35   gke-test-pool-69efb6b8-5d7m   <none>   <none>
node-local-dns-htx4w    1/1   Running   0   6m24s   10.128.0.36   gke-test-pool-69efb6b8-wssk   <none>   <none>
node-local-dns-v5njk    1/1   Running   0   6m24s   10.128.0.33   gke-test-pool-69efb6b8-bhz3   <none>   <none>

בפלט מוצג node-local-dns Pod לכל צומת שמופעלת בו גרסה 1.15 של GKE ואילך.

השבתה של NodeLocal DNSCache

באשכולות GKE Autopilot, ‏ NodeLocal DNSCache מופעל כברירת מחדל ואי אפשר להשבית אותו.

השבתה של NodeLocal DNSCache באשכול חדש

אפשר להשבית את NodeLocal DNSCache כשיוצרים אשכול GKE Standard חדש בגרסה 1.34.1-gke.3720000 ואילך, על ידי הפעלת הפקודה הבאה:

gcloud container clusters create CLUSTER_NAME  \
    --location=COMPUTE_LOCATION \
    --addons=NodeLocalDNS=DISABLED

מחליפים את מה שכתוב בשדות הבאים:

השבתה של NodeLocal DNSCache באשכול קיים

כדי להשבית את NodeLocal DNSCache באשכול GKE קיים, מריצים את הפקודה הבאה:

gcloud container clusters update CLUSTER_NAME \
    --location=COMPUTE_LOCATION \
    --update-addons=NodeLocalDNS=DISABLED

מחליפים את מה שכתוב בשדות הבאים:

השינוי הזה מחייב ליצור מחדש את הצמתים, מה שעלול לשבש את עומסי העבודה הפעילים. פרטים על השינוי הספציפי הזה מופיעים בשורה המתאימה בטבלה שינויים ידניים שיוצרים מחדש את הצמתים באמצעות אסטרטגיית שדרוג צמתים, בהתאם למדיניות התחזוקה. מידע נוסף על עדכוני צמתים זמין במאמר תכנון שיבושים בעדכון צמתים.

פתרון בעיות ב-NodeLocal DNSCache

מידע כללי על אבחון בעיות DNS ב-Kubernetes זמין במאמר בנושא ניפוי באגים של רזולוציית DNS.

ההפעלה של NodeLocal DNSCache לא מתבצעת באופן מיידי

כשמפעילים את NodeLocal DNSCache באשכול קיים, יכול להיות ש-GKE לא יעדכן את הצמתים באופן מיידי אם באשכול מוגדר חלון זמן לתחזוקה או החרגה. מידע נוסף זמין במאמר הערות לגבי יצירה מחדש של צמתים וחלונות תחזוקה.

אם לא רוצים לחכות, אפשר להחיל את השינויים על הצמתים באופן ידני על ידי הפעלת הפקודה gcloud container clusters upgrade והעברת הדגל --cluster-version עם אותה גרסת GKE שמאגר הצמתים כבר פועל בה. כדי להשתמש בפתרון העקיף הזה, צריך להשתמש ב-Google Cloud CLI.

‫NodeLocal DNSCache עם Cloud DNS

אם משתמשים ב-NodeLocal DNSCache עם Cloud DNS, האשכול משתמש בכתובת ה-IP של שרת השמות 169.254.20.10, כמו שמוצג בתרשים הבא:

‫NodeLocal DNSCache עם ארכיטקטורת Cloud DNS.

כתוצאה מכך, כתובת ה-IP של שירות kube-dns עשויה להיות שונה מכתובת ה-IP של שרת השמות שבה נעשה שימוש ב-Pods. ההבדל הזה בכתובות ה-IP צפוי, כי כתובת ה-IP של שרת השמות 169.254.20.10 נדרשת כדי ש-Cloud DNS יפעל בצורה תקינה.

כדי לבדוק את כתובות ה-IP, מריצים את הפקודות הבאות:

  1. הצגת כתובת ה-IP של שירות kube-dns:

    kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"
    

    הפלט הוא כתובת ה-IP של kube-dns, למשל 10.0.0.10

  2. פותחים סשן של מעטפת ב-Pod:

    kubectl exec -it POD_NAME -- /bin/bash
    
  3. בסשן של Pod shell, קוראים את התוכן של הקובץ /etc/resolv.conf:

    cat /etc/resolv.conf
    

    הפלט הוא 169.254.20.10

מדיניות רשת עם NodeLocal DNSCache

אם אתם משתמשים במדיניות רשת עם NodeLocal DNSCache ואתם לא משתמשים ב-Cloud DNS או ב-GKE Dataplane V2, אתם צריכים להגדיר כללים שיאפשרו לעומסי העבודה ול-Pods שלכם לשלוח שאילתות DNS.node-local-dns

משתמשים בכלל ipBlock במניפסט כדי לאפשר תקשורת בין ה-Pods לבין kube-dns.

במניפסט הבא מתוארת מדיניות רשת שמשתמשת בכלל ipBlock:

spec:
  egress:
  - ports:
    - port: 53
      protocol: TCP
    - port: 53
      protocol: UDP
    to:
    - ipBlock:
        cidr: KUBE_DNS_SVC_CLUSTER_IP/32
  podSelector: {}
  policyTypes:
    - Egress

מחליפים את KUBE_DNS_SVC_CLUSTER_IP בכתובת ה-IP של שירות kube-dns. כדי לקבל את כתובת ה-IP של שירות kube-dns, משתמשים בפקודה הבאה:

kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"

בעיות מוכרות

בקטע הזה מפורטות בעיות מוכרות ב-NodeLocal DNSCache.

תם הזמן הקצוב ל-DNS ב-dnsPolicy‏ ClusterFirstWithHostNet כשמשתמשים ב-NodeLocal DNSCache וב-GKE Dataplane V2

באשכולות שמשתמשים ב-GKE Dataplane V2 וב-NodeLocal DNSCache, ‏ Pods עם השדה hostNetwork שמוגדר לערך true והשדה dnsPolicy שמוגדר לערך ClusterFirstWithHostNet לא יכולים לגשת ל-backends של DNS באשכול. יומני DNS עשויים להכיל רשומות שדומות לרשומות הבאות:

dnslookup: write to 'a.b.c.d': Operation not permitted

;; connection timed out; no servers could be reached

הפלט מציין שבקשות ה-DNS לא מגיעות לשרתי הקצה העורפי.

פתרון עקיף הוא להגדיר את השדות dnsPolicy ו-dnsConfig עבור hostNetwork Pods:

spec:
 dnsPolicy: "None"
 dnsConfig:
   nameservers:
     - KUBE_DNS_UPSTREAM
   searches:
     - NAMESPACE.svc.cluster.local
     - svc.cluster.local
     - cluster.local
     - c.PROJECT_ID.internal
     - google.internal
   options:
     - name: ndots
       value: "5"

מחליפים את מה שכתוב בשדות הבאים:

  • NAMESPACE: מרחב השמות של ה-pod‏ hostNetwork.
  • PROJECT_ID: מזהה הפרויקט ב- Google Cloud .
  • KUBE_DNS_UPSTREAM: ClusterIP של שירות kube-dns במעלה הזרם. אפשר לקבל את הערך הזה באמצעות הפקודה הבאה:

    kubectl get svc -n kube-system kube-dns-upstream -o jsonpath="{.spec.clusterIP}"
    

בקשות ה-DNS מה-Pod יכולות עכשיו להגיע אל kube-dns ולעקוף את NodeLocal DNSCache.

שגיאות שקשורות לחלון הזמן הקצוב לתפוגה של NodeLocal DNSCache

באשכולות שבהם מופעל NodeLocal DNSCache, יכול להיות שהיומנים יכילו רשומות דומות לאלה:

[ERROR] plugin/errors: 2 <hostname> A: read tcp <node IP: port>-><kubedns IP>:53: i/o timeout

הפלט כולל את כתובת ה-IP של שירות kube-dns-upstream Cluster IP. בדוגמה הזו, התגובה לבקשת DNS לא התקבלה מ- kube-dns תוך שתי שניות. יכולות להיות כמה סיבות לבעיה הזו:

  • בעיה בקישוריות הרשת.
  • עלייה משמעותית בשאילתות DNS מעומס העבודה או מהגדלת הקיבולת של מאגר הצמתים.

כתוצאה מכך, לא ניתן לטפל בכל הבקשות בזמן באמצעות ה-kube-dns Pods הקיימים. הפתרון הוא להגדיל את מספר העותקים של kube-dns על ידי הגדלת הקיבולת של kube-dns.

הגדלת היקף הפעילות kube-dns

כדי להבטיח שייווצרו יותר תרמילי kube-dns בזמן שהצמתים של האשכול מתרחבים, אפשר להשתמש בערך נמוך יותר בשדה nodesPerReplica. מומלץ מאוד להגדיר ערך max מפורש כדי לוודא שהמכונה הווירטואלית (VM) של מישור הבקרה של GKE לא תהיה עמוסה מדי בגלל מספר גדול של פודים kube-dns שעוקבים אחרי Kubernetes API.

אפשר להגדיר בשדה max את מספר הצמתים באשכול. אם באשכול יש יותר מ-500 צמתים, צריך להגדיר את השדה max לערך 500.

במערכות סטנדרטיות, אפשר לשנות את מספר העותקים המשוכפלים של kube-dns על ידי עריכת kube-dns-autoscaler ConfigMap. ההגדרה הזו לא נתמכת באשכולות של Autopilot.

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))

אם מגדירים את השדות min ו-max ב-ConfigMap, העותקים מוגבלים לערכים האלה. כדי להגדיל את מספר המכונות, משנים את הערך של השדה 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}'

המאמרים הבאים