Résoudre les problèmes liés à kube-dns dans GKE

Si vous utilisez kube-dns pour la détection de services, vous pouvez rencontrer des erreurs de connexion telles que dial tcp: i/o timeout ou no such host. Ces erreurs indiquent souvent des problèmes avec les pods kube-dns dans l'espace de noms kube-system, tels que des configurations incorrectes, des limites de ressources ou des problèmes de connectivité réseau affectant ces pods.

Cette page vous permet de diagnostiquer et de résoudre les problèmes courants spécifiques au déploiement kube-dns, afin de garantir une résolution DNS fiable pour vos charges de travail.

Ces informations sont importantes pour les administrateurs et opérateurs de plate-forme, qui sont responsables de la maintenance des composants de base du cluster tels que kube-dns, et pour les développeurs d'applications, dont les applications en dépendent pour se connecter à d'autres services du cluster. Pour en savoir plus sur les rôles courants et les exemples de tâches que nous citons dans le contenu Google Cloud , consultez Rôles utilisateur et tâches courantes de GKE.

Identifier la source des problèmes DNS dans kube-dns

Les sections suivantes vous aident à diagnostiquer pourquoi kube-dns a du mal à résoudre les requêtes.

Vérifier si les pods kube-dns sont en cours d'exécution

Les pods kube-dns sont essentiels pour la résolution de noms dans le cluster. Si ce n'est pas le cas, vous risquez de rencontrer des problèmes de résolution DNS.

Pour vérifier que les pods kube-dns sont en cours d'exécution sans redémarrage récent, consultez l'état de ces pods :

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

Le résultat ressemble à ce qui suit :

NAME                   READY          STATUS          RESTARTS       AGE
kube-dns-POD_ID_1      5/5            Running         0              16d
kube-dns-POD_ID_2      0/5            Terminating     0              16d

Dans ce résultat, POD_ID_1 et POD_ID_2 représentent des identifiants uniques qui sont automatiquement ajoutés aux pods kube-dns.

Si le résultat indique que l'un de vos pods kube-dns n'a pas l'état Running, suivez les étapes suivantes :

  1. Utilisez les journaux d'audit des activités d'administration pour vérifier si des modifications récentes ont été apportées, comme des mises à niveau de la version du cluster ou du pool de nœuds, ou des modifications du ConfigMap kube-dns. Pour en savoir plus sur les journaux d'audit, consultez Informations sur les journaux d'audit GKE. Si vous constatez des modifications, rétablissez-les et affichez à nouveau l'état des pods.

  2. Si vous ne trouvez aucune modification récente pertinente, vérifiez si vous rencontrez une erreur OOM sur le nœud sur lequel le pod kube-dns s'exécute. Si un message d'erreur semblable à celui-ci s'affiche dans vos messages de journalisation Cloud Logging, cela signifie que ces pods rencontrent une erreur OOM :

    Warning: OOMKilling Memory cgroup out of memory
    

    Ce message indique que Kubernetes a arrêté un processus en raison d'une consommation excessive de ressources. Kubernetes planifie les pods en fonction des demandes de ressources, mais leur permet de consommer jusqu'à leurs limites de ressources. Si les limites sont supérieures aux demandes ou s'il n'y a pas de limites, l'utilisation des ressources du pod peut dépasser les ressources du système.

    Pour résoudre cette erreur, vous pouvez supprimer les charges de travail problématiques ou définir des limites de mémoire ou de processeur. Pour en savoir plus sur la définition de limites, consultez Gestion des ressources pour les pods et les conteneurs dans la documentation Kubernetes. Pour en savoir plus sur les événements OOM, consultez Résoudre les problèmes liés aux événements OOM.

  3. Si vous ne trouvez aucun message d'erreur OOM, redémarrez le déploiement kube-dns :

    kubectl rollout restart deployment/kube-dns --namespace=kube-system
    

    Après avoir redémarré le déploiement, vérifiez si vos pods kube-dns sont en cours d'exécution.

Si ces étapes ne fonctionnent pas ou si tous vos pods kube-dns ont l'état Running, mais que vous rencontrez toujours des problèmes DNS, vérifiez que le fichier /etc/resolv.conf est correctement configuré.

Vérifiez que /etc/resolv.conf est correctement configuré.

Examinez le fichier /etc/resolv.conf des pods qui rencontrent des problèmes DNS et assurez-vous que les entrées qu'il contient sont correctes :

  1. Affichez le fichier /etc/resolv.conf du pod :

    kubectl exec -it POD_NAME -- cat /etc/resolv.conf
    

    Remplacez POD_NAME par le nom du pod qui rencontre des problèmes de DNS. Si plusieurs pods rencontrent des problèmes, répétez les étapes de cette section pour chacun d'eux.

    Si le binaire du pod n'est pas compatible avec la commande kubectl exec, cette commande peut échouer. Si cela se produit, créez un pod simple à utiliser comme environnement de test. Cette procédure vous permet d'exécuter un pod de test dans le même espace de noms que votre pod problématique.

  2. Vérifiez que l'adresse IP du serveur de noms dans le fichier /etc/resolv.conf est correcte :

    • Les pods qui utilisent un réseau hôte doivent utiliser les valeurs du fichier /etc/resolv.conf du nœud. L'adresse IP du serveur de noms doit être 169.254.169.254.
    • Pour les pods qui n'utilisent pas de réseau hôte, l'adresse IP du service kube-dns doit être identique à l'adresse IP du serveur de noms. Pour comparer les adresses IP, procédez comme suit :

      1. Récupérez l'adresse IP du service kube-dns :

        kubectl get svc kube-dns -n kube-system
        

        Le résultat ressemble à ce qui suit :

        NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
        kube-dns   ClusterIP   192.0.2.10   <none>        53/UDP,53/TCP   64d
        
      2. Notez la valeur de la colonne "Adresse IP du cluster". Dans cet exemple, il s'agit de 192.0.2.10.

      3. Comparez l'adresse IP du service kube-dns à l'adresse IP du fichier /etc/resolv.conf :

        # cat /etc/resolv.conf
        
        search default.svc.cluster.local svc.cluster.local cluster.local c.PROJECT_NAME google.internal
        nameserver 192.0.2.10
        options ndots:5
        

        Dans cet exemple, les deux valeurs correspondent. Par conséquent, une adresse IP de serveur de noms incorrecte n'est pas à l'origine de votre problème.

        Toutefois, si les adresses IP ne correspondent pas, cela signifie qu'un champ dnsConfig est configuré dans le fichier manifeste du pod d'application.

        Si la valeur du champ dnsConfig.nameservers est correcte, examinez votre serveur DNS et assurez-vous qu'il fonctionne correctement.

        Si vous ne souhaitez pas utiliser le serveur de noms personnalisé, supprimez le champ et effectuez un redémarrage progressif du pod :

        kubectl rollout restart deployment POD_NAME
        

        Remplacez POD_NAME par le nom de votre pod.

  3. Vérifiez les entrées search et ndots dans /etc/resolv.conf. Assurez-vous qu'il n'y a pas de fautes d'orthographe ni de configurations obsolètes, et que la requête défaillante pointe vers un service existant dans l'espace de noms approprié.

Effectuer une résolution DNS

Après avoir vérifié que /etc/resolv.conf est correctement configuré et que l'enregistrement DNS est correct, utilisez l'outil de ligne de commande dig pour effectuer des résolutions DNS à partir du pod qui signale des erreurs DNS :

  1. Interrogez directement un pod en ouvrant un shell à l'intérieur :

    kubectl exec -it POD_NAME -n NAMESPACE_NAME -- SHELL_NAME
    

    Remplacez les éléments suivants :

    • POD_NAME : nom du pod qui signale des erreurs DNS.
    • NAMESPACE_NAME : espace de noms auquel appartient le pod.
    • SHELL_NAME : nom du shell que vous souhaitez ouvrir. Par exemple, sh ou /bin/bash.

    Cette commande peut échouer si votre pod n'autorise pas la commande kubectl exec ou s'il ne dispose pas du binaire dig. Si cela se produit, créez un pod de test avec une image sur laquelle dig est installé :

    kubectl run "test-$RANDOM" ti --restart=Never --image=thockin/dnsutils - bash
    
  2. Vérifiez si le pod peut résoudre correctement le service DNS interne du cluster :

    dig kubernetes
    

    Étant donné que le fichier /etc/resolv.conf pointe vers l'adresse IP du service kube-dns, lorsque vous exécutez cette commande, le serveur DNS est le service kube-dns.

    Vous devriez voir une réponse DNS réussie avec l'adresse IP du service d'API Kubernetes (souvent quelque chose comme 10.96.0.1). Si vous voyez SERVFAIL ou aucune réponse, cela indique généralement que le pod kube-dns ne parvient pas à résoudre les noms de services internes.

  3. Vérifiez si le service kube-dns peut résoudre un nom de domaine externe :

    dig example.com
    
  4. Si vous rencontrez des difficultés avec un pod kube-dns spécifique qui répond aux requêtes DNS, vérifiez si ce pod peut résoudre un nom de domaine externe :

     dig example.com @KUBE_DNS_POD_IP
    

    Remplacez KUBE_DNS_POD_IP par l'adresse IP du pod kube-dns. Si vous ne connaissez pas la valeur de cette adresse IP, exécutez la commande suivante :

     kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
    

    L'adresse IP se trouve dans la colonne IP.

    Si la résolution de la commande aboutit, status: NOERROR et les détails de l'enregistrement A s'affichent, comme dans l'exemple suivant :

     ; <<>> DiG 9.16.27 <<>> example.com
     ;; global options: +cmd
     ;; Got answer:
     ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31256
     ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
     ;; OPT PSEUDOSECTION:
     ; EDNS: version: 0, flags:; udp: 512
     ;; QUESTION SECTION:
     ;example.com.                   IN      A
    
     ;; ANSWER SECTION:
     example.com.            30      IN      A       93.184.215.14
    
     ;; Query time: 6 msec
     ;; SERVER: 10.76.0.10#53(10.76.0.10)
     ;; WHEN: Tue Oct 15 16:45:26 UTC 2024
     ;; MSG SIZE  rcvd: 56
    
  5. Quittez l'interface système :

    exit
    

Si l'une de ces commandes échoue, effectuez un redémarrage progressif du déploiement kube-dns :

kubectl rollout restart deployment/kube-dns --namespace=kube-system

Une fois le redémarrage terminé, réessayez les commandes dig et vérifiez si elles fonctionnent désormais. Si elles échouent toujours, effectuez une capture de paquets.

Effectuer une capture de paquets

Effectuez une capture de paquets pour vérifier si les requêtes DNS sont reçues et traitées correctement par les pods kube-dns :

  1. À l'aide de SSH, connectez-vous au nœud exécutant le pod kube-dns. Exemple :

    1. Dans la console Google Cloud , accédez à la page Instances de VM.

      Accéder à la page "Instances de VM"

    2. Recherchez le nœud auquel vous souhaitez vous connecter. Si vous ne connaissez pas le nom du nœud sur votre pod kube-dns, exécutez la commande suivante :

      kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
      

      Le nom du nœud est indiqué dans la colonne Nœud.

    3. Dans la colonne Connecter, cliquez sur SSH.

  2. Dans le terminal, démarrez toolbox, un outil de débogage préinstallé :

    toolbox
    
  3. Dans l'invite racine, installez le package tcpdump :

    apt update -y && apt install -y tcpdump
    
  4. À l'aide de tcpdump, capturez les paquets de votre trafic DNS :

    tcpdump -i eth0 port 53" -w FILE_LOCATION
    

    Remplacez FILE_LOCATION par le chemin d'accès à l'emplacement où vous souhaitez enregistrer la capture.

  5. Examinez la capture de paquets. Vérifiez s'il existe des paquets dont les adresses IP de destination correspondent à l'adresse IP du service kube-dns. Cela permet de s'assurer que les requêtes DNS sont acheminées vers la bonne destination pour la résolution. Si le trafic DNS n'arrive pas sur les pods appropriés, cela peut indiquer la présence d'une règle de réseau qui bloque les requêtes.

Rechercher une règle de réseau

Des règles de réseau restrictives peuvent parfois perturber le trafic DNS. Pour vérifier si une règle de réseau existe dans l'espace de noms kube-system, exécutez la commande suivante :

kubectl get networkpolicy -n kube-system

Si vous trouvez une règle de réseau, examinez-la et assurez-vous qu'elle autorise la communication DNS nécessaire. Par exemple, si vous avez une règle de réseau qui bloque tout le trafic sortant, elle bloquera également les requêtes DNS.

Si la sortie est No resources found in kube-system namespace, cela signifie que vous n'avez aucune règle de réseau et que vous pouvez exclure cette cause pour votre problème. L'examen des journaux peut vous aider à identifier d'autres points de défaillance.

Activer la journalisation temporaire des requêtes DNS

Pour vous aider à identifier les problèmes tels que des réponses DNS incorrectes, activez temporairement la journalisation de débogage des requêtes DNS. Pour activer les requêtes, créez un pod basé sur un pod kube-dns existant. Toute modification apportée au déploiement kube-dns est automatiquement annulée.

L'activation de la journalisation temporaire des requêtes DNS est une procédure gourmande en ressources. Nous vous recommandons donc de supprimer le pod que vous créez dès que vous avez collecté un échantillon de journaux approprié.

Pour activer la journalisation temporaire des requêtes DNS, procédez comme suit :

  1. Récupérez un pod kube-dns et stockez-le dans une variable nommée POD :

    POD=$(kubectl -n kube-system get pods --selector=k8s-app=kube-dns -o jsonpath="{.items[0].metadata.name}")
    
  2. Créez un pod nommé kube-dns-debug. Ce pod est une copie du pod stocké dans la variable POD, mais avec la journalisation dnsmasq activée. Cette commande ne modifie pas le pod kube-dns d'origine :

    kubectl apply -f <(kubectl get pod -n kube-system ${POD} -o json | jq -e '
    
    (
    
    (.spec.containers[] | select(.name == "dnsmasq") | .args) += ["--log-queries"]
    
    )
    
    | (.metadata.name = "kube-dns-debug")
    
    | (del(.metadata.labels."pod-template-hash"))
    
    ')
    
  3. Inspectez les journaux :

    kubectl logs -f --tail 100 -c dnsmasq -n kube-system kube-dns-debug
    

    Vous pouvez également consulter les requêtes dans Cloud Logging.

  4. Une fois que vous avez terminé de consulter les journaux de requêtes DNS, supprimez le pod kube-dns-debug :

    kubectl -n kube-system delete pod kube-dns-debug
    

Examiner le pod kube-dns

Découvrez comment les pods kube-dns reçoivent et résolvent les requêtes DNS avec Cloud Logging.

Pour afficher les entrées de journal liées au pod kube-dns, procédez comme suit :

  1. Dans la console Google Cloud , accédez à la page Explorateur de journaux.

    Accéder à l'explorateur de journaux

  2. Dans le volet de requête, saisissez le filtre suivant pour afficher les événements liés au conteneur kube-dns :

    resource.type="k8s_container"
    resource.labels.namespace_name="kube-system"
    resource.labels.pod_name:"kube-dns"
    resource.labels.cluster_name="CLUSTER_NAME"
    resource.labels.location="CLUSTER_LOCATION"
    

    Remplacez les éléments suivants :

    • CLUSTER_NAME : nom du cluster auquel appartient le pod kube-dns.
    • CLUSTER_LOCATION : emplacement de votre cluster.
  3. Cliquez sur Exécuter la requête.

  4. Examinez le résultat. L'exemple de résultat suivant montre une erreur possible :

    {
       "timestamp": "2024-10-10T15:32:16.789Z",
       "severity": "ERROR",
       "resource": {
          "type": "k8s_container",
          "labels": {
          "namespace_name": "kube-system",
          "pod_name": "kube-dns",
          "cluster_name": "CLUSTER_NAME",
          "location": "CLUSTER_LOCATION"
          }
       },
       "message": "Failed to resolve 'example.com': Timeout."
    },
    

    Dans cet exemple, kube-dns n'a pas pu résoudre example.com dans un délai raisonnable. Ce type d'erreur peut être dû à plusieurs problèmes. Par exemple, le serveur en amont peut être mal configuré dans le fichier ConfigMap de kube-dns, ou le trafic réseau peut être élevé.

Si Cloud Logging n'est pas activé, affichez plutôt les journaux Kubernetes :

Pod=$(kubectl get Pods -n kube-system -l k8s-app=kube-dns -o name | head -n1)
kubectl logs -n kube-system $Pod -c dnsmasq
kubectl logs -n kube-system $Pod -c kubedns
kubectl logs -n kube-system $Pod -c sidecar

Examiner les modifications récentes apportées au ConfigMap kube-dns

Si vous rencontrez soudainement des échecs de résolution DNS dans votre cluster, l'une des causes possibles est une modification incorrecte de la configuration apportée au fichier ConfigMap de kube-dns. En particulier, les modifications de configuration apportées aux définitions des domaines de simulation et des serveurs en amont peuvent entraîner des problèmes.

Pour vérifier si les paramètres du domaine stub ont été mis à jour, procédez comme suit :

  1. Dans la console Google Cloud , accédez à la page Explorateur de journaux.

    Accéder à l'explorateur de journaux

  2. Dans le volet "Requête", saisissez la requête suivante :

    resource.labels.cluster_name="clouddns"
    resource.type="k8s_container"
    resource.labels.namespace_name="kube-system"
    labels.k8s-pod/k8s-app="kube-dns" jsonPayload.message=~"Updated stubDomains to"
    
  3. Cliquez sur Exécuter la requête.

  4. Examinez le résultat. Si des mises à jour ont été effectuées, le résultat ressemble à ce qui suit :

    Updated stubDomains to map[example.com: [8.8.8.8 8.8.4.4 1.1.3.3 1.0.8.111]]
    

    Si une mise à jour est disponible, développez le résultat pour en savoir plus sur les modifications. Vérifiez que les domaines de simulation et leurs serveurs DNS en amont correspondants sont correctement définis. Des entrées incorrectes peuvent entraîner des échecs de résolution pour ces domaines.

Pour vérifier si le serveur en amont a été modifié, procédez comme suit :

  1. Dans la console Google Cloud , accédez à la page Explorateur de journaux.

    Accéder à l'explorateur de journaux

  2. Dans le volet Requête, saisissez la requête suivante :

    resource.labels.cluster_name="clouddns"
    resource.type="k8s_container" resource.labels.namespace_name="kube-system"
    labels.k8s-pod/k8s-app="kube-dns" jsonPayload.message=~"Updated upstreamNameservers to"
    
  3. Cliquez sur Exécuter la requête.

  4. Examinez le résultat. Si des modifications ont été apportées, le résultat ressemble à ce qui suit :

    Updated upstreamNameservers to [8.8.8.8]
    

    Développez le résultat pour en savoir plus sur les modifications. Vérifiez que la liste des serveurs DNS en amont est exacte et que ces serveurs sont accessibles depuis votre cluster. Si ces serveurs ne sont pas disponibles ou sont mal configurés, la résolution DNS générale peut échouer.

Si vous avez vérifié les modifications apportées aux domaines stub et aux serveurs en amont, mais que vous n'avez trouvé aucun résultat, recherchez toutes les modifications avec le filtre suivant :

resource.type="k8s_cluster"
protoPayload.resourceName:"namespaces/kube-system/configmaps/kube-dns"
protoPayload.methodName=~"io.k8s.core.v1.configmaps."

Examinez les modifications listées pour voir si elles sont à l'origine de l'erreur.

Contacter Cloud Customer Care

Si vous avez suivi les sections précédentes, mais que vous ne parvenez toujours pas à diagnostiquer la cause de votre problème, contactez Cloud Customer Care.

Résoudre les problèmes les plus courants

Si vous avez rencontré une erreur ou un problème spécifique, suivez les conseils des sections suivantes.

Problème : délais avant expiration DNS intermittents

Si vous constatez des délais avant expiration intermittents de la résolution DNS qui se produisent lorsque le trafic DNS augmente ou lorsque les horaires d'ouverture commencent, essayez les solutions suivantes pour optimiser vos performances DNS :

  • Vérifiez le nombre de pods kube-dns en cours d'exécution sur le cluster et comparez-le au nombre total de nœuds GKE. Si les ressources sont insuffisantes, envisagez d'augmenter la capacité des pods kube-dns.

  • Pour améliorer le temps moyen de résolution DNS, activez NodeLocal DNSCache.

  • La résolution DNS vers des noms externes peut surcharger le pod kube-dns. Pour réduire le nombre de requêtes, ajustez le paramètre ndots dans le fichier /etc/resolv.conf. ndots représente le nombre de points qui doivent figurer dans un nom de domaine pour résoudre une requête avant la requête absolue initiale.

    L'exemple suivant est le fichier /etc/resolv.conf d'un pod d'application :

    search default.svc.cluster.local svc.cluster.local cluster.local c.PROJECT_ID.internal google.internal
    nameserver 10.52.16.10
    options ndots:5
    

    Dans cet exemple, kube-dns recherche cinq points dans le domaine interrogé. Si le pod effectue un appel de résolution DNS pour example.com, vos journaux ressemblent à l'exemple suivant :

    "A IN example.com.default.svc.cluster.local." NXDOMAIN
    "A IN example.com.svc.cluster.local." NXDOMAIN
    "A IN example.com.cluster.local." NXDOMAIN
    "A IN example.com.google.internal." NXDOMAIN
    "A IN example.com.c.PROJECT_ID.internal." NXDOMAIN
    "A IN example.com." NOERROR
    

    Pour résoudre ce problème, vous pouvez modifier la valeur de ndots en 1 pour rechercher uniquement un seul point, ou ajouter un point (.) à la fin du domaine que vous interrogez ou utilisez. Exemple :

    dig example.com.
    

Problème : les requêtes DNS échouent par intermittence à partir de certains nœuds

Si vous remarquez que les requêtes DNS échouent par intermittence à partir de certains nœuds, vous pouvez observer les symptômes suivants :

  • Lorsque vous exécutez des commandes dig sur l'adresse IP du service kube-dns ou l'adresse IP du pod, les requêtes DNS échouent par intermittence avec des délais d'attente.
  • L'exécution de commandes dig à partir d'un pod sur le même nœud que le pod kube-dns échoue.

Pour résoudre ce problème, procédez comme suit :

  1. Effectuez un test de connectivité. Définissez le pod ou le nœud problématique comme source, et l'adresse IP du pod kube-dns comme destination. Cela vous permet de vérifier que vous avez mis en place les règles de pare-feu requises pour autoriser ce trafic.
  2. Si le test n'est pas concluant et que le trafic est bloqué par une règle de pare-feu, utilisez Cloud Logging pour lister les modifications manuelles apportées aux règles de pare-feu. Recherchez les modifications qui bloquent un type de trafic spécifique :

    1. Dans la console Google Cloud , accédez à la page Explorateur de journaux.

      Accéder à l'explorateur de journaux

    2. Dans le volet "Requête", saisissez la requête suivante :

      logName="projects/project-name/logs/cloudaudit.googleapis.com/activity"
      resource.type="gce_firewall_rule"
      
    3. Cliquez sur Exécuter la requête. Utilisez le résultat de la requête pour déterminer si des modifications ont été apportées. Si vous constatez des erreurs, corrigez-les et appliquez de nouveau la règle de pare-feu.

      Assurez-vous de ne pas modifier les règles de pare-feu automatiques.

  3. Si aucune modification n'a été apportée aux règles de pare-feu, vérifiez la version du pool de nœuds et assurez-vous qu'elle est compatible avec le plan de contrôle et les autres pools de nœuds de calcul. Si l'un des pools de nœuds du cluster a plus de deux versions mineures antérieures au plan de contrôle, cela peut engendrer des problèmes. Pour en savoir plus sur cette incompatibilité, consultez La version du nœud n'est pas compatible avec la version du plan de contrôle.

  4. Pour déterminer si les requêtes sont envoyées à la bonne adresse IP du service kube-dns, capturez le trafic réseau sur le nœud problématique et filtrez-le sur le port 53 (trafic DNS). Capturez le trafic sur les pods kube-dns eux-mêmes pour voir si les requêtes atteignent les pods prévus et si elles sont résolues avec succès.

Étapes suivantes