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


Cette page explique comment résoudre les problèmes liés à kube-dns dans Google Kubernetes Engine (GKE).

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

Les erreurs telles que dial tcp: i/o timeout, no such host ou Could not resolve host signalent souvent des problèmes liés à la capacité de kube-dns à résoudre les requêtes.

Si l'un de ces messages d'erreur s'est affiché, mais que vous ne connaissez pas la cause, consultez les sections suivantes pour l'identifier. Les sections suivantes sont organisées de manière à commencer par les étapes les plus susceptibles de vous aider. Essayez donc chaque section dans l'ordre.

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 cette sortie, 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 ci-dessous :

  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 la journalisation d'audit de 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 journaux 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 en a pas, 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 savoir comment définir des limites, consultez Gestion des ressources pour les pods et les conteneurs dans la documentation de Kubernetes. Pour en savoir plus sur les événements OOM, consultez Résoudre les problèmes liés aux événements OOM.

  3. Si aucun message d'erreur OOM ne s'affiche, 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érifier 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 DNS. Si plusieurs pods rencontrent des problèmes, répétez les étapes de cette section pour chacun d'eux.

    Si le binaire Pod n'accepte pas la commande kubectl exec, cette commande peut échouer. Dans ce cas, 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 à celle du serveur de noms. Pour comparer les adresses IP, procédez comme suit :

      1. Obtenez 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 de cluster". Dans cet exemple, il s'agit de 192.0.2.10.

      3. Comparez l'adresse IP du service kube-dns avec 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 en échec pointe vers un service existant dans le bon espace de noms.

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 en ligne de commande dig pour effectuer des recherches 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 n'est pas en mesure de résoudre les noms de service 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 le shell :

    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, passez à la 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. Localisez 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. À 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 atteignent la bonne destination pour la résolution. Si le trafic DNS n'arrive pas sur les bons pods, 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 disposez d'une règle de réseau qui bloque tout le trafic de sortie, elle bloquera également les requêtes DNS.

Si le résultat 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 les réponses DNS incorrectes, activez temporairement la journalisation du 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é, consultez 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 à kube-dns ConfigMap

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 à kube-dns ConfigMap. En particulier, les modifications 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 de 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 s'affiche, 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 sont indisponibles ou mal configurés, la résolution DNS générale peut échouer.

Si vous avez vérifié les modifications apportées aux domaines de 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 l'assistance 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 ci-dessous.

Problème : Expiration de délais DNS intermittente

Si vous constatez des délais d'expiration intermittents de la résolution DNS qui se produisent en cas d'augmentation du trafic DNS ou au début des heures d'ouverture, essayez les solutions suivantes pour optimiser les performances de votre 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. S'il n'y a pas assez de ressources, envisagez de faire évoluer les pods kube-dns.

  • Pour améliorer la durée moyenne de résolution DNS, activez NodeLocal DNSCache.

  • La résolution DNS pour les 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, modifiez la valeur de ndots en 1 afin de rechercher uniquement un seul point, ou ajoutez 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 constatez 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 sur 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 si 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 réappliquez la règle de pare-feu.

      Veillez à 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 fonctionnels. 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 être à l'origine de 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 à l'adresse IP du service kube-dns appropriée, 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