Verbindungsprobleme im Cluster beheben


Auf dieser Seite wird beschrieben, wie Sie Verbindungsprobleme in Ihrem Cluster beheben.

Verbindungsprobleme beim Erfassen von Netzwerkpaketen in GKE

In diesem Abschnitt wird beschrieben, wie Sie Verbindungsprobleme im Zusammenhang mit der Erfassung von Netzwerkpaketen beheben, z. B. Symptome wie Zeitüberschreitungen bei der Verbindung, Fehler aufgrund abgelehnter Verbindungen oder unerwartetes Anwendungsverhalten. Diese Verbindungsprobleme können auf Knoten- oder Podebene auftreten.

Verbindungsprobleme in Ihrem Clusternetzwerk fallen häufig in eine der folgenden Kategorien:

  • Pods nicht erreichbar: Auf einen Pod kann aufgrund von Netzwerkfehlern möglicherweise nicht von innerhalb oder außerhalb des Clusters zugegriffen werden.
  • Dienstunterbrechungen: Bei einem Dienst kann es zu Unterbrechungen oder Verzögerungen kommen.
  • Kommunikationsprobleme zwischen Pods: Pods können möglicherweise nicht effektiv miteinander kommunizieren.

Verbindungsprobleme in Ihrem GKE-Cluster können verschiedene Ursachen haben, darunter:

  • Fehlkonfigurationen des Netzwerks: Falsche Netzwerkrichtlinien, Firewallregeln oder Routingtabellen.
  • Anwendungsfehler: Fehler im Anwendungscode, die sich auf Netzwerkinteraktionen auswirken.
  • Infrastrukturprobleme: Netzwerküberlastung, Hardwarefehler oder Ressourceneinschränkungen.

Im folgenden Abschnitt wird gezeigt, wie Sie das Problem bei den problematischen Knoten oder Pods beheben.

  1. Ermitteln Sie mit dem folgenden Befehl den Knoten, auf dem der problematische Pod ausgeführt wird:

    kubectl get pods POD_NAME -o=wide -n NAMESPACE
    

    Ersetzen Sie Folgendes:

    • POD_NAME durch den Namen des -Pods.
    • NAMESPACE durch den Kubernetes-Namespace.
  2. Stellen Sie eine Verbindung zum Knoten her:

    gcloud compute ssh NODE_NAME \
        --zone=ZONE
    

    Ersetzen Sie Folgendes:

    • NODE_NAME: Name Ihres Knotens.
    • ZONE: Name der Zone, in der der Knoten ausgeführt wird.
  3. Wenn Sie einen bestimmten Pod debuggen möchten, ermitteln Sie die veth-Schnittstelle, die mit dem Pod verknüpft ist:

    ip route | grep POD_IP
    

    Ersetzen Sie POD_IP durch die Pod-IP-Adresse.

  4. Führen Sie die Toolbox-Befehle aus.

toolbox-Befehle

toolbox ist ein Dienstprogramm, das eine containerisierte Umgebung in Ihren GKE-Knoten für das Debuggen und die Fehlerbehebung bereitstellt. In diesem Abschnitt wird beschrieben, wie Sie das Dienstprogramm toolbox installieren und damit Fehler am Knoten beheben.

  1. Starten Sie das toolbox-Tool, während Sie mit dem Knoten verbunden sind:

    toolbox
    

    Dadurch werden die Dateien heruntergeladen, die das toolbox-Dienstprogramm unterstützen.

  2. Installieren Sie tcpdump in der Root-Eingabeaufforderung toolbox:

    • Für Cluster mit externen IP-Adressen oder Cloud NAT:

      apt update -y && apt install -y tcpdump
      
    • Für private Cluster ohne Cloud NAT:

      Wenn Sie einen privaten Cluster ohne Cloud NAT haben, können Sie tcpdump nicht mit apt installieren. Laden Sie stattdessen die Release-Dateien libpcap und tcpdump aus dem offiziellen Repository herunter und kopieren Sie sie mit gcloud compute scp oder gsutil auf die VM. Installieren Sie die Bibliotheken dann manuell mit den folgenden Schritten:

      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
      

      Ersetzen Sie Folgendes:

      • USER_NAME: Ihr Nutzername auf dem System, auf dem sich die Dateien befinden.
      • VERSION: Die spezifische Versionsnummer der tcpdump- und libpcap-Pakete.
  3. Starten Sie die Paketerfassung:

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

    Ersetzen Sie Folgendes:

    • PORT: Name Ihrer Portnummer.
    • CAPTURE_FILE_NAME: Name der Aufnahmedatei.
  4. Beenden Sie die Paketerfassung und unterbrechen Sie die tcpdump.

  5. Verlassen Sie die Toolbox, indem Sie exit eingeben.

  6. Liste der Paket-Capture-Datei aufrufen und Größe prüfen:

    ls -ltr /mnt/stateful_partition/CAPTURE_FILE_NAME
    
  7. Kopieren Sie die Paketerfassung vom Knoten in das aktuelle Arbeitsverzeichnis auf Ihrem Computer:

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

    Ersetzen Sie Folgendes:

    • NODE_NAME: Name Ihres Knotens.
    • CAPTURE_FILE_NAME: Name der Aufnahmedatei.
    • ZONE: Name der Zone.

Alternative Befehle

Sie können auch die folgenden Methoden verwenden, um Verbindungsprobleme bei den problematischen Pods zu beheben:

Probleme mit der Pod-Netzwerkverbindung

Damit Sie Fehler erfolgreich beheben können, sollten Sie wissen, wie die Netzwerk-Namespaces von Pods mit dem Stamm-Namespace auf dem Knoten verbunden sind (siehe Netzwerkübersicht). Gehen Sie bei der folgenden Erläuterung davon aus, dass der Cluster das native CNI von GKE und nicht das CNI von Calico verwendet (sofern nicht anders angegeben). Das heißt, es wurde keine Netzwerkrichtlinie angewendet.

Pods auf bestimmten Knoten sind nicht verfügbar

Wenn Pods auf bestimmten Knoten keine Netzwerkverbindung haben, prüfen Sie, ob die Linux-Bridge aktiv ist:

ip address show cbr0

Wenn die Linux-Bridge nicht aktiv ist, starten Sie sie:

sudo ip link set cbr0 up

Prüfen Sie, ob der Knoten Pod-MAC-Adressen in Erfahrung bringt, die zu cbr0 gehören:

arp -an

Pods auf bestimmten Knoten haben nur minimale Konnektivität

Wenn Pods auf bestimmten Knoten nur minimale Konnektivität haben, sollten Sie zuerst prüfen, ob Pakete verloren gegangen sind. Führen Sie dazu tcpdump im Toolbox-Container aus:

sudo toolbox bash

Installieren Sie tcpdump in der Toolbox, wenn nicht bereits geschehen:

apt install -y tcpdump

Führen Sie tcpdump für cbr0 aus:

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

Wenn es so aussieht, als würden große Pakete nach der Bridge verloren gehen (der TCP-Handshake wird beispielsweise abgeschlossen, es gehen aber keine SSL-Hellos ein), prüfen Sie, ob die MTU für jede Linux-Pod-Schnittstelle richtig auf die die MTU des VPC-Netzwerks des Clusters festgelegt ist.

ip address show cbr0

Wenn Overlays verwendet werden (z. B. Weave oder Flannel), muss dieser MTU-Wert weiter reduziert werden, um Kapselungsoverhead für das Overlay aufzufangen.

GKE-MTU

Die für eine Pod-Schnittstelle ausgewählte MTU hängt von der von den Clusterknoten verwendeten Container Network Interface (CNI) und der zugrunde liegenden VPC-MTU-Einstellung ab. Weitere Informationen finden Sie unter Pods.

Der MTU-Wert der Pod-Schnittstelle ist entweder 1460 oder wird von der primären Schnittstelle des Knotens übernommen.

CNI MTU GKE Standard
kubenet 1460 Standard
kubenet
(GKE-Version 1.26.1 und höher)
Übernommen Standard
Calico 1460

Aktiviert mit --enable-network-policy.

Weitere Informationen finden Sie unter Kommunikation zwischen Pods und Services mithilfe von Netzwerkrichtlinien steuern.

netd Übernommen Aktiviert durch Verwendung einer der folgenden Optionen:
GKE Dataplane V2 Übernommen

Aktiviert mit --enable-dataplane-v2.

Weitere Informationen finden Sie unter GKE Dataplane V2 verwenden.

Zeitweise fehlgeschlagene Verbindungen

Verbindungen zu und von den Pods werden von iptables weitergeleitet. Datenflüsse werden als Einträge in der Conntrack-Tabelle verfolgt. Wenn viele Arbeitslasten pro Knoten vorhanden sind, kann die Überfüllung der Conntrack-Tabelle zu einem Fehler führen. Solche Fehler können in der seriellen Konsole des Knotens protokolliert werden. Beispiel:

nf_conntrack: table full, dropping packet

Wenn sich zeitweise auftretende Probleme auf eine volle Conntrack-Tabelle zurückführen lassen, können Sie die Größe des Clusters erhöhen, um die Anzahl der Arbeitslasten und Datenflüsse pro Knoten zu reduzieren, oder nf_conntrack_max erhöhen:

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

Sie können auch NodeLocal DNSCache verwenden, um Einträge für das Verbindungs-Tracking zu reduzieren.

„bind: Address already in use“ wird für einen Container gemeldet

Aus den Containerlogs geht hervor, dass ein Container in einem Pod nicht gestartet werden kann, da der Port, an den sich die Anwendung binden möchte, bereits reserviert ist. Der Container gerät in eine Absturzschleife. Zum Beispiel 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

Wenn Docker abstürzt, wird manchmal ein veralteter Container weiterhin ausgeführt. Der Prozess läuft im Netzwerk-Namespace weiter, der dem Pod zugewiesen ist, und überwacht seinen Port. Da Docker und das kubelet nichts von dem veralteten Container wissen, versuchen sie, einen neuen Container mit einem neuen Prozess zu starten. Dieser Prozess kann sich jedoch nicht an den Port binden, da er dem Netzwerk-Namespace hinzugefügt wird, der bereits mit dem Pod verknüpft ist.

So diagnostizieren Sie dieses Problem:

  1. Sie benötigen die UUID des Pods im Feld .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. Rufen Sie die Ausgabe der folgenden Befehle vom Knoten ab:

    docker ps -a
    ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]
    
  3. Prüfen Sie die laufenden Prozesse von diesem Pod. Da die UUID der cgroup-Namespaces die UUID des Pods enthält, können Sie die Pod-UUID mit grep in ps ausgeben. Rufen Sie auch die Zeile davor mit grep ab, sodass Sie die docker-containerd-shim-Prozesse erhalten, die auch die Container-ID im Argument haben. Schneiden Sie den Rest der cgroup-Spalte ab, um die Ausgabe zu vereinfachen:

    # 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. Dieser Liste können Sie die Container-IDs entnehmen, die auch in docker ps sichtbar sein sollten.

    In diesem Fall:

    • docker-containerd-shim 276e173b0846e24b704d4 für pause
    • docker-containerd-shim ab4c7762f5abf40951770 für sh mit sleep (sleep-ctr)
    • docker-containerd-shim 44e76e50e5ef4156fd5d3 für nginx (echoserver-ctr)
  5. Prüfen Sie diese in der Ausgabe von 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
    

    Normalerweise werden alle Container-IDs aus ps in docker ps angezeigt. Wenn Sie eine ID nicht sehen, ist der Container veraltet. Wahrscheinlich sehen Sie dann einen untergeordneten Prozess von docker-containerd-shim process, der den TCP-Port überwacht, der als bereits verwendet gemeldet wird.

    Damit Sie das prüfen können, führen Sie netstat im Netzwerk-Namespace des Containers aus. Rufen Sie die PID eines beliebigen Containerprozesses (jedoch NICHT docker-containerd-shim) für den Pod ab.

    Aus dem vorherigen Beispiel:

    • 1283107 – pause
    • 1283169 – sh
    • 1283185 – sleep
    • 1283263 – nginx-Master
    • 1283282 – nginx-Worker
    # 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
    

    Sie können auch netstat mit ip netns ausführen, müssen jedoch den Netzwerk-Namespace des Prozesses manuell verbinden, da Docker die Verbindung nicht herstellt:

    # 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
    

Abhilfe:

Zur vorläufigen Abhilfe können Sie veraltete Prozesse mit der zuvor beschriebenen Methode identifizieren und die Prozesse mit dem Befehl kill [PID] beenden.

Zur langfristigen Abhilfe müssen Sie feststellen, warum Docker abstürzt, und dieses Problem beheben. Mögliche Gründe:

  • Es sammeln sich Zombie-Prozesse an, sodass PID-Namespaces ausgehen
  • Programmfehler in Docker
  • Ressourcenknappheit/nicht genügend Arbeitsspeicher

Nächste Schritte