À propos de kube-dns pour GKE

Si vous exécutez des applications dans des clusters Standard, kube-dns est le fournisseur DNS par défaut qui vous aide à activer la découverte et la communication des services. Ce document explique comment gérer le DNS avec kube-dns, y compris son architecture, sa configuration et les bonnes pratiques pour optimiser la résolution DNS dans votre environnement GKE.

Ce document s'adresse aux développeurs, aux administrateurs et aux architectes chargés de gérer le DNS dans GKE. Pour en savoir plus sur les rôles et les tâches courants dans Google Cloud, consultez Rôles utilisateur et tâches courantes de GKE.

Avant de commencer, assurez-vous de maîtriser les services Kubernetes et les concepts généraux de DNS.

Comprendre l'architecture kube-dns

kube-dns fonctionne dans votre cluster GKE pour permettre la résolution DNS entre les pods et les services.

Le schéma suivant montre comment vos pods interagissent avec le service kube-dns :

Figure 1 : Schéma montrant comment les pods envoient des requêtes DNS au service `kube-dns`, qui est soutenu par les pods `kube-dns`. Les pods `kube-dns` gèrent la résolution DNS interne et transfèrent les requêtes externes vers les serveurs DNS en amont.

Composants clés

kube-dns inclut les composants clés suivants :

  • kube-dns Pods : ces pods exécutent le logiciel serveur kube-dns. Plusieurs répliques de ces pods s'exécutent dans l'espace de noms kube-system. Elles offrent une haute disponibilité et une redondance.
  • kube-dns Service : le tableau suivant compare les limites de scalabilité et de configuration des versions héritée et basée sur CoreDNS de kube-dns :
    Fonctionnalité Ancienne (kube-dns 1.35 et versions antérieures) kube-dns sur CoreDNS (1.36 et versions ultérieures)
    Notoriété des points de terminaison Connaît jusqu'à 1 000 points de terminaison par service. Si un service comporte plus de 1 000 pods, kube-dns n'a pas connaissance des points de terminaison supplémentaires. Connaître tous les points de terminaison. Cette version utilise EndpointSlices pour garantir l'exactitude et améliorer l'efficacité des services volumineux.
    Serveurs de noms en amont Limité à trois Jusqu'à 15
    Connexions TCP sortantes simultanées Limitée à 200 Jusqu'à 1 500
  • kube-dns-autoscaler : ce pod ajuste le nombre de répliques kube-dns en fonction de la taille du cluster, qui inclut le nombre de nœuds et de cœurs de processeur. Cette approche permet de s'assurer que kube-dns peut gérer différentes charges de requêtes DNS.

Résolution DNS interne

Lorsqu'un pod doit résoudre un nom DNS dans le domaine du cluster, tel que myservice.my-namespace.svc.cluster.local, le processus suivant se produit :

  1. Configuration DNS du pod : le fichier kubelet de chaque nœud configure le fichier /etc/resolv.conf du pod. Ce fichier utilise le ClusterIP du service kube-dns comme serveur de noms.
  2. Requête DNS : le pod envoie une requête DNS au service kube-dns.
  3. Résolution de noms :

    • GKE version 1.36 ou ultérieure : l'implémentation basée sur CoreDNS utilise des EndpointSlices pour que kube-dns soit au courant de tous les pods d'un service. Cela améliore l'exactitude et l'efficacité des services à grande échelle.
    • GKE version 1.35 ou antérieure : kube-dns résout les noms en fonction de l'ancienne API Cloud Endpoints, qui est limitée à 1 000 points de terminaison. Si un service comporte plus de 1 000 pods de sauvegarde, kube-dns ne connaît pas les points de terminaison supplémentaires.
  4. Communication : le pod utilise ensuite l'adresse IP résolue pour communiquer avec le service cible.

Résolution DNS externe

Lorsqu'un pod doit résoudre un nom DNS externe ou un nom qui se trouve en dehors du domaine du cluster, kube-dns agit comme un résolveur récursif. Il transmet la requête aux serveurs DNS en amont configurés dans son fichier ConfigMap. Vous pouvez également configurer des résolveurs personnalisés pour des domaines spécifiques, également appelés domaines de simulation. Cette configuration indique à kube-dns de transférer les requêtes pour ces domaines vers des serveurs DNS spécifiques en amont.

Configurer le DNS de pod

Dans GKE, l'agent kubelet sur chaque nœud configure les paramètres DNS pour les pods qui s'exécutent sur ce nœud.

Configurer le fichier /etc/resolv.conf

Lorsque GKE crée un pod, l'agent kubelet modifie le fichier /etc/resolv.conf du pod. Ce fichier configure le serveur DNS pour la résolution de noms et spécifie les domaines de recherche. Par défaut, kubelet configure le pod pour qu'il utilise le service DNS interne du cluster, kube-dns, comme serveur de noms. Il remplit également les domaines de recherche dans le fichier. Ces domaines de recherche vous permettent d'utiliser des noms non qualifiés dans les requêtes DNS. Par exemple, si un pod interroge myservice, Kubernetes tente d'abord de résoudre myservice.default.svc.cluster.local, puis myservice.svc.cluster.local, puis d'autres domaines de la liste search.

L'exemple suivant montre une configuration /etc/resolv.conf par défaut :

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

Ce fichier contient les entrées suivantes :

  • nameserver : définit le ClusterIP du service kube-dns.
  • search : définit les domaines de recherche qui sont ajoutés aux noms non qualifiés lors des recherches DNS.
  • options ndots:5 : définit le seuil à partir duquel GKE considère qu'un nom est complet. Un nom est considéré comme complet s'il comporte au moins cinq points.

Les pods configurés avec hostNetwork: true héritent de leur configuration DNS de l'hôte et n'interrogent pas directement kube-dns, sauf s'ils utilisent ClusterFirstWithHostNet dnsPolicy.

Personnaliser kube-dns

kube-dns fournit une résolution DNS par défaut robuste. Vous pouvez adapter son comportement à des besoins spécifiques, comme améliorer l'efficacité de la résolution ou utiliser des résolveurs DNS préférés. Les domaines de simulation et les serveurs de noms en amont sont configurés en modifiant le ConfigMap kube-dns dans l'espace de noms kube-system.

Modifier le fichier ConfigMap kube-dns

Pour modifier le ConfigMap kube-dns, procédez comme suit :

  1. Ouvrez le ConfigMap pour le modifier :

    kubectl edit configmap kube-dns -n kube-system
    
  2. Dans la section data, ajoutez les champs stubDomains et upstreamNameservers comme suit :

    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. Enregistrez le ConfigMap. kube-dns recharge automatiquement la configuration.

Domaines de simulation

Les domaines de simulation vous permettent de définir des résolveurs DNS personnalisés pour des domaines spécifiques. Lorsqu'un pod interroge un nom dans ce domaine stub, kube-dns transmet la requête au résolveur spécifié au lieu d'utiliser son mécanisme de résolution par défaut.

Vous incluez une section stubDomains dans le kube-dns ConfigMap.

Cette section spécifie le domaine et les serveurs de noms en amont correspondants. kube-dns transmet ensuite les requêtes de noms dans ce domaine aux serveurs désignés. Par exemple, vous pouvez acheminer toutes les requêtes DNS pour internal.mycompany.com vers 192.168.0.10 et ajouter "internal.mycompany.com": ["192.168.0.10"] à stubDomains.

Lorsque vous configurez un résolveur personnalisé pour un domaine de simulation, tel que example.com, kube-dns transfère toutes les requêtes de résolution de noms pour ce domaine, y compris les sous-domaines tels que *.example.com, vers les serveurs spécifiés.

Serveurs de noms en amont

Vous pouvez configurer kube-dns pour qu'il utilise des serveurs de noms en amont personnalisés afin de résoudre les noms de domaine externes. Cette configuration indique à kube-dns de transférer toutes les requêtes DNS, à l'exception de celles concernant le domaine interne du cluster (*.cluster.local), vers les serveurs en amont désignés. Il est possible que vos serveurs en amont personnalisés ne puissent pas résoudre les domaines internes tels que metadata.internal et *.google.internal. Si vous activez la fédération d'identité de charge de travail pour GKE ou si vous avez des charges de travail qui dépendent de ces domaines, ajoutez un domaine stub pour internal dans ConfigMap. Utilisez 169.254.169.254, l'adresse IP du serveur de métadonnées, comme résolveur pour ce domaine stub.

Gérer un déploiement kube-dns personnalisé

Dans un cluster Standard, kube-dns s'exécute en tant que déploiement. Un déploiement kube-dns personnalisé signifie que vous, en tant qu'administrateur du cluster, pouvez contrôler le déploiement et le personnaliser en fonction de vos besoins, au lieu d'utiliser le déploiement par défaut fourni par GKE.

Motifs d'un déploiement personnalisé

Envisagez un déploiement kube-dns personnalisé pour les raisons suivantes :

  • Allocation des ressources : ajustez précisément les ressources de processeur et de mémoire pour les pods kube-dns afin d'optimiser les performances dans les clusters avec un trafic DNS élevé.
  • Version de l'image : utilisez une version spécifique de l'image kube-dns ou passez à un autre fournisseur DNS, comme CoreDNS.
  • Configuration avancée : personnalisez les niveaux de journalisation, les règles de sécurité et le comportement de mise en cache DNS.

Autoscaling pour les déploiements personnalisés

La fonction intégrée kube-dns-autoscaler fonctionne avec le déploiement kube-dns par défaut. Si vous créez un déploiement kube-dns personnalisé, l'autoscaler intégré ne le gère pas. Par conséquent, vous devez configurer un autoscaler distinct, spécifiquement conçu pour surveiller et ajuster le nombre de répliques de votre déploiement personnalisé. Cette approche consiste à créer et à déployer votre propre configuration d'autoscaler dans votre cluster.

Lorsque vous gérez un déploiement personnalisé, vous êtes responsable de tous ses composants, comme la mise à jour de l'image de l'autoscaler. L'utilisation de composants obsolètes peut entraîner une dégradation des performances ou des échecs DNS.

Pour obtenir des instructions détaillées sur la configuration et la gestion de votre propre déploiement kube-dns, consultez Configurer un déploiement kube-dns personnalisé.

Résoudre les problèmes

Pour savoir comment résoudre les problèmes liés à kube-dns, consultez les pages suivantes :

Optimiser la résolution DNS

Cette section décrit les problèmes courants et les bonnes pratiques pour gérer le DNS dans GKE.

Limite de domaines de recherche dnsConfig d'un pod

Kubernetes limite le nombre de domaines de recherche DNS à 32. Si vous essayez de définir plus de 32 domaines de recherche dans le dnsConfig d'un pod, le kube-apiserver ne créera pas le pod et affichera une erreur semblable à la suivante :

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 renvoie ce message d'erreur en réponse à une tentative de création de pod. Pour résoudre ce problème, supprimez les chemins de recherche supplémentaires de la configuration.

Limite nameservers en amont pour kube-dns

Les anciennes versions de kube-dns (version 1.35 et antérieures) limitent le nombre de upstreamNameservers à trois. Si vous en définissez plus de trois, Cloud Logging affiche une erreur semblable à la suivante :

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

Dans ce cas, kube-dns ignore la configuration upstreamNameservers et continue d'utiliser la configuration valide précédente. Pour résoudre ce problème, supprimez les upstreamNameservers supplémentaires de kube-dns ConfigMap.

Augmenter la capacité de kube-dns

Dans les clusters Standard, vous pouvez utiliser une valeur inférieure pour nodesPerReplica afin de créer davantage de pods kube-dns lorsque les nœuds du cluster évoluent à la hausse. Nous vous recommandons vivement de définir une valeur explicite pour le champ max afin de vous assurer que la machine virtuelle (VM) du plan de contrôle GKE n'est pas submergée par le grand nombre de pods kube-dns qui surveillent l'API Kubernetes.

Vous pouvez définir la valeur du champ max sur le nombre de nœuds du cluster. Si le cluster comporte plus de 500 nœuds, définissez la valeur du champ max sur 500.

Vous pouvez modifier le nombre de répliques kube-dns en modifiant le ConfigMap kube-dns-autoscaler.

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

Le résultat ressemble à ce qui suit :

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

Le nombre d'instances répliquées kube-dns est calculé à l'aide de la formule suivante :

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

Pour effectuer un scaling à la hausse, réduisez la valeur du champ nodesPerReplica et incluez une valeur pour le champ max.

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

Cette configuration crée un pod kube-dns pour chacun des huit nœuds du cluster. Un cluster de 24 nœuds comporte trois instances dupliquées, tandis qu'un cluster de 40 nœuds en comporte cinq. Si le cluster dépasse 120 nœuds, le nombre d'instances dupliquées kube-dns ne dépasse pas 15, qui est la valeur du champ max.

Pour garantir un niveau de disponibilité du DNS de base dans votre cluster, définissez un nombre minimal d'instances dupliquées pour le champ kube-dns.

Le résultat de kube-dns-autoscaler ConfigMap avec le champ min configuré ressemble à ce qui suit :

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

Améliorer les durées des résolution DNS

Plusieurs facteurs peuvent entraîner une latence élevée avec les résolutions DNS ou des échecs de résolution DNS avec le fournisseur kube-dns par défaut. Les applications peuvent rencontrer ces problèmes sous la forme d'erreurs getaddrinfo EAI_AGAIN, qui indiquent un échec temporaire de la résolution de noms. Voici quelques exemples de causes :

  • Résolutions DNS fréquentes dans votre charge de travail.
  • Densité de pods élevée par nœud.
  • Vous exécutez kube-dns sur des VM Spot ou préemptives, ce qui peut entraîner des suppressions inattendues de nœuds.
  • Limites de connexion : les anciennes versions de kube-dns (GKE version 1.35 et versions antérieures) sont limitées à 200 connexions TCP simultanées. kube-dns sur CoreDNS (GKE version 1.36 et ultérieures) supprime ces limites fixes pour les connexions entrantes et offre une capacité beaucoup plus élevée pour les connexions sortantes.

Pour améliorer les durées des résolution DNS :

  • Évitez d'exécuter des composants système critiques tels que kube-dns sur des VM Spot ou préemptives. Créez au moins un pool de nœuds doté de VM standards, mais pas de VM Spot ni de VM préemptives. Utilisez des rejets et des tolérances pour vous assurer que les charges de travail critiques sont planifiées sur ces nœuds fiables.
  • Activez NodeLocal DNSCache. NodeLocal DNSCache met en cache les réponses DNS directement sur chaque nœud, ce qui réduit la latence et la charge sur le service kube-dns. Si vous activez NodeLocal DNSCache et que vous utilisez des règles de réseau avec des règles de refus par défaut, ajoutez une règle pour autoriser les charges de travail à envoyer des requêtes DNS aux pods node-local-dns.
  • Effectuez un scaling à la hausse de kube-dns.
  • Assurez-vous que votre application utilise des fonctions basées sur dns.resolve* plutôt que sur dns.lookup, car dns.lookup est synchrone.
  • Utilisez des noms de domaine complets, par exemple https://google.com./ au lieu de https://google.com/.

Des échecs de résolution DNS peuvent survenir lors des mises à niveau du cluster GKE en raison de mises à niveau simultanées des composants du plan de contrôle, y compris kube-dns. Ces échecs affectent généralement un faible pourcentage de nœuds. Testez soigneusement les mises à niveau de cluster dans un environnement hors production avant de les appliquer aux clusters de production.

Assurer la visibilité des services

kube-dns ne crée des enregistrements DNS que pour les services qui possèdent des points de terminaison. Si un service ne possède aucun point de terminaison, kube-dns ne crée pas d'enregistrements DNS pour ce service.

Gérer les différences de TTL DNS

Si kube-dns reçoit une réponse DNS d'un résolveur DNS en amont avec une valeur TTL élevée ou infinie, il conserve cette valeur TTL. Ce comportement peut créer un écart entre l'entrée mise en cache et l'adresse IP réelle.

GKE résout ce problème dans des versions spécifiques du plan de contrôle, telles que 1.21.14-gke.9100 et ultérieures, ou 1.22.15-gke.2100 et ultérieures. Ces versions définissent une valeur TTL maximale de 30 secondes pour toute réponse DNS dont la valeur TTL est supérieure. Ce comportement est semblable à celui de NodeLocal DNSCache.

Afficher les métriques kube-dns

Vous pouvez récupérer des métriques sur les requêtes DNS directement à partir des pods kube-dns. La façon dont vous récupérez ces métriques dépend de votre version de GKE.

GKE version 1.36 et ultérieure

Si votre cluster exécute la version 1.36 ou ultérieure de GKE (kube-dns sur CoreDNS), vous pouvez surveiller les performances DNS à l'aide de tableaux de bord prédéfinis dans Cloud Monitoring ou récupérer manuellement les métriques à partir des pods.

Afficher les métriques dans la console Google Cloud

  1. Dans la console Google Cloud , accédez à la page Tableaux de bord.
  2. Sélectionnez le tableau de bord Observabilité DNS GKE – Vue du cluster.

Vous pouvez également interroger ces métriques directement dans la console Google Cloud en accédant à Monitoring > Explorateur de métriques et en recherchant les noms de métriques spécifiques.

Récupérer les métriques manuellement

Pour récupérer manuellement les métriques du pod, procédez comme suit :

  1. Recherchez les pods kube-dns.

    kubectl get pods -n kube-system --selector=k8s-app=kube-dns
    
  2. Transférez le port 9153 vers l'un des pods.

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

    Remplacez POD_NAME par le nom de l'un des pods kube-dns de la sortie précédente.

  3. Accédez aux métriques.

    curl http://127.0.0.1:9153/metrics
    

GKE version 1.35 et versions antérieures

Cette version de kube-dns utilise des pods multiconteneurs. Pour récupérer les métriques, procédez comme suit :

  1. Recherchez les pods kube-dns dans l'espace de noms kube-system.

    kubectl get pods -n kube-system --selector=k8s-app=kube-dns
    
  2. Transférez les ports 10055 (pour le conteneur kube-dns) et 10054 (pour le conteneur dnsmasq) :

    #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
    

    Remplacez POD_NAME par le nom de l'un des pods kube-dns de la sortie précédente. Exécutez ces commandes de transfert de port dans des sessions de terminal distinctes.

  3. Accédez aux métriques.

    #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
    

Étapes suivantes