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 indicano problemi con la capacità di kube-dns di risolvere le query.

Se hai riscontrato uno di questi errori, ma non ne conosci la causa, utilizza le sezioni seguenti per aiutarti a individuarla. Le sezioni seguenti sono organizzate in modo da iniziare con i passaggi che hanno maggiori probabilità di aiutarti, quindi prova ogni sezione in ordine.

Verifica che i pod kube-dns siano in esecuzione

I pod kube-dns sono fondamentali per la risoluzione dei nomi all'interno del cluster. Se non sono in esecuzione, è probabile che si verifichino 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 mostra che nessuno dei tuoi pod kube-dns ha lo stato Running, segui questi passaggi:

  1. Utilizza i log di controllo dell'attività di amministrazione per verificare se sono state apportate modifiche recenti, ad esempio upgrade della versione del cluster o del pool di nodi oppure modifiche a kube-dns ConfigMap. Per saperne di più sui log di controllo, vedi 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, verifica se si verifica un errore di esaurimento della memoria sul nodo su cui viene eseguito il pod kube-dns. Se nei messaggi di log di Cloud Logging visualizzi un errore simile al seguente, significa che questi pod stanno riscontrando un errore OOM:

    Warning: OOMKilling Memory cgroup out of memory
    

    Questo messaggio indica che Kubernetes ha terminato un processo a causa dell'eccessivo consumo di risorse. Kubernetes pianifica i pod in base alle richieste di risorse, ma consente ai pod di consumare fino ai limiti delle risorse. Se i limiti sono superiori alle richieste o non sono presenti limiti, l'utilizzo delle risorse del pod può superare le risorse del sistema.

    Per risolvere questo errore, puoi eliminare i workload problematici o impostare limiti di memoria o CPU. Per scoprire di più sull'impostazione dei limiti, consulta la sezione Gestione delle risorse per pod e container nella documentazione di Kubernetes. Per saperne di più sugli eventi OOM, vedi Risolvere i problemi relativi agli eventi OOM.

  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 tutti i tuoi pod kube-dns hanno lo stato Running, ma riscontri ancora problemi DNS, verifica che il file /etc/resolv.conf sia configurato correttamente.

Verifica che /etc/resolv.conf sia configurato correttamente

Esamina il file /etc/resolv.conf dei pod che presentano problemi DNS e assicurati che le voci che contiene 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 presenta problemi di DNS. Se ci sono più pod che presentano problemi, ripeti i passaggi di questa sezione per ogni pod.

    Se il binario del pod non supporta il comando kubectl exec, questo comando potrebbe non riuscire. In questo caso, crea un pod semplice da utilizzare come ambiente di test. Questa procedura 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 corrispondere all'indirizzo IP del server dei nomi. Per confrontare gli indirizzi IP, completa i seguenti passaggi:

      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 un indirizzo IP del nameserver errato non è la causa del problema.

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

        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 ed esegui un riavvio graduale del pod:

        kubectl rollout restart deployment POD_NAME
        

        Sostituisci POD_NAME con il nome del tuo 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 faccia riferimento a un servizio esistente nello spazio dei nomi corretto.

Esegui una ricerca DNS

Dopo aver verificato che /etc/resolv.conf sia configurato correttamente e che il record DNS sia corretto, utilizza lostrumento a riga di comandoo 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 il pod non dispone del 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. Controlla se il pod è in grado di risolvere correttamente il servizio DNS interno del cluster:

    dig kubernetes
    

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

    Dovresti visualizzare una risposta DNS riuscita con l'indirizzo IP del servizio API Kubernetes (spesso qualcosa come 10.96.0.1). Se visualizzi SERVFAIL o nessuna risposta, di solito ciò indica 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 riscontri difficoltà con un determinato pod kube-dns che risponde alle query DNS, verifica 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 ha esito positivo, vengono visualizzati status: NOERROR e i dettagli del record A, come mostrato nel seguente esempio:

     ; <<>> 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 in sequenza del deployment kube-dns:

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

Dopo aver completato il riavvio, riprova i comandi dig e verifica se ora hanno esito positivo. Se i test continuano a non andare a buon fine, procedi con l'acquisizione di un pacchetto.

Acquisire un'acquisizione di pacchetti

Acquisisci un pacchetto per verificare se le query DNS vengono ricevute e risposte 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 sul 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 root, installa il pacchetto tcpdump:

    apt update -y && apt install -y tcpdump
    
  4. Utilizzando tcpdump, acquisisci un pacchetto del traffico DNS:

    tcpdump -i eth0 port 53" -w FILE_LOCATION
    

    Sostituisci FILE_LOCATION con un percorso in cui vuoi salvare l'acquisizione.

  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. Se non vedi il traffico DNS arrivare sui pod corretti, potrebbe essere presente un criterio di rete che blocca le richieste.

Verificare la presenza di un criterio di rete

A volte, le norme di rete restrittive possono interrompere il traffico DNS. Per verificare se esiste una policy di rete nello spazio dei nomi kube-system, esegui questo comando:

kubectl get networkpolicy -n kube-system

Se trovi una policy di rete, esaminala 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 bloccherebbe anche le richieste DNS.

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

Abilitare il logging temporaneo delle query DNS

Per aiutarti a identificare problemi come risposte DNS errate, attiva temporaneamente la registrazione di debug delle query DNS. Per abilitare le query, crea un pod basato su un pod kube-dns esistente. Eventuali modifiche al deployment di kube-dns vengono annullate automaticamente.

L'attivazione della registrazione temporanea delle query DNS è una procedura che richiede molte risorse, pertanto ti consigliamo di eliminare il pod che crei non appena raccogli un campione di log adeguato.

Per abilitare la registrazione temporanea delle query DNS, completa i seguenti passaggi:

  1. Recupera un pod kube-dns e memorizzalo nella variabile denominata POD:

    POD=$(kubectl -n kube-system get pods --selector=k8s-app=kube-dns -o jsonpath="{.items[0].metadata.name}")
    
  2. Crea un pod denominato kube-dns-debug. Questo pod è una copia del pod archiviato nella variabile POD, ma con la registrazione dnsmasq abilitata. Questo comando non modifica il pod kube-dns originale:

    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. Esamina i log:

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

    Puoi anche visualizzare le query in Cloud Logging.

  4. Dopo aver visualizzato i log delle query DNS, elimina il pod kube-dns-debug:

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

Esamina il pod kube-dns

Esamina in che modo 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 della query, inserisci il seguente filtro per visualizzare gli eventi correlati al container 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'output di esempio 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 diversi problemi. Ad esempio, il server upstream potrebbe essere configurato in modo errato in kube-dns ConfigMap oppure potrebbe esserci un traffico di rete 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

Esamina le modifiche recenti apportate a kube-dns ConfigMap

Se improvvisamente si verificano errori di risoluzione DNS nel cluster, una causa è una modifica di configurazione errata apportata a kube-dns ConfigMap. 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, completa i seguenti passaggi:

  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 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 tutti i domini stub e i relativi server DNS upstream siano definiti correttamente. Le voci errate qui possono causare errori di risoluzione per questi domini.

Per verificare la presenza di modifiche al server upstream, completa i seguenti passaggi:

  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 dei 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 verificato 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 seguito 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 sezioni seguenti.

Problema: timeout DNS intermittenti

Se noti timeout intermittenti della risoluzione DNS che si verificano quando si verifica un aumento del traffico DNS o quando iniziano le ore lavorative, prova le seguenti soluzioni per ottimizzare il rendimento del DNS:

  • Controlla il numero di pod kube-dns in esecuzione sul cluster e confrontalo con il numero totale di nodi GKE. Se le risorse non sono sufficienti, valuta la possibilità di scalare orizzontalmente i pod kube-dns.

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

  • La risoluzione DNS per i nomi esterni può sovraccaricare il pod kube-dns. Per ridurre il numero di query, modifica l'impostazione ndots nel file /etc/resolv.conf. ndots rappresenta il numero di punti che devono essere presenti 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 dell'applicazione:

    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 interrogato. Se il pod effettua una chiamata di risoluzione DNS per example.com, i log sono 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 che interroghi o utilizzi. Ad esempio:

    dig example.com.
    

Problema: le query DNS non riescono a intermittenza da alcuni nodi

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

  • Quando esegui i comandi dig sull'indirizzo IP del servizio kube-dns o sull'indirizzo IP del pod, le query DNS non riescono 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, completa 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 richieste per consentire questo traffico.
  2. Se il test non va a buon fine e il traffico viene bloccato da una regola firewall, utilizza Cloud Logging per elencare le modifiche manuali apportate alle regole firewall. Cerca 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 riapplica la regola firewall.

      Assicurati di non apportare modifiche alle regole firewall automatizzate.

  3. Se non sono state apportate modifiche alle regole firewall, controlla la versione pool di nodi e assicurati che sia compatibile con il control plane e con gli altri node pool funzionanti. Se uno dei pool di nodi del cluster è precedente di più di due versioni secondarie rispetto al control plane, questo potrebbe causare problemi. Per maggiori 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