Risolvere i problemi di kube-dns in GKE


Questa pagina mostra come risolvere i problemi relativi a kube-dns in Google Kubernetes Engine (GKE).

Identificare l'origine dei problemi DNS in kube-dns

Errori come dial tcp: i/o timeout, no such host o Could not resolve host spesso segnalano problemi con la capacità di kube-dns di risolvere le query.

Se hai visualizzato uno di questi errori, ma non ne conosci la causa, consulta le seguenti sezioni per trovarla. Le sezioni seguenti sono disposte in modo da iniziare con i passaggi che hanno maggiori probabilità di aiutarti, quindi prova ciascuna sezione in ordine.

Verificare se i pod kube-dns sono in esecuzione

I pod kube-dns sono fondamentali per la risoluzione dei nomi all'interno del cluster. Se non sono in esecuzione, è probabile che tu abbia problemi con la risoluzione DNS.

Per verificare che i pod kube-dns siano in esecuzione senza riavvii recenti, visualizza lo stato di questi pod:

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

L'output è simile al seguente:

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

In questo output, POD_ID_1 e POD_ID_2 rappresentano identificatori univoci che vengono aggiunti automaticamente ai pod kube-dns.

Se l'output indica che uno dei pod kube-dns non ha lo stato Running, svolgi i seguenti passaggi:

  1. Utilizza i log di controllo delle attività di amministrazione per verificare se sono state apportate modifiche recenti, ad esempio upgrade delle versioni del cluster o del pool di nodi o modifiche al ConfigMap kube-dns. Per scoprire di più sui log di controllo, consulta Informazioni sui log di controllo di GKE. Se trovi modifiche, ripristinale e visualizza di nuovo lo stato dei pod.

  2. Se non trovi modifiche recenti pertinenti, controlla se si verifica un errore OOM sul nodo su cui viene eseguito il pod kube-dns. Se nei messaggi di log di Cloud Logging viene visualizzato un errore simile al seguente, questi pod stanno riscontrando un errore OOM:

    Warning: OOMKilling Memory cgroup out of memory
    

    Per risolvere questo errore, consulta Messaggio di errore: "Avviso: OOMKilling Memory cgroup out of memory".

  3. Se non trovi messaggi di errore OOM, riavvia il deployment di kube-dns:

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

    Dopo aver riavviato il deployment, controlla se i pod kube-dns sono in esecuzione.

Se questi passaggi non funzionano o se tutti i pod kube-dns hanno lo stato Running, ma continui a riscontrare problemi DNS, verifica che il file /etc/resolv.conf sia configurato correttamente.

Verificare che /etc/resolv.conf sia configurato correttamente

Esamina il file /etc/resolv.conf dei pod che presentano problemi DNS e assicurati che le voci in esso contenute siano corrette:

  1. Visualizza il file /etc/resolv.conf del pod:

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

    Sostituisci POD_NAME con il nome del pod che riscontra problemi DNS. Se si verificano problemi con più pod, ripeti i passaggi descritti in questa sezione per ogni pod.

    Se il file binario del pod non supporta il comando kubectl exec, questo comando potrebbe non riuscire. In questo caso, crea un semplice pod da utilizzare come ambiente di test. Questa procedura ti consente di eseguire un pod di test nello stesso spazio dei nomi del pod problematico.

  2. Verifica che l'indirizzo IP del server dei nomi nel file /etc/resolv.conf sia corretto:

    • I pod che utilizzano una rete host devono utilizzare i valori nel file /etc/resolv.conf del nodo. L'indirizzo IP del server dei nomi deve essere 169.254.169.254.
    • Per i pod che non utilizzano una rete host, l'indirizzo IP del servizio kube-dns deve essere uguale all'indirizzo IP del server dei nomi. Per confrontare gli indirizzi IP:

      1. Ottieni l'indirizzo IP del servizio kube-dns:

        kubectl get svc kube-dns -n kube-system
        

        L'output è simile al seguente:

        NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
        kube-dns   ClusterIP   192.0.2.10   <none>        53/UDP,53/TCP   64d
        
      2. Prendi nota del valore nella colonna IP cluster. In questo esempio, è 192.0.2.10.

      3. Confronta l'indirizzo IP del servizio kube-dns con l'indirizzo IP del file /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
        

        In questo esempio, i due valori corrispondono, quindi l'indirizzo IP del nome del server non è la causa del problema.

        Tuttavia, se gli indirizzi IP non corrispondono, significa che nel manifest del pod dell'applicazione è configurato un campo dnsConfig.

        Se il valore nel campo dnsConfig.nameservers è corretto, esamina il server DNS e assicurati che funzioni correttamente.

        Se non vuoi utilizzare il server dei nomi personalizzato, rimuovi il campo e esegui un riavvio graduale del pod:

        kubectl rollout restart deployment POD_NAME
        

        Sostituisci POD_NAME con il nome del pod.

  3. Verifica le voci search e ndots in /etc/resolv.conf. Assicurati che non ci siano errori ortografici, configurazioni obsolete e che la richiesta non riuscita indichi il servizio esistente nello spazio dei nomi corretto.

Esegui una ricerca DNS

Dopo aver verificato che /etc/resolv.conf è configurato correttamente e che il record DNS è corretto, utilizza lo strumento a riga di comando dig per eseguire ricerche DNS dal pod che segnala errori DNS:

  1. Esegui una query direttamente su un pod aprendo una shell al suo interno:

    kubectl exec -it POD_NAME -n NAMESPACE_NAME -- SHELL_NAME
    

    Sostituisci quanto segue:

    • POD_NAME: il nome del pod che segnala errori DNS.
    • NAMESPACE_NAME: lo spazio dei nomi a cui appartiene il pod.
    • SHELL_NAME: il nome della shell che vuoi aprire. Ad esempio, sh o /bin/bash.

    Questo comando potrebbe non riuscire se il pod non consente il comando kubectl exec o se non dispone del file binario dig. In questo caso, crea un pod di test con un'immagine in cui è installato dig:

    kubectl run "test-$RANDOM" ti --restart=Never --image=thockin/dnsutils - bash
    
  2. Verifica se il pod può risolvere correttamente il servizio DNS interno del cluster:

    dig kubernetes
    

    Poiché il file /etc/resolv.conf rimanda all'indirizzo IP del servizio kube-dns, quando esegui questo comando il server DNS è il servizio kube-dns.

    Dovresti visualizzare una risposta DNS positiva con l'indirizzo IP del servizio API Kubernetes (spesso qualcosa di simile a 10.96.0.1). Se vedi SERVFAIL o nessuna risposta, in genere significa che il pod kube-dns non è in grado di risolvere i nomi dei servizi interni.

  3. Verifica se il servizio kube-dns può risolvere un nome di dominio esterno:

    dig example.com
    
  4. Se hai difficoltà con un determinato pod kube-dns che risponde alle query DNS, controlla se il pod può risolvere un nome di dominio esterno:

     dig example.com @KUBE_DNS_POD_IP
    

    Sostituisci KUBE_DNS_POD_IP con l'indirizzo IP del pod kube-dns. Se non conosci il valore di questo indirizzo IP, esegui il seguente comando:

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

    L'indirizzo IP si trova nella colonna IP.

    Se la risoluzione del comando è andata a buon fine, viene visualizzato status: NOERROR e i dettagli del record A, come mostrato nell'esempio seguente:

     ; <<>> 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. Esci dalla shell:

    exit
    

Se uno di questi comandi non va a buon fine, esegui un riavvio graduale del deployment di kube-dns:

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

Dopo aver completato il riavvio, riprova a eseguire i comandi dig e controlla se ora vanno a buon fine. Se i test non vanno a buon fine, procedi con l'acquisizione di un pacchetto.

Acquisisci un'acquisizione di pacchetti

Esegui un'acquisizione di pacchetti per verificare se le query DNS vengono ricevute e annotate in modo appropriato dai pod kube-dns:

  1. Utilizzando SSH, connettiti al nodo che esegue il pod kube-dns. Ad esempio:

    1. Nella console Google Cloud, vai alla pagina Istanze VM.

      Vai a Istanze VM

    2. Individua il nodo a cui vuoi connetterti. Se non conosci il nome del nodo nel pod kube-dns, esegui il seguente comando:

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

      Il nome del nodo è elencato nella colonna Nodo.

    3. Nella colonna Connetti, fai clic su SSH.

  2. Nel terminale, avvia toolbox, uno strumento di debug preinstallato:

    toolbox
    
  3. Al prompt di root, installa il pacchetto tcpdump:

    apt update -y && apt install -y tcpdump
    
  4. Utilizzando tcpdump, acquisisci un'acquisizione di pacchetti del traffico DNS:

    tcpdump -i eth0 port 53" -w FILE_LOCATION
    

    Sostituisci FILE_LOCATION con il percorso in cui vuoi salvare la cattura.

  5. Esamina l'acquisizione dei pacchetti. Controlla se sono presenti pacchetti con indirizzi IP di destinazione che corrispondono all'indirizzo IP del servizio kube-dns. In questo modo, le richieste DNS raggiungono la destinazione corretta per la risoluzione. L'impossibilità di vedere il traffico DNS che arriva ai pod corretti potrebbe indicare la presenza di un criterio di rete che blocca le richieste.

Verificare la presenza di un criterio di rete

A volte i criteri di rete restrittivi possono interrompere il traffico DNS. Per verificare se un criterio di rete esiste nello spazio dei nomi kube-system, esegui il seguente comando:

kubectl get networkpolicy -n kube-system

Se trovi un criterio di rete, esaminalo e assicurati che consenta la comunicazione DNS necessaria. Ad esempio, se hai un criterio di rete che blocca tutto il traffico in uscita, il criterio bloccherà anche le richieste DNS.

Se l'output è No resources found in kube-system namespace, significa che non hai parametri di rete e puoi escludere questa causa del problema. L'analisi dei log può aiutarti a trovare altri punti di errore.

Attivare il logging temporaneo delle query DNS

Per aiutarti a identificare problemi come risposte DNS errate, abilita temporaneamente il logging di debug delle query DNS.

Si tratta di una procedura che richiede molte risorse, pertanto ti consigliamo di disattivare questo logging dopo aver raccolto un campione di log adeguato.

Esaminare il pod kube-dns

Scopri come i pod kube-dns ricevono e risolvono le query DNS con Cloud Logging.

Per visualizzare le voci di log relative al pod kube-dns, completa i seguenti passaggi:

  1. Nella console Google Cloud, vai alla pagina Esplora log.

    Vai a Esplora log

  2. Nel riquadro delle query, inserisci il seguente filtro per visualizzare gli eventi relativi al contenitore 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"
    

    Sostituisci quanto segue:

    • CLUSTER_NAME: il nome del cluster a cui appartiene il pod kube-dns.
    • CLUSTER_LOCATION: la posizione del cluster.
  3. Fai clic su Esegui query.

  4. Rivedi l'output. L'esempio di output seguente mostra un possibile errore che potresti visualizzare:

    {
       "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."
    },
    

    In questo esempio, kube-dns non è riuscito a risolvere example.com in un tempo ragionevole. Questo tipo di errore può essere causato da più problemi. Ad esempio, il server upstream potrebbe essere configurato in modo errato nel ConfigMap kube-dns oppure il traffico di rete potrebbe essere elevato.

Se Cloud Logging non è abilitato, visualizza i log di 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

Esaminare le modifiche recenti nel ConfigMap kube-dns

Se improvvisamente riscontri errori di risoluzione DNS nel cluster, una possibile causa è una modifica errata della configurazione apportata al ConfigMap kube-dns. In particolare, le modifiche alla configurazione dei domini stub e delle definizioni dei server upstream possono causare problemi.

Per verificare la presenza di aggiornamenti alle impostazioni del dominio stub, segui questi passaggi:

  1. Nella console Google Cloud, vai alla pagina Esplora log.

    Vai a Esplora log

  2. Nel riquadro delle query, inserisci la seguente query:

    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. Fai clic su Esegui query.

  4. Rivedi l'output. Se sono stati eseguiti aggiornamenti, l'output è simile al seguente:

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

    Se vedi un aggiornamento, espandi il risultato per scoprire di più sulle modifiche. Verifica che eventuali domini stub e i relativi server DNS upstream siano definiti correttamente. Le voci errate possono comportare errori di risoluzione per i domini in questione.

Per verificare la presenza di modifiche al server upstream:

  1. Nella console Google Cloud, vai alla pagina Esplora log.

    Vai a Esplora log

  2. Nel riquadro della query, inserisci la seguente query:

    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. Fai clic su Esegui query.

  4. Rivedi l'output. Se sono state apportate modifiche, l'output è simile al seguente:

    Updated upstreamNameservers to [8.8.8.8]
    

    Espandi il risultato per scoprire di più sulle modifiche. Verifica che l'elenco di server DNS upstream sia accurato e che questi server siano raggiungibili dal tuo cluster. Se questi server non sono disponibili o sono configurati in modo errato, la risoluzione DNS generale potrebbe non riuscire.

Se hai controllato la presenza di modifiche ai domini stub e ai server upstream, ma non hai trovato risultati, controlla tutte le modifiche con il seguente filtro:

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

Esamina le modifiche elencate per verificare se hanno causato l'errore.

Contattare l'assistenza clienti Google Cloud

Se hai letto le sezioni precedenti, ma non riesci ancora a diagnosticare la causa del problema, contatta l'assistenza clienti Google Cloud.

Risolvere i problemi comuni

Se hai riscontrato un errore o un problema specifico, segui i consigli riportati nelle seguenti sezioni.

Problema: timeout DNS intermittenti

Se noti timeout intermittenti della risoluzione DNS che si verificano quando c'è un aumento del traffico DNS o quando iniziano gli orari di apertura, prova le seguenti soluzioni per ottimizzare il rendimento del DNS:

  • Controlla il numero di pod kube-dns in esecuzione nel cluster e confrontalo con il numero totale di nodi GKE. Se le risorse non sono sufficienti, valuta la possibilità di eseguire lo scaling up dei pod kube-dns.

  • Per migliorare il tempo medio di ricerca DNS, abilita NodeLocal DNS Cache.

  • La risoluzione DNS in nomi esterni può sovraccaricare il pod kube-dns. Per ridurre il numero di query, modifica l'impostazione ndots nel file /etc/resolv.conf. ndots indica il numero di punti che devono apparire in un nome di dominio per risolvere una query prima della query assoluta iniziale.

    L'esempio seguente è il file /etc/resolv.conf di un pod di applicazioni:

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

    In questo esempio, kube-dns cerca cinque punti nel dominio sottoposto a query. Se il pod effettua una chiamata di risoluzione DNS per example.com, i log saranno simili al seguente esempio:

    "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
    

    Per risolvere il problema, modifica il valore di ndots in 1 per cercare solo un singolo punto o aggiungi un punto (.) alla fine del dominio su cui esegui query o che utilizzi. Ad esempio:

    dig example.com.
    

Problema: le query DNS non riescono a essere eseguite in modo intermittente da alcuni nodi

Se noti che le query DNS non vanno a buon fine in modo intermittente da alcuni nodi, potresti riscontrare i seguenti sintomi:

  • Quando esegui comandi dig all'indirizzo IP del servizio kube-dns o all'indirizzo IP del pod, le query DNS non vanno a buon fine in modo intermittente con timeout.
  • L'esecuzione di comandi dig da un pod sullo stesso nodo del pod kube-dns non va a buon fine.

Per risolvere il problema, svolgi i seguenti passaggi:

  1. Esegui un test di connettività. Imposta il pod o il nodo problematico come origine e la destinazione come indirizzo IP del pod kube-dns. In questo modo puoi verificare se sono presenti le regole firewall necessarie per consentire questo traffico.
  2. Se il test non va a buon fine e il traffico viene bloccato da una regola del firewall, utilizza Cloud Logging per elencare eventuali modifiche manuali apportate alle regole del firewall. Cerca le modifiche che bloccano un tipo specifico di traffico:

    1. Nella console Google Cloud, vai alla pagina Esplora log.

      Vai a Esplora log

    2. Nel riquadro della query, inserisci la seguente query:

      logName="projects/project-name/logs/cloudaudit.googleapis.com/activity"
      resource.type="gce_firewall_rule"
      
    3. Fai clic su Esegui query. Utilizza l'output della query per determinare se sono state apportate modifiche. Se rilevi errori, correggili e applica di nuovo la regola del firewall.

      Assicurati di non apportare modifiche alle regole firewall automatizzate.

  3. Se non sono state apportate modifiche alle regole del firewall, controlla la versione del pool di nodi e assicurati che sia compatibile con il control plane e con gli altri pool di nodi funzionanti. Se uno dei pool di nodi del cluster è precedente di più di due versioni secondarie rispetto al piano di controllo, potrebbero verificarsi problemi. Per ulteriori informazioni su questa incompatibilità, consulta Versione del nodo non compatibile con la versione del control plane.

  4. Per determinare se le richieste vengono inviate all'IP del servizio kube-dns corretto, acquisisci il traffico di rete sul nodo problematico e filtra per la porta 53 (traffico DNS). Acquisisci il traffico sui pod kube-dns stessi per vedere se le richieste raggiungono i pod previsti e se vengono risolte correttamente.

Passaggi successivi