kube-dns für GKE

Wenn Sie Anwendungen in Standardclustern ausführen, ist kube-dns der standardmäßige DNS-Anbieter, mit dem Sie die Diensterkennung 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. Weitere Informationen zu gängigen Rollen und Aufgaben in Google Cloudfinden Sie unter Häufig verwendete GKE Enterprise-Nutzerrollen und -Aufgaben.

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

kube-dns-Architektur verstehen

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:In diesen Pods wird die kube-dns-Serversoftware ausgeführt. Mehrere Replikate dieser Pods werden im Namespace kube-system ausgeführt und bieten hohe Verfügbarkeit und Redundanz.
  • kube-dns-Dienst:Dieser Kubernetes-Dienst vom Typ ClusterIP gruppiert die kube-dns-Pods und stellt sie als einzelnen, stabilen Endpunkt bereit. Der ClusterIP fungiert als DNS-Server für den Cluster, den Pods zum Senden von DNS-Abfragen verwenden. kube-dns unterstützt bis zu 1.000 Endpunkte pro monitorlosem Dienst.
  • 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. Dieser Ansatz trägt dazu bei, dass kube-dns unterschiedliche DNS-Abfragelasten bewältigen kann.

Interne DNS-Auflösung

Wenn ein Pod einen DNS-Namen in der Clusterdomain auflösen muss, z. B. myservice.my-namespace.svc.cluster.local, läuft der folgende Prozess ab:

  1. Pod-DNS-Konfiguration:Die kubelet auf jedem Knoten konfiguriert die /etc/resolv.conf-Datei des Pods. In dieser Datei wird der kube-dns-Dienst ClusterIP als Nameserver verwendet.
  2. DNS-Anfrage:Der Pod sendet eine DNS-Anfrage an den kube-dns-Dienst.
  3. Namensauflösung:kube-dns empfängt die Anfrage. Er sucht in seinen internen DNS-Einträgen nach der entsprechenden IP-Adresse und antwortet dem Pod.
  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. Die Anfrage wird an vorgelagerte DNS-Server weitergeleitet, die in der Datei ConfigMap 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.

/etc/resolv.conf-Datei konfigurieren

Wenn GKE einen Pod erstellt, ändert der kubelet-Agent die /etc/resolv.conf-Datei des Pods. In dieser Datei wird der DNS-Server für die Namensauflösung konfiguriert und Suchdomains werden 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 in DNS-Abfragen nicht qualifizierte Namen 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 für /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 vollständig qualifiziert, wenn er mindestens fünf Punkte enthält.

Pods, die mit der Einstellung hostNetwork: true konfiguriert sind, übernehmen ihre DNS-Konfiguration vom Host und fragen kube-dns nicht direkt ab.

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 Effizienz der Auflösung zu verbessern oder bevorzugte DNS-Resolver zu verwenden. Sowohl Stub-Domains als auch Upstream-Nameserver werden konfiguriert, indem die kube-dns ConfigMap im Namespace kube-system geändert wird.

ConfigMap kube-dns ändern

So ändern Sie die kube-dns-ConfigMap:

  1. Öffnen Sie die ConfigMap zum Bearbeiten:

    kubectl edit configmap kube-dns -n kube-system
    
  2. Fügen Sie im Abschnitt data die Felder stubDomains und upstreamNameservers 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
          "1.1.1.1" # Cloudflare DNS
        ]
    
  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 Anfrage an den angegebenen Resolver weiter, anstatt den Standardauflösungsmechanismus zu verwenden.

Sie fügen einen stubDomains-Abschnitt in die kube-dns ConfigMap ein.

In diesem Abschnitt werden die Domain und die entsprechenden vorgelagerten Nameserver angegeben. kube-dns leitet dann Anfragen für Namen innerhalb 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 und "internal.mycompany.com": ["192.168.0.10"] zu stubDomains hinzufügen.

Wenn Sie einen benutzerdefinierten Resolver für eine Stub-Domain festlegen, z. B. example.com, leitet kube-dns 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 zum Auflösen externer Domainnamen verwendet werden. 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 Upstream-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-Föderation für GKE aktivieren oder Arbeitslasten haben, die von diesen Domains abhängen, fügen Sie eine Stubs-Domain für internal in 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 GKE-Standardcluster wird kube-dns als Deployment ausgeführt. Bei einer benutzerdefinierten kube-dns-Bereitstellung können Sie als Clusteradministrator die Bereitstellung steuern und an Ihre Anforderungen anpassen, anstatt die standardmäßige von GKE bereitgestellte Bereitstellung zu verwenden.

Gründe für ein benutzerdefiniertes Deployment

Eine benutzerdefinierte kube-dns-Bereitstellung kann aus folgenden Gründen sinnvoll sein:

  • Ressourcenzuweisung:Optimieren Sie CPU- und Arbeitsspeicherressourcen für kube-dns-Pods, um die Leistung in Clustern mit hohem DNS-Traffic zu optimieren.
  • 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 Protokollierungsstufen, Sicherheitsrichtlinien und das DNS-Caching-Verhalten an.

Autoscaling für benutzerdefinierte Deployments

Die integrierte kube-dns-autoscaler-Funktion funktioniert mit der Standardbereitstellung kube-dns. Wenn Sie eine benutzerdefinierte kube-dns-Bereitstellung erstellen, wird sie nicht vom integrierten Autoscaler verwaltet. Daher müssen Sie ein separates Autoscaling einrichten, das speziell für die Überwachung und Anpassung der Anzahl der Replikate Ihrer benutzerdefinierten Bereitstellung konfiguriert ist. Bei dieser Methode erstellen und stellen Sie Ihre eigene Autoscaler-Konfiguration in Ihrem Cluster bereit.

Wenn Sie eine benutzerdefinierte Bereitstellung 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 Ihres 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 die dnsConfig-Suchdomains eines Pods

In Kubernetes ist die Anzahl der DNS-Suchdomains auf 32 begrenzt. Wenn Sie versuchen, mehr als 32 Suchdomains in der dnsConfig eines Pods zu definieren, wird der Pod von kube-apiserver nicht erstellt und es wird ein Fehler ähnlich dem folgenden angezeigt:

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 Reaktion auf einen Versuch zur Pod-Erstellung zurück. Entfernen Sie zusätzliche Suchpfade aus der Konfiguration, um dieses Problem zu beheben.

Upstream-Limit von nameservers für kube-dns

Mit kube-dns wird die Anzahl der upstreamNameservers-Werte auf drei begrenzt. Wenn Sie mehr als drei definieren, wird in Cloud Logging ein Fehler wie der folgende 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 dem kube-dns ConfigMap, um dieses Problem zu beheben.

kube-dns hochskalieren

In Standardclustern können Sie einen niedrigeren Wert für nodesPerReplica verwenden, damit mehr kube-dns-Pods erstellt werden, wenn Clusterknoten 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 das 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 Hochskalieren den Wert des Felds nodesPerReplica in einen kleineren Wert und fügen Sie einen Wert für das Feld max ein.

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

Mit dieser Konfiguration wird ein kube-dns-Pod pro 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 über 120 Knoten hat, steigt die Anzahl der kube-dns-Replikate nicht über 15 an. Dies ist der Wert des Felds max.

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 kube-dns-autoscaler ConfigMap mit dem konfigurierten Feld min sieht in 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 zu DNS-Auflösungsfehlern mit dem Standardanbieter kube-dns führen. In 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.
  • Die Ausführung von kube-dns auf Spot-VMs oder VMs auf Abruf, was zu unerwarteten Knotenlöschungen führen kann.
  • Hohes Anfragevolumen, das die Kapazität der dnsmasq-Instanz im kube-dns-Pod überschreitet. Eine einzelne kube-dns-Instanz hat in GKE-Version 1.31 und höher ein Limit von 200 gleichzeitigen TCP-Verbindungen und in GKE-Version 1.30 und niedriger ein Limit von 20 gleichzeitigen TCP-Verbindungen.

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, um dafür zu sorgen, dass kritische Arbeitslasten auf diesen zuverlässigen Knoten geplant werden.
  • NodeLocal DNSCache aktivieren. NodeLocal DNSCache speichert DNS-Antworten direkt auf jedem Knoten im Cache. Dadurch werden die Latenz und die Last für den kube-dns-Dienst reduziert. Wenn Sie NodeLocal DNSCache aktivieren und Netzwerkrichtlinien mit Standardablehnungsregeln verwenden, fügen Sie eine Richtlinie hinzu, die es Arbeitslasten erlaubt, DNS-Anfragen an die node-local-dns-Pods zu senden.
  • Skalieren Sie kube-dns hoch.
  • Achten Sie darauf, dass Ihre Anwendung dns.resolve*-basierte Funktionen anstelle von dns.lookup-basierten Funktionen verwendet, da dns.lookup synchron ist.
  • Verwenden Sie vollständig qualifizierte Domainnamen (FQDNs), z. B. https://google.com./ anstelle von https://google.com/.

Während GKE-Clusterupgrades können Fehler bei der DNS-Auflösung 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 Cluster-Upgrades gründlich in einer Nicht-Produktionsumgebung, bevor Sie sie auf Produktionscluster anwenden.

Dienstsichtbarkeit sicherstellen

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.

Abweichungen bei der DNS-Gültigkeitsdauer (TTL) verwalten

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

In GKE wird dieses Problem in bestimmten Steuerungsebenenversionen behoben, z. B. in 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 in Ihrem Cluster direkt von den kube-dns-Pods abrufen.

  1. Suchen Sie nach den kube-dns-Pods im Namespace kube-system:

    kubectl get pods -n kube-system --selector=k8s-app=kube-dns
    

    Die Ausgabe sieht etwa so aus:

    NAME                        READY     STATUS    RESTARTS   AGE
    kube-dns-548976df6c-98fkd   4/4       Running   0          48m
    kube-dns-548976df6c-x4xsh   4/4       Running   0          47m
    
  2. Wählen Sie einen der Pods aus und richten Sie die Portweiterleitung ein, um auf die Messwerte dieses Pods zuzugreifen:

    • Über Port 10055 werden kube-dns-Messwerte verfügbar gemacht.
    • Über Port 10054 werden dnsmasq-Messwerte verfügbar gemacht.

    Ersetzen Sie POD_NAME durch den Namen des ausgewählten Pods.

    POD_NAME="kube-dns-548976df6c-98fkd" # Replace with your pod name
    kubectl port-forward pod/${POD_NAME} -n kube-system 10055:10055 10054:10054
    

    Die Ausgabe sieht etwa so aus:

    Forwarding from 127.0.0.1:10054 -> 10054
    Forwarding from 127.0.0.1:10055 -> 10055
    
  3. Verwenden Sie in einer neuen Terminalsitzung den Befehl curl, um auf die Messwertendpunkte zuzugreifen.

    # Get kube-dns metrics
    curl http://127.0.0.1:10055/metrics
    
    # Get dnsmasq metrics
    curl http://127.0.0.1:10054/metrics
    

    Die Ausgabe sollte in etwa so aussehen:

    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
    

Nächste Schritte