Risolvere i problemi di connettività nel cluster


Questa pagina mostra come risolvere i problemi di connettività nel cluster.

Problemi di connettività relativi all'acquisizione di pacchetti di rete in GKE

Questa sezione descrive come risolvere i problemi di connettività relativi alla cattura di pacchetti di rete, inclusi sintomi come timeout della connessione, errori di rifiuto della connessione o comportamento inaspettato dell'applicazione. Questi problemi di connettività possono verificarsi a livello di nodo o di pod.

I problemi di connettività nella rete del cluster rientrano spesso nelle seguenti categorie:

  • Pod non raggiungibili: un pod potrebbe non essere accessibile dall'interno o dall'esterno del cluster a causa di configurazioni di rete errate.
  • Interruzione del servizio: un servizio potrebbe subire interruzioni o ritardi.
  • Problemi di comunicazione tra pod: i pod potrebbero non essere in grado di comunicare tra loro in modo efficace.

I problemi di connettività nel cluster GKE possono avere varie cause, tra cui:

  • Configurazioni errate della rete: criteri di rete, regole firewall o tabelle di routing errati.
  • Bug dell'applicazione: errori nel codice dell'applicazione che influiscono sulle interazioni con la rete.
  • Problemi di infrastruttura: congestione della rete, guasti hardware o limitazioni delle risorse.

La sezione seguente mostra come risolvere il problema sui nodi o sui pod problematici.

  1. Identifica il nodo su cui è in esecuzione il pod problematico utilizzando il seguente comando:

    kubectl get pods POD_NAME -o=wide -n NAMESPACE
    

    Sostituisci quanto segue:

    • POD_NAME con il nome del pod.
    • NAMESPACE con lo spazio dei nomi Kubernetes.
  2. Connettiti al nodo:

    gcloud compute ssh NODE_NAME \
        --zone=ZONE
    

    Sostituisci quanto segue:

    • NODE_NAME: il nome del tuo nodo.
    • ZONE: il nome della zona in cui viene eseguito il nodo.
  3. Per eseguire il debug di un pod specifico, identifica l'interfaccia veth associata al pod:

    ip route | grep POD_IP
    

    Sostituisci POD_IP con l'indirizzo IP del pod.

  4. Esegui i comandi della cassetta degli attrezzi.

toolbox comandi

toolbox è un'utilità che fornisce un ambiente containerizzato all'interno dei nodi GKE per il debug e la risoluzione dei problemi. Questa sezione descrive come installare l'utilità toolbox e utilizzarla per risolvere i problemi del nodo.

  1. Mentre sei connesso al nodo, avvia lo strumento toolbox:

    toolbox
    

    Verranno scaricati i file che facilitano l'utility toolbox.

  2. Nel prompt toolbox root, installa tcpdump:

    • Per i cluster con indirizzi IP esterni o Cloud NAT:

      apt update -y && apt install -y tcpdump
      
    • Per i cluster privati senza Cloud NAT:

      Se hai un cluster privato senza Cloud NAT, non puoi installare tcpdump utilizzando apt. Scarica invece i file di release libpcap e tcpdump dal repository ufficiale e copiali nella VM utilizzando gcloud compute scp o gsutil. Poi installa le librerie manualmente seguendo questi passaggi:

      cp /media/root/home/USER_NAME/tcpdump-VERSION.tar.gz  /usr/sbin/
      cp /media/root/home/USER_NAME/libpcap-VERSION.tar.gz  /usr/sbin/
      cd /usr/sbin/
      tar -xvzf tcpdump-VERSION.tar.gz
      tar -xvzf libpcap-VERSION.tar.gz
      cd libpcap-VERSION
      ./configure ; make ; make install
      cd ../tcpdump-VERSION
      ./configure ; make ; make install
      tcpdump --version
      

      Sostituisci quanto segue:

      • USER_NAME: il tuo nome utente sul sistema in cui si trovano i file.
      • VERSION: il numero di versione specifico dei pacchetti tcpdump e libpcap.
  3. Avvia l'acquisizione dei pacchetti:

    tcpdump -i eth0 -s 100 "port PORT" \
    -w /media/root/mnt/stateful_partition/CAPTURE_FILE_NAME
    

    Sostituisci quanto segue:

    • PORT: il nome del numero di porta.
    • CAPTURE_FILE_NAME: il nome del file di acquisizione.
  4. Interrompi l'acquisizione dei pacchetti e interrompi tcpdump.

  5. Esci dalla cassetta degli attrezzi digitando exit.

  6. Elenca il file di acquisizione dei pacchetti e controllane le dimensioni:

    ls -ltr /mnt/stateful_partition/CAPTURE_FILE_NAME
    
  7. Copia l'acquisizione dei pacchetti dal nodo alla directory di lavoro corrente sul computer:

    gcloud compute scp NODE_NAME:/mnt/stateful_partition/CAPTURE_FILE_NAME \
        --zone=ZONE
    

    Sostituisci quanto segue:

    • NODE_NAME: il nome del tuo nodo.
    • CAPTURE_FILE_NAME: il nome del file di acquisizione.
    • ZONE: il nome della tua zona.

Comandi alternativi

Puoi anche utilizzare i seguenti metodi per risolvere i problemi di connettività nei pod problematici:

  • Carico di lavoro di debug temporaneo collegato al container del pod.

  • Esegui una shell direttamente sul pod di destinazione utilizzando kubectl exec, quindi installa e avvia il comando tcpdump.

Problemi di connettività di rete del pod

Come accennato nella discussione sulla Panoramica della rete, è importante capire in che modo i pod sono collegati dai loro spazi dei nomi di rete allo spazio dei nomi principale sul nodo per risolvere i problemi in modo efficace. Per la discussione che segue, se non diversamente indicato, si presume che il cluster utilizzi il CNI nativo di GKE anziché quello di Calico. Ciò significa che non è stato applicato alcun criterio di rete.

I pod su alcuni nodi non sono disponibili

Se i pod su alcuni nodi non hanno connettività di rete, assicurati che il bridge Linux sia attivo:

ip address show cbr0

Se il bridge Linux non è attivo, sollevalo:

sudo ip link set cbr0 up

Assicurati che il nodo apprenda gli indirizzi MAC dei pod collegati a cbr0:

arp -an

I pod su alcuni nodi hanno una connettività minima

Se i pod su alcuni nodi hanno una connettività minima, devi prima verificare se sono presenti pacchetti persi eseguendo tcpdump nel contenitore della cassetta degli attrezzi:

sudo toolbox bash

Se non l'hai ancora fatto, installa tcpdump nella cassetta degli attrezzi:

apt install -y tcpdump

Esegui tcpdump contro cbr0:

tcpdump -ni cbr0 host HOSTNAME and port PORT_NUMBER and [TCP|UDP|ICMP]

Se sembra che i pacchetti di grandi dimensioni vengano eliminati a valle del bridge (ad esempio, l'handshake TCP viene completato, ma non vengono ricevuti messaggi di aggiornamento SSL), assicurati che l'MTU per ogni interfaccia del pod Linux sia impostato correttamente sull'MTU della rete VPC del cluster.

ip address show cbr0

Quando vengono utilizzati overlay (ad esempio Weave o Flannel), questo valore MTU deve essere ulteriormente ridotto per tenere conto del sovraccarico di incapsulamento sull'overlay.

MTU GKE

L'MTU selezionato per un'interfaccia del pod dipende dall'interfaccia di rete del contenitore (CNI) utilizzata dai nodi del cluster e dall'impostazione MTU della VPC sottostante. Per ulteriori informazioni, consulta Pod.

Il valore MTU dell'interfaccia del pod è 1460 o ereditato dall'interfaccia principale del nodo.

CNI MTU GKE Standard
kubenet 1460 Predefinito
kubenet
(GKE versione 1.26.1 e successive)
Ereditato Predefinito
Calico 1460

Abilitato utilizzando --enable-network-policy.

Per maggiori dettagli, vedi Controllare la comunicazione tra pod e servizi utilizzando i criteri di rete.

netd Ereditato Attivata utilizzando una delle seguenti opzioni:
GKE Dataplane V2 Ereditato

Abilitato utilizzando --enable-dataplane-v2.

Per maggiori dettagli, consulta Utilizzare GKE Dataplane V2.

Connessioni non riuscite intermittenti

Le connessioni da e verso i pod vengono inoltrate da iptables. I flussi vengono monitorati come voci nella tabella conntrack e, se sono presenti molti carichi di lavoro per nodo, l'esaurimento della tabella conntrack può manifestarsi come un errore. Questi possono essere registrati nella console seriale del nodo, ad esempio:

nf_conntrack: table full, dropping packet

Se riesci a determinare che i problemi intermittenti sono causati dall'esaurimento di conntrack, puoi aumentare le dimensioni del cluster (riducendo così il numero di carichi di lavoro e flussi per nodo) o aumentare nf_conntrack_max:

new_ct_max=$(awk '$1 == "MemTotal:" { printf "%d\n", $2/32; exit; }' /proc/meminfo)
sysctl -w net.netfilter.nf_conntrack_max="${new_ct_max:?}" \
  && echo "net.netfilter.nf_conntrack_max=${new_ct_max:?}" >> /etc/sysctl.conf

Puoi anche utilizzare NodeLocal DNSCache per ridurre le voci di monitoraggio delle connessioni.

"bind: Address already in use " segnalato per un contenitore

Un contenitore in un pod non riesce ad avviarsi perché, in base ai log del contenitore, la porta a cui l'applicazione sta tentando di eseguire il binding è già prenotata. Il container è in loop di arresti anomali. Ad esempio, in Cloud Logging:

resource.type="container"
textPayload:"bind: Address already in use"
resource.labels.container_name="redis"

2018-10-16 07:06:47.000 CEST 16 Oct 05:06:47.533 # Creating Server TCP listening socket *:60250: bind: Address already in use
2018-10-16 07:07:35.000 CEST 16 Oct 05:07:35.753 # Creating Server TCP listening socket *:60250: bind: Address already in use

Quando Docker si arresta in modo anomalo, a volte un container in esecuzione viene ignorato e rimane inattivo. Il processo è ancora in esecuzione nello spazio dei nomi di rete allocato per il pod ed è in ascolto sulla relativa porta. Poiché Docker e kubelet non sono a conoscenza del contenitore obsoleto, tentano di avviare un nuovo contenitore con un nuovo processo, che non è in grado di eseguire il binding sulla porta perché viene aggiunto allo spazio dei nomi di rete già associato al pod.

Per diagnosticare il problema:

  1. Devi avere l'UUID del pod nel campo .metadata.uuid:

    kubectl get pod -o custom-columns="name:.metadata.name,UUID:.metadata.uid" ubuntu-6948dd5657-4gsgg
    
    name                      UUID
    ubuntu-6948dd5657-4gsgg   db9ed086-edba-11e8-bdd6-42010a800164
    
  2. Ottieni l'output dei seguenti comandi dal nodo:

    docker ps -a
    ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]
    
  3. Controlla i processi in esecuzione da questo pod. Poiché l'UUID dei namespace cgroup contiene l'UUID del pod, puoi cercare l'UUID del pod nell'output di ps. Cerca anche la riga precedente, in modo da avere anche i processi docker-containerd-shim con l'ID contenitore nell'argomento. Taglia il resto della colonna cgroup per ottenere un output più semplice:

    # ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep -B 1 db9ed086-edba-11e8-bdd6-42010a800164 | sed s/'blkio:.*'/''/
    1283089     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim 276e173b0846e24b704d4 12:
    1283107 1283089 Ss   sys_pause            4026532393         pause           /pause                                     12:
    1283150     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim ab4c7762f5abf40951770 12:
    1283169 1283150 Ss   do_wait              4026532393         sh              /bin/sh -c echo hello && sleep 6000000     12:
    1283185 1283169 S    hrtimer_nanosleep    4026532393           sleep           sleep 6000000                            12:
    1283244     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim 44e76e50e5ef4156fd5d3 12:
    1283263 1283244 Ss   sigsuspend           4026532393         nginx           nginx: master process nginx -g daemon off; 12:
    1283282 1283263 S    ep_poll              4026532393           nginx           nginx: worker process
    
  4. In questo elenco puoi vedere gli ID contenitore, che dovrebbero essere visibili anche in docker ps.

    In questo caso:

    • docker-containerd-shim 276e173b0846e24b704d4 per mettere in pausa
    • docker-containerd-shim ab4c7762f5abf40951770 per sh con sospensione (sleep-ctr)
    • docker-containerd-shim 44e76e50e5ef4156fd5d3 per nginx (echoserver-ctr)
  5. Controllali nell'output di docker ps:

    # docker ps --no-trunc | egrep '276e173b0846e24b704d4|ab4c7762f5abf40951770|44e76e50e5ef4156fd5d3'
    44e76e50e5ef4156fd5d383744fa6a5f14460582d0b16855177cbed89a3cbd1f   gcr.io/google_containers/echoserver@sha256:3e7b182372b398d97b747bbe6cb7595e5ffaaae9a62506c725656966d36643cc                   "nginx -g 'daemon off;'"                                                                                                                                                                                                                                                                                                                                                                     14 hours ago        Up 14 hours                             k8s_echoserver-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0
    ab4c7762f5abf40951770d3e247fa2559a2d1f8c8834e5412bdcec7df37f8475   ubuntu@sha256:acd85db6e4b18aafa7fcde5480872909bd8e6d5fbd4e5e790ecc09acc06a8b78                                                "/bin/sh -c 'echo hello && sleep 6000000'"                                                                                                                                                                                                                                                                                                                                                   14 hours ago        Up 14 hours                             k8s_sleep-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0
    276e173b0846e24b704d41cf4fbb950bfa5d0f59c304827349f4cf5091be3327   registry.k8s.io/pause-amd64:3.1
    

    In condizioni normali, tutti gli ID contenitore di ps vengono visualizzati in docker ps. Se non ne vedi uno, si tratta di un contenitore obsoleto e probabilmente vedrai un processo secondario di docker-containerd-shim process in ascolto sulla porta TCP che viene segnalato come già in uso.

    Per verificarlo, esegui netstat nello spazio dei nomi di rete del contenitore. Recupera il pid di qualsiasi processo del contenitore (quindi NON docker-containerd-shim) per il pod.

    Nell'esempio precedente:

    • 1283107 - pausa
    • 1283169 - sh
    • 1283185 - sonno
    • 1283263 - nginx master
    • 1283282 - worker nginx
    # nsenter -t 1283107 --net netstat -anp
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
    Active UNIX domain sockets (servers and established)
    Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
    unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
    unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
    
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # nsenter -t 1283169 --net netstat -anp
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
    Active UNIX domain sockets (servers and established)
    Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
    unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
    unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
    

    Puoi anche eseguire netstat utilizzando ip netns, ma devi collegare manualmente lo spazio dei nomi di rete del processo, poiché Docker non esegue il collegamento:

    # ln -s /proc/1283169/ns/net /var/run/netns/1283169
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns list
    1283169 (id: 2)
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns exec 1283169 netstat -anp
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
    Active UNIX domain sockets (servers and established)
    Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
    unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
    unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # rm /var/run/netns/1283169
    

Mitigazione:

La mitigazione a breve termine consiste nell'identificare i processi inattivi utilizzando il metodo descritto sopra e nell'interromperli utilizzando il comando kill [PID].

La mitigazione a lungo termine prevede l'identificazione del motivo dell'arresto anomalo di Docker e la relativa correzione. Le possibili cause includono:

  • I processi zombie si accumulano, quindi si esauriscono gli spazi dei nomi PID
  • Bug in Docker
  • Pressione sulle risorse / OOM

Passaggi successivi