Résoudre les problèmes de connectivité de votre cluster


Cette page explique comment résoudre les problèmes de connectivité dans votre cluster.

Problèmes de connectivité liés à la capture de paquets réseau dans GKE

Cette section explique comment résoudre les problèmes de connectivité liés à la capture des paquets réseau, y compris les symptômes tels que expirations de connexions, les erreurs de connexion refusée ou les comportements d'application inattendus. Ces problèmes de connectivité peuvent se produire au niveau du nœud ou du pod.

Les problèmes de connectivité de votre réseau de cluster relèvent souvent des catégories suivantes :

  • Pods non accessibles : un pod peut ne pas être accessible depuis l'intérieur ou l'extérieur du cluster en raison d'une mauvaise configuration réseau.
  • Interruptions de service : un service peut subir des interruptions ou des retards.
  • Problèmes de communication entre pods : les pods peuvent ne pas être en mesure de communiquer efficacement entre eux.

Les problèmes de connectivité de votre cluster GKE peuvent provenir de diverses causes, y compris les suivantes :

  • Mauvaise configuration réseau : stratégies réseau, règles de pare-feu ou tables de routage incorrectes.
  • Bugs d'application : erreurs affectant les interactions réseau dans le code d'application.
  • Problèmes d'infrastructure : congestion du réseau, défaillances matérielles ou limites de ressources.

La section suivante montre comment résoudre le problème sur les nœuds ou les pods problématiques.

  1. Identifiez le nœud sur lequel le pod problématique s'exécute à l'aide de la commande suivante :

    kubectl get pods POD_NAME -o=wide -n NAMESPACE
    

    Remplacez les éléments suivants :

    • POD_NAME par le nom du pod.
    • NAMESPACE par l'espace de noms Kubernetes.
  2. Connectez-vous au nœud :

    gcloud compute ssh NODE_NAME \
        --zone=ZONE
    

    Remplacez les éléments suivants :

    • NODE_NAME : nom de votre nœud.
    • ZONE : nom de la zone dans laquelle le nœud s'exécute.
  3. Pour déboguer un pod spécifique, identifiez l'interface veth associée au pod :

    ip route | grep POD_IP
    

    Remplacez POD_IP par l'adresse IP du pod.

  4. Exécutez les commandes de la boîte à outils.

Commandes toolbox

toolbox est un utilitaire qui fournit un environnement conteneurisé dans vos nœuds GKE pour le débogage et le dépannage. Cette section explique comment installer l'utilitaire toolbox et l'utiliser pour résoudre les problèmes liés au nœud.

  1. Lorsque vous êtes connecté au nœud, démarrez l'outil toolbox :

    toolbox
    

    Les fichiers qui facilitent l'utilitaire toolbox sont téléchargés.

  2. Dans l'invite racine toolbox, installez tcpdump :

    • Pour les clusters avec des adresses IP externes ou Cloud NAT :

      apt update -y && apt install -y tcpdump
      
    • Pour les clusters privés sans Cloud NAT :

      Si vous disposez d'un cluster privé sans Cloud NAT, vous ne pouvez pas installer tcpdump à l'aide de apt. Au lieu de cela, téléchargez les fichiers de version libpcap et tcpdump à partir du dépôt officiel, puis copiez-les fichiers sur la VM à l'aide de gcloud compute scp ou gsutil. Installez ensuite les bibliothèques manuellement en procédant comme suit :

      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
      

      Remplacez les éléments suivants :

      • USER_NAME : votre nom d'utilisateur sur le système où se trouvent les fichiers.
      • VERSION : numéro de version spécifique des packages tcpdump et libpcap.
  3. Lancez la capture de paquets :

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

    Remplacez les éléments suivants :

    • PORT : nom de votre numéro de port.
    • CAPTURE_FILE_NAME : nom de votre fichier de capture.
  4. Arrêtez la capture de paquets et interrompez tcpdump.

  5. Quittez la boîte à outils en saisissant exit.

  6. Listez le fichier de capture de paquets et vérifiez sa taille :

    ls -ltr /mnt/stateful_partition/CAPTURE_FILE_NAME
    
  7. Copiez la capture de paquets du nœud vers le répertoire de travail actuel de votre ordinateur :

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

    Remplacez les éléments suivants :

    • NODE_NAME : nom de votre nœud.
    • CAPTURE_FILE_NAME : nom de votre fichier de capture.
    • ZONE : nom de votre zone.

Autres commandes

Vous pouvez également utiliser les méthodes suivantes pour résoudre les problèmes de connectivité sur les pods problématiques :

Problèmes de connectivité réseau du pod

Comme indiqué dans la partie Présentation du réseau, il est important de comprendre comment les pods sont connectés entre leurs espaces de noms réseau et l'espace de noms racine sur le nœud afin de procéder au dépannage de façon efficace. Dans la démonstration suivante, sauf indication contraire, nous supposerons que le cluster utilise la CNI native (Container Network Interface) de GKE plutôt que celle de Calico. C'est-à-dire qu'aucune stratégie réseau n'a été appliquée.

Les pods sur les nœuds sélectionnés n'ont pas de disponibilité

Si les pods sur certains nœuds ne disposent pas d'une connectivité réseau, assurez-vous que le pont Linux est actif :

ip address show cbr0

Si le pont Linux est arrêté, activez-le :

sudo ip link set cbr0 up

Assurez-vous que le nœud apprend les adresses MAC du pod associées à cbr0 :

arp -an

La connectivité des pods sur certains nœuds est minimale

Si les pods sur certains nœuds ont une connectivité minimale, vous devez d’abord rechercher une perte de paquets éventuelle en exécutant la commande tcpdump dans le conteneur de la boîte à outils :

sudo toolbox bash

Installez tcpdump dans la boîte à outils si ce n'est déjà fait :

apt install -y tcpdump

Exécutez tcpdump sur cbr0 :

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

Si vous constatez que des paquets volumineux sont rejetés en aval du pont (par exemple, le handshake TCP a bien lieu, mais aucun "hello" SSL n'est reçu), assurez-vous que la MTU de chaque interface de pod Linux est correctement définie sur la MTU deRéseau VPC du cluster.

ip address show cbr0

En cas d'utilisation de superpositions (par exemple, Weave ou Flannel), cette MTU doit être encore réduite pour tolérer la surcharge d'encapsulation sur la superposition.

MTU GKE

La MTU sélectionnée pour une interface de pod dépend de l'interface CNI (Container Network Interface) utilisée par les nœuds du cluster et du paramètre de MTU sous-jacent du VPC. Pour en savoir plus, consultez la section Pods.

La valeur de la MTU de l'interface de pod est 1460 ou héritée de l'interface principale du nœud.

CNI MTU GKE Standard
kubenet 1460 Par défaut
kubenet
(version 1.26.1 de GKE et versions ultérieures)
Hérité Par défaut
Calico 1460

Activation à l'aide de --enable-network-policy.

Pour en savoir plus, consultez la page Contrôler la communication entre les pods et les services à l'aide de règles de réseau.

netd Hérité Activation à l'aide de l'une des options suivantes :
GKE Dataplane V2 Hérité

Activation à l'aide de --enable-dataplane-v2.

Pour en savoir plus, consultez la page Utiliser GKE Dataplane V2.

Échecs de connexion intermittents

Les connexions vers et depuis les pods sont transférées au moyen de règles iptables. Les flux sont suivis en tant qu'entrées dans la table conntrack et, lorsqu'il existe de nombreuses charges de travail par nœud, l'épuisement de la table conntrack peut se traduire par un échec. Ceux-ci peuvent être enregistrés dans la console série du nœud, par exemple :

nf_conntrack: table full, dropping packet

Si vous parvenez à déterminer que les déconnexions intermittentes sont liées à l'épuisement de conntrack, augmentez la taille du cluster (réduisant ainsi le nombre de charges de travail et de flux par nœud), ou augmentez 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

Vous pouvez également utiliser NodeLocal DNSCache pour réduire les entrées de suivi de connexion.

"Liaison : adresse déjà utilisée" signalé pour un conteneur

Un conteneur dans un pod ne parvient pas à démarrer car, d'après les journaux du conteneur, le port auquel l'application tente de se connecter est déjà réservé. Le conteneur est bloqué dans une boucle de plantage. Par exemple, dans 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

Lorsque Docker plante, un conteneur en cours d'exécution est parfois laissé de côté et n'est plus actualisé. Le processus est toujours en cours d'exécution dans l'espace de noms réseau attribué au pod et en écoute sur son port. Comme Docker et le kubelet ignorent que le conteneur est obsolète, ils tentent de démarrer un nouveau conteneur avec un nouveau processus, qui ne peut pas se connecter au port puisqu'il est ajouté à l'espace de nom réseau déjà associé au pod.

Pour diagnostiquer ce problème, procédez comme suit :

  1. Vous avez besoin de l'UUID du pod dans le champ .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. Obtenez le résultat des commandes suivantes à partir du nœud :

    docker ps -a
    ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]
    
  3. Vérifiez les processus en cours depuis ce pod. Comme l'UUID des espaces de noms cgroup contient l'UUID du pod, vous pouvez utiliser une commande grep pour le pod UUID dans le résultat ps. Appliquez également une commande grep à la ligne précédente, de façon à obtenir les processus docker-containerd-shim qui contiennent aussi l'identifiant du conteneur dans l'argument. Coupez le reste de la colonne cgroup pour simplifier la sortie obtenue :

    # 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. Dans cette liste, les identifiants de conteneur s'affichent et devraient également être visibles dans docker ps.

    Dans ce cas :

    • docker-containerd-shim 276e173b0846e24b704d4 pour la mise en pause
    • docker-containerd-shim ab4c7762f5abf40951770 pour sh avec mise en veille (sleep-ctr)
    • docker-containerd-shim 44e76e50e5ef4156fd5d3 pour nginx (echoserver-ctr)
  5. Vérifiez les identifiants dans le résultat de 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
    

    Normalement, tous les identifiants de conteneur de ps apparaissent dans docker ps. Si l'un d'entre eux n'apparaît pas, il s'agit d'un conteneur obsolète, et vous verrez probablement un processus enfant de docker-containerd-shim process en écoute sur le port TCP signalé comme déjà utilisé.

    Pour le vérifier, exécutez la commande netstat dans l'espace de noms réseau du conteneur. Récupérez le pid d'un processus de conteneur pour le pod (et NON docker-containerd-shim).

    Dans l'exemple précédent :

    • 1283107 - pause
    • 1283169 - sh
    • 1283185 - veille
    • 1283263 - maître nginx
    • 1283282 - nœud de calcul 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
    

    Vous pouvez également exécuter netstat en utilisant ip netns, mais vous devez relier manuellement l'espace de noms réseau du processus, car Docker n'effectue par la liaison :

    # 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
    

Atténuation :

L'atténuation à court terme consiste à identifier les processus obsolètes à l'aide de la méthode décrite précédemment, puis à les éliminer en exécutant la commande kill [PID].

L'atténuation à long terme consiste à identifier l'origine des plantages de Docker et à y remédier. Voici les différents motifs possibles :

  • Les processus zombies s'empilent et les espaces de noms PID deviennent insuffisants
  • Bug dans Docker
  • Ressource saturée/OOM

Étape suivante

  • Pour obtenir des informations générales sur l'analyse des problèmes de DNS de Kubernetes, consultez la section Déboguer la résolution DNS.