kube-dns für GKE

Wenn Sie Anwendungen in Standard-Clustern ausführen, ist kube-dns der Standard-DNS-Anbieter, mit dem Sie die Service Discovery und -kommunikation aktivieren können. In diesem Dokument wird beschrieben, wie Sie DNS mit kube-dns verwalten, einschließlich der Architektur, Konfiguration und Best Practices zur Optimierung der DNS-Auflösung in Ihrer GKE-Umgebung.

Dieses Dokument richtet sich an Entwickler, Administratoren und Architekten, die für die Verwaltung von DNS in GKE verantwortlich sind. Informationen zu häufigen Rollen und Aufgaben in Google CloudGKE finden Sie unter Häufige GKE-Nutzerrollen und -Aufgaben.

Machen Sie sich vor Beginn mit Kubernetes Diensten und allgemeinen DNS Konzepten vertraut.

Architektur von kube-dns

kube-dns wird in Ihrem GKE-Cluster ausgeführt, um die DNS-Auflösung zwischen Pods und Diensten zu ermöglichen.

Das folgende Diagramm zeigt, wie Ihre Pods mit dem kube-dns-Dienst interagieren:

Abbildung 1: Diagramm, das zeigt, wie Pods DNS-Anfragen an den `kube-dns`-Dienst senden, der von `kube-dns`-Pods unterstützt wird. Die `kube-dns`-Pods verarbeiten die interne DNS-Auflösung und leiten externe Anfragen an vorgelagerte DNS-Server weiter.

Schlüsselkomponenten

kube-dns umfasst die folgenden Schlüsselkomponenten:

  • kube-dns-Pods:Diese Pods führen die kube-dns-Serversoftware aus. Mehrere Replikate dieser Pods werden im kube-system-Namespace ausgeführt und bieten Hochverfügbarkeit und Redundanz.
  • kube-dns -Dienst:In der folgenden Tabelle werden die Skalierbarkeits- und Konfigurationslimits der Legacy- und CoreDNS-basierten Versionen von kube-dns verglichen:
    Funktion Legacy (kube-dns 1.35 und früher) kube-dns auf CoreDNS (1.36 und höher)
    Endpunktbewusstsein Bis zu 1.000 Endpunkte pro Dienst. Wenn ein Dienst mehr als 1.000 Pods hat, kennt kube-dns die zusätzlichen Endpunkte nicht. Alle Endpunkte. Diese Version verwendet EndpointSlices, um die Korrektheit zu gewährleisten und die Effizienz für große Dienste zu verbessern.
    Vorgelagerte Nameserver Auf 3 begrenzt Unterstützt bis zu 15
    Gleichzeitige ausgehende TCP-Verbindungen Auf 200 begrenzt Unterstützt bis zu 1.500
  • kube-dns-autoscaler: Dieser Pod passt die Anzahl der kube-dns Replikate an die Größe des Clusters an, einschließlich der Anzahl der Knoten und CPU-Kerne. So kann kube-dns unterschiedliche DNS-Abfragelasten verarbeiten.

Interne DNS-Auflösung

Wenn ein Pod einen DNS-Namen in der Clusterdomain auflösen muss, z. B. myservice.my-namespace.svc.cluster.local, geschieht Folgendes:

  1. DNS-Konfiguration des Pods:Das kubelet auf jedem Knoten konfiguriert die Datei /etc/resolv.conf des Pods. In dieser Datei wird die ClusterIP des kube-dns-Dienstes als Nameserver verwendet.
  2. DNS-Abfrage:Der Pod sendet eine DNS-Abfrage an den kube-dns-Dienst.
  3. Namensauflösung :

    • GKE-Version 1.36 oder höher:Die CoreDNS-basierte Implementierung verwendet EndpointSlices, sodass kube-dns alle Pods in einem Dienst kennt. Dies verbessert die Korrektheit und Effizienz für große Dienste.
    • GKE-Version 1.35 oder früher:kube-dns löst Namen basierend auf der älteren Cloud Endpoints API auf, die auf 1.000 Endpunkte begrenzt ist. Wenn ein Dienst mehr als 1.000 unterstützende Pods hat, kennt kube-dns die zusätzlichen Endpunkte nicht.
  4. Kommunikation:Der Pod verwendet dann die aufgelöste IP-Adresse, um mit dem Zieldienst zu kommunizieren.

Externe DNS-Auflösung

Wenn ein Pod einen externen DNS-Namen oder einen Namen außerhalb der Clusterdomain auflösen muss, fungiert kube-dns als rekursiver Resolver. Er leitet die Abfrage an vorgelagerte DNS-Server weiter, die in der ConfigMap Datei konfiguriert sind. Sie können auch benutzerdefinierte Resolver für bestimmte Domains konfigurieren, die auch als Stub-Domains bezeichnet werden. Mit dieser Konfiguration wird kube-dns angewiesen, Anfragen für diese Domains an bestimmte vorgelagerte DNS-Server weiterzuleiten.

Pod-DNS konfigurieren

In GKE konfiguriert der kubelet-Agent auf jedem Knoten die DNS-Einstellungen für die Pods, die auf diesem Knoten ausgeführt werden.

Datei /etc/resolv.conf konfigurieren

Wenn GKE einen Pod erstellt, ändert der kubelet-Agent die Datei /etc/resolv.conf des Pods. In dieser Datei wird der DNS-Server für die Namensauflösung konfiguriert und Suchdomains angegeben. Standardmäßig konfiguriert kubelet den Pod so, dass er den internen DNS-Dienst des Clusters, kube-dns, als Nameserver verwendet. Außerdem werden Suchdomains in die Datei eingefügt. Mit diesen Suchdomains können Sie nicht qualifizierte Namen in DNS-Abfragen verwenden. Wenn ein Pod beispielsweise myservice abfragt, versucht Kubernetes zuerst, myservice.default.svc.cluster.local aufzulösen, dann myservice.svc.cluster.local und dann andere Domains aus der Liste search.

Das folgende Beispiel zeigt eine Standardkonfiguration von /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

Diese Datei enthält die folgenden Einträge:

  • nameserver: definiert die ClusterIP des kube-dns-Dienstes.
  • search: definiert die Suchdomains, die bei DNS-Lookups an nicht qualifizierte Namen angehängt werden.
  • options ndots:5: legt den Schwellenwert fest, ab dem GKE einen Namen als vollständig qualifiziert betrachtet. Ein Name gilt als voll qualifiziert, wenn er fünf oder mehr Punkte enthält.

Pods, die mit hostNetwork: true konfiguriert sind, übernehmen ihre DNS-Konfiguration vom Host und fragen kube-dns nicht direkt ab, es sei denn, sie verwenden die dnsPolicy ClusterFirstWithHostNet.

kube-dns anpassen

kube-dns bietet eine robuste Standard-DNS-Auflösung. Sie können das Verhalten an bestimmte Anforderungen anpassen, z. B. um die Auflösungseffizienz zu verbessern oder bevorzugte DNS-Resolver zu verwenden. Sowohl Stub-Domains als auch vorgelagerte Nameserver werden konfiguriert, indem Sie die kube-dns ConfigMap im kube-system-Namespace ändern.

kube-dns ConfigMap ändern

So ändern Sie die kube-dns ConfigMap:

  1. Öffnen Sie die ConfigMap zur Bearbeitung:

    kubectl edit configmap kube-dns -n kube-system
    
  2. Fügen Sie im Abschnitt data die Felder stubDomains und upstreamNameservers wie folgt hinzu:

    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
          "8.8.4.4" # Google Public DNS Backup
        ]
    
  3. Speichern Sie die ConfigMap. kube-dns lädt die Konfiguration automatisch neu.

Stub-Domains

Mit Stub-Domains können Sie benutzerdefinierte DNS-Resolver für bestimmte Domains definieren. Wenn ein Pod einen Namen in dieser Stub-Domain abfragt, leitet kube-dns die Abfrage an den angegebenen Resolver weiter, anstatt den Standardauflösungsmechanismus zu verwenden.

Fügen Sie in der kube-dns ConfigMap einen Abschnitt stubDomains ein.

In diesem Abschnitt werden die Domain und die entsprechenden vorgelagerten Nameserver angegeben. kube-dns leitet dann Abfragen für Namen in dieser Domain an die angegebenen Server weiter. Sie können beispielsweise alle DNS-Abfragen für internal.mycompany.com an 192.168.0.10 weiterleiten, indem Sie stubDomains"internal.mycompany.com": ["192.168.0.10"] hinzufügen.

Wenn Sie einen benutzerdefinierten Resolver für eine Stub-Domain festlegen, z. B. example.com, kube-dns leitet alle Anfragen zur Namensauflösung für diese Domain, einschließlich Subdomains wie *.example.com, an die angegebenen Server weiter.

Vorgelagerte Nameserver

Sie können kube-dns so konfigurieren, dass benutzerdefinierte vorgelagerte Nameserver verwendet werden, um externe Domainnamen aufzulösen. Mit dieser Konfiguration wird kube-dns angewiesen, alle DNS-Anfragen mit Ausnahme der Anfragen für die interne Domain des Clusters (*.cluster.local) an die angegebenen vorgelagerten Server weiterzuleiten. Interne Domains wie metadata.internal und *.google.internal können möglicherweise nicht von Ihren benutzerdefinierten vorgelagerten Servern aufgelöst werden. Wenn Sie die Workload Identity Federation for GKE aktivieren oder Arbeitslasten haben, die von diesen Domains abhängen, fügen Sie eine Stub-Domain für internal in der ConfigMap hinzu. Verwenden Sie 169.254.169.254, die IP-Adresse des Metadatenservers, als Resolver für diese Stub-Domain.

Benutzerdefiniertes kube-dns-Deployment verwalten

In einem Standard-Cluster wird kube-dns als Deployment ausgeführt. Ein benutzerdefiniertes kube-dns-Deployment bedeutet, dass Sie als Clusteradministrator das Deployment steuern und an Ihre Bedürfnisse anpassen können, anstatt das von GKE bereitgestellte Standard-Deployment zu verwenden.

Gründe für ein benutzerdefiniertes Deployment

Ein benutzerdefiniertes kube-dns-Deployment kann aus folgenden Gründen sinnvoll sein:

  • Ressourcenzuweisung:Optimieren Sie die CPU- und Arbeitsspeicherressourcen für kube-dns-Pods, um die Leistung in Clustern mit hohem DNS-Traffic zu verbessern.
  • Image-Version:Verwenden Sie eine bestimmte Version des kube-dns-Images oder wechseln Sie zu einem alternativen DNS-Anbieter wie CoreDNS.
  • Erweiterte Konfiguration:Passen Sie Logging-Level, Sicherheitsrichtlinien und das DNS-Caching-Verhalten an.

Autoscaling für benutzerdefinierte Deployments

Der integrierte kube-dns-autoscaler funktioniert mit dem Standard-kube-dns-Deployment. Wenn Sie ein benutzerdefiniertes kube-dns-Deployment erstellen, wird es nicht vom integrierten Autoscaler verwaltet. Daher müssen Sie einen separaten Autoscaler einrichten, der speziell für die Überwachung und Anpassung der Anzahl der Replikate Ihres benutzerdefinierten Deployments konfiguriert ist. Dazu müssen Sie eine eigene Autoscaler-Konfiguration in Ihrem Cluster erstellen und bereitstellen.

Wenn Sie ein benutzerdefiniertes Deployment verwalten, sind Sie für alle Komponenten verantwortlich, z. B. dafür, dass das Autoscaler-Image auf dem neuesten Stand ist. Die Verwendung veralteter Komponenten kann zu Leistungseinbußen oder DNS-Fehlern führen.

Eine detaillierte Anleitung zum Konfigurieren und Verwalten eines eigenen kube-dns Deployments finden Sie unter Benutzerdefiniertes kube-dns Deployment einrichten.

Fehlerbehebung

Informationen zur Fehlerbehebung bei kube-dns finden Sie auf den folgenden Seiten:

DNS-Auflösung optimieren

In diesem Abschnitt werden häufige Probleme und Best Practices für die Verwaltung von DNS in GKE beschrieben.

Limit für dnsConfig-Suchdomains eines Pods

Kubernetes begrenzt die Anzahl der DNS-Suchdomains auf 32. Wenn Sie in der dnsConfig eines Pods mehr als 32 Suchdomains definieren, erstellt der kube-apiserver den Pod nicht und gibt einen Fehler ähnlich dem folgenden zurück:

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.

Der kube-apiserver gibt diese Fehlermeldung als Antwort auf einen Versuch zur Pod-Erstellung zurück. Entfernen Sie zusätzliche Suchpfade aus der Konfiguration, um dieses Problem zu beheben.

Limit für vorgelagerte nameservers für kube-dns

In älteren Versionen von kube-dns (Version 1.35 und früher) ist die Anzahl der upstreamNameservers auf drei begrenzt. Wenn Sie mehr als drei definieren, wird in Cloud Logging ein Fehler ähnlich dem folgenden angezeigt:

Invalid configuration: upstreamNameserver cannot have more than three entries (value was &TypeMeta{Kind:,APIVersion:,}), ignoring update

In diesem Fall ignoriert kube-dns die upstreamNameservers-Konfiguration und verwendet weiterhin die vorherige gültige Konfiguration. Entfernen Sie die zusätzlichen upstreamNameservers aus der kube-dns ConfigMap, um dieses Problem zu beheben.

kube-dns vertikal skalieren

In Standard-Clustern können Sie einen niedrigeren Wert für nodesPerReplica verwenden, damit mehr kube-dns-Pods erstellt werden, wenn Clusterknoten vertikal skaliert werden. Es wird dringend empfohlen, einen expliziten Wert für das Feld max festzulegen, damit die GKE-Steuerungsebenen-VM (Virtuelle Maschine) aufgrund der großen Anzahl von kube-dns-Pods, die die Kubernetes API überwachen, nicht überlastet ist.

Sie können den Wert des Felds max auf die Anzahl der Knoten im Cluster festlegen. Wenn der Cluster mehr als 500 Knoten hat, legen Sie den Wert des Felds max auf 500 fest.

Sie können die Anzahl der kube-dns-Replikate ändern, indem Sie die kube-dns-autoscaler ConfigMap bearbeiten.

kubectl edit configmap kube-dns-autoscaler --namespace=kube-system

Die Ausgabe sieht etwa so aus:

linear: '{"coresPerReplica":256, "nodesPerReplica":16,"preventSinglePointFailure":true}'

Die Anzahl der kube-dns-Replikate wird mit der folgenden Formel berechnet:

replicas = max( ceil( cores * 1/coresPerReplica ) , ceil( nodes * 1/nodesPerReplica ) )

Ändern Sie zum vertikalen Skalieren den Wert des Felds nodesPerReplica in einen kleineren Wert und geben Sie einen Wert für das Feld max an.

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

Mit dieser Konfiguration wird ein kube-dns-Pod für jeweils acht Knoten im Cluster erstellt. Ein Cluster mit 24 Knoten hat drei Replikate und ein Cluster mit 40 Knoten hat fünf Replikate. Wenn der Cluster auf mehr als 120 Knoten anwächst, steigt die Anzahl der kube-dns-Replikate nicht über 15 hinaus, was dem Wert des Felds max entspricht.

Legen Sie eine Mindestanzahl von Replikat für das Feld kube-dns fest, um eine grundlegende DNS-Verfügbarkeit in Ihrem Cluster zu gewährleisten.

Die Ausgabe für die kube-dns-autoscaler ConfigMap mit konfiguriertem Feld min sieht etwa so aus:

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

DNS-Lookup-Zeiten verbessern

Mehrere Faktoren können zu einer hohen Latenz bei DNS-Lookups oder DNS-Auflösungsfehlern mit dem Standardanbieter kube-dns führen. Bei Anwendungen können diese Probleme als getaddrinfo EAI_AGAIN-Fehler auftreten, die auf einen vorübergehenden Fehler bei der Namensauflösung hinweisen. Mögliche Ursachen:

  • Häufige DNS-Lookups innerhalb Ihrer Arbeitslast.
  • Hohe Pod-Dichte pro Knoten.
  • Ausführung von kube-dns auf Spot-VMs oder VMs auf Abruf, was zu unerwarteten Knotenlöschungen führen kann.
  • Verbindungslimits:Ältere Versionen von kube-dns (GKE-Version 1.35 und früher) sind auf 200 gleichzeitige TCP-Verbindungen begrenzt. Bei kube-dns auf CoreDNS (GKE-Version 1.36 und höher) werden diese festen Limits für eingehende Verbindungen entfernt und die Kapazität für ausgehende Verbindungen deutlich erhöht.

So verbessern Sie die DNS-Lookup-Zeiten:

  • Vermeiden Sie die Ausführung kritischer Systemkomponenten wie kube-dns auf Spot-VMs oder VMs auf Abruf. Erstellen Sie mindestens einen Knotenpool mit Standard-VMs, der keine Spot-VMs oder VMs auf Abruf enthält. Verwenden Sie Markierungen und Toleranzen, damit kritische Arbeitslasten auf diesen zuverlässigen Knoten geplant werden.
  • Aktivieren Sie NodeLocal DNSCache. NodeLocal DNSCache speichert DNS-Antworten direkt auf jedem Knoten im Cache, wodurch die Latenz und die Last auf den kube-dns-Dienst reduziert werden. Wenn Sie NodeLocal DNSCache aktivieren und Netzwerkrichtlinien mit Standardregeln zum Ablehnen verwenden, fügen Sie eine Richtlinie hinzu, mit der Arbeitslasten DNS-Abfragen an die node-local-dns-Pods senden dürfen.
  • kube-dns vertikal skalieren.
  • Achten Sie darauf, dass Ihre Anwendung dns.resolve*-basierte Funktionen anstelle von dns.lookup-basierten Funktionen verwendet, da dns.lookup synchron ist.
  • Verwenden Sie vollqualifizierte Domainnamen (FQDNs), z. B. https://google.com./ anstelle von https://google.com/.

Während GKE-Clusterupgrades können DNS-Auflösungsfehler auftreten, da Komponenten der Steuerungsebene, einschließlich kube-dns, gleichzeitig aktualisiert werden. Diese Fehler betreffen in der Regel nur einen kleinen Prozentsatz der Knoten. Testen Sie Clusterupgrades gründlich in einer Nicht-Produktionsumgebung, bevor Sie sie auf Produktionscluster anwenden.

Dienstsichtbarkeit gewährleisten

kube-dns erstellt nur DNS-Einträge für Services, die Endpunkte haben. Wenn ein Dienst keine Endpunkte hat, erstellt kube-dns keine DNS-Einträge für diesen Dienst.

DNS-TTL-Abweichungen verwalten

Wenn kube-dns eine DNS-Antwort von einem vorgelagerten DNS-Resolver mit einer großen oder unendlichen TTL empfängt, behält es diesen TTL-Wert bei. Dieses Verhalten kann zu einer Abweichung zwischen dem Eintrag im Cache und der tatsächlichen IP-Adresse führen.

GKE behebt dieses Problem in bestimmten Versionen der Steuerungsebene, z. B. 1.21.14-gke.9100 und höher oder 1.22.15-gke.2100 und höher. In diesen Versionen wird ein maximaler TTL-Wert von 30 Sekunden für jede DNS-Antwort mit einer höheren TTL festgelegt. Dieses Verhalten ähnelt NodeLocal DNSCache.

kube-dns-Messwerte ansehen

Sie können Messwerte zu DNS-Abfragen direkt aus den kube-dns-Pods abrufen. Wie Sie diese Messwerte abrufen, hängt von Ihrer GKE-Version ab.

GKE-Version 1.36 und höher

Wenn in Ihrem Cluster GKE-Version 1.36 oder höher (kube-dns auf CoreDNS) ausgeführt wird, können Sie die DNS-Leistung mit vordefinierten Dashboards in Cloud Monitoring überwachen oder Messwerte manuell aus den Pods abrufen.

Messwerte in der Google Cloud Console ansehen

  1. Rufen Sie in der Google Cloud Console die Seite Dashboards auf.
  2. Wählen Sie das Dashboard GKE DNS Observability - Cluster View aus.

Alternativ können Sie diese Messwerte direkt in der Google Cloud Console abfragen. Rufen Sie dazu Monitoring > Messwert-Explorer auf und suchen Sie nach den spezifischen Messwertnamen.

Messwerte manuell abrufen

So rufen Sie Messwerte manuell aus dem Pod ab:

  1. Suchen Sie die kube-dns-Pods.

    kubectl get pods -n kube-system --selector=k8s-app=kube-dns
    
  2. Leiten Sie Port 9153 an einen der Pods weiter.

    kubectl port-forward pod/POD_NAME -n kube-system 9153:9153
    

    Ersetzen Sie POD_NAME durch den Namen eines der kube-dns-Pods aus der vorherigen Ausgabe.

  3. Greifen Sie auf die Messwerte zu.

    curl http://127.0.0.1:9153/metrics
    

GKE-Version 1.35 und früher

In dieser Version von kube-dns werden Pods mit mehreren Containern verwendet. So rufen Sie Messwerte ab:

  1. Suchen Sie die kube-dns-Pods im kube-system-Namespace.

    kubectl get pods -n kube-system --selector=k8s-app=kube-dns
    
  2. Leiten Sie Ports an die Ports 10055 (für den kube-dns-Container) und 10054 (für den dnsmasq-Container) weiter:

    #For the kube-dns container
    kubectl port-forward pod/POD_NAME -n kube-system 10055:10055
    #For the dnsmasq container
    kubectl port-forward pod/POD_NAME -n kube-system 10054:10054
    

    Ersetzen Sie POD_NAME durch den Namen eines der kube-dns-Pods aus der vorherigen Ausgabe. Führen Sie diese Portweiterleitungsbefehle in separaten Terminalsitzungen aus.

  3. Greifen Sie auf die Messwerte zu.

    #Metrics from the kube-dns container
    curl http://127.0.0.1:10055/metrics
    
    #Metrics from the dnsmasq container
    curl http://127.0.0.1:10054/metrics
    

Nächste Schritte