Verbindungsprobleme im Cluster beheben

Auf dieser Seite wird beschrieben, wie Sie Verbindungsprobleme in Ihrem Google Kubernetes Engine-Cluster (GKE) beheben.

Verbindungsprobleme im Zusammenhang mit dem 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 Pod-Ebene auftreten.

Verbindungsprobleme in Ihrem Clusternetzwerk lassen sich häufig in die folgenden Kategorien einteilen:

  • 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 die Netzwerkinteraktionen auswirken.
  • Infrastrukturprobleme: Netzwerküberlastung, Hardwarefehler oder Ressourceneinschränkungen.

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

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

    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 mit dem Pod verknüpfte veth-Schnittstelle:

    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 auf Ihren GKE-Knoten für das Debugging und die Fehlerbehebung bereitstellt. In diesem Abschnitt wird beschrieben, wie Sie das toolbox-Dienstprogramm installieren und damit Fehler auf dem 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 ermöglichen.

  2. Installieren Sie tcpdump an 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 die Dateien mit gcloud compute scp oder gcloud storage cp auf die VM. Installieren Sie die Bibliotheken dann manuell:

      # Copy the downloaded packages to a staging area
      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/
      
      # Extract the archives
      tar -xvzf tcpdump-VERSION.tar.gz
      tar -xvzf libpcap-VERSION.tar.gz
      
      # Build and install libpcap (a dependency for tcpdump)
      cd libpcap-VERSION
      ./configure ; make ; make install
      
      # Build and install tcpdump
      cd ../tcpdump-VERSION
      ./configure ; make ; make install
      
      # Verify tcpdump installation
      tcpdump --version
      

      Ersetzen Sie Folgendes:

      • USER_NAME: Ihr Nutzername auf dem System, auf dem sich die Dateien befinden.
      • VERSION: die spezifische Versionsnummer der Pakete tcpdump und libpcap.
  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 tcpdump.

  5. Beenden Sie die Toolbox durch Eingabe von exit.

  6. Listen Sie die Paketaufzeichnungsdatei auf und prüfen Sie ihre Größe:

    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 haben auch folgende Möglichkeiten, Verbindungsprobleme auf den problematischen Pods zu beheben:

  • Flüchtige Debugging-Arbeitslast, die an den Pod-Container angehängt ist.

  • Führen Sie mit kubectl exec eine Shell direkt auf dem Ziel-Pod aus und installieren und starten Sie dann den Befehl tcpdump.

Probleme mit der Netzwerkverbindung des Pods

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 die Anzahl der Einträge für die Verbindungsverfolgung 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