הגדרה של NodeLocal DNSCache

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

‫NodeLocal DNSCache הוא תוסף ל-GKE שמשפר את ביצועי ה-DNS על ידי הפעלת מטמון DNS ישירות בכל צומת באשכול בתור DaemonSet. כשה-Pods שולחים בקשת DNS, הבקשה עוברת קודם למטמון המקומי באותו צומת. טיפול בבקשות באופן מקומי מקצר משמעותית את זמני חיפוש ה-DNS הממוצעים ומפחית את העומס על ספק ה-DNS המרכזי של האשכול, כמו kube-dns או Cloud DNS ל-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. הפודים של node-local-dns משתמשים בשירות kube-dns-upstream כדי לגשת לפודים של kube-dns.
  • דומיינים בהתאמה אישית או שרתי שמות במעלה הזרם: השאילתות מועברות ישירות מ-Pods של NodeLocal DNSCache.
  • ‫Cloud DNS: כל השאילתות האחרות מועברות אל שרת המטא-נתונים המקומי שפועל באותו צומת שממנו הגיעה השאילתה. שרת המטא-נתונים המקומי ניגש ל-Cloud DNS.

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

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

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

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

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

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

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

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

הפעלת NodeLocal DNSCache

בגרסה 1.34.1-gke.3720000 ואילך, NodeLocal DNSCache מופעל כברירת מחדל באשכולות רגילים. אם גרסת האשכול שלכם היא לפני 1.34.1-gke.3720000, אתם יכולים להשתמש ב-Google Cloud CLI כדי להפעיל את 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. בקטע Networking, בשדה ספק DNS, לוחצים על Edit DNS provider.

  4. מסמנים את התיבה Enable NodeLocal DNSCache.

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

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

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

כדי לוודא ש-NodeLocal DNSCache פועל, אפשר להציג את רשימת הפודים של 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>

בפלט מוצג Pod של node-local-dns לכל צומת שפועלת בו גרסה 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, קוראים את התוכן של הקובץ /etc/resolv.conf:

    cat /etc/resolv.conf
    

    הפלט הוא 169.254.20.10

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

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

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

המניפסט הבא מתאר מדיניות רשת ב-Kubernetes שמשתמשת בכלל 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, פודים שהשדה hostNetwork שלהם מוגדר כ-true והשדה dnsPolicy שלהם מוגדר כ-ClusterFirstWithHostNet לא יכולים להגיע לקצוות העורפיים של ה-DNS של האשכול. יכול להיות שיומני ה-DNS יכילו רשומות שדומות לאלה:

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

;; connection timed out; no servers could be reached

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

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

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 לא התקבלה מכתובת ה-IP‏ kube-dns תוך שתי שניות. הבעיה הזו יכולה להיגרם מאחת מהסיבות הבאות:

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

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

הרחבה אנכית (scale up) של kube-dns

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

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

באשכולות רגילים, אפשר לשנות את מספר הרפליקות של kube-dns על ידי עריכת ה-ConfigMap של kube-dns-autoscaler. ההגדרה הזו לא נתמכת באשכולות 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 לכל שמונה צמתים באשכול. באשכול עם 24 צמתים יש שלוש רפליקות, ובאשכול עם 40 צמתים יש חמש רפליקות. אם האשכול גדל ליותר מ-120 צמתים, מספר הרפליקות של kube-dns לא גדל מעבר ל-15, שהוא הערך של max.

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

הפלט של ConfigMap של kube-dns-autoscaler עם שדה min מוגדר אמור להיראות כך:

linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"min": 5,"preventSinglePointFailure":true}'

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