Comment inspecter le réseau Kubernetes

introduction

Kubernetes est un système d'orchestration de conteneur capable de gérer des applications conteneurisées sur un cluster de nœuds de serveur. Le maintien de la connectivité réseau entre tous les conteneurs d'un cluster nécessite des techniques réseau avancées. Dans cet article, nous aborderons brièvement quelques outils et techniques permettant d'inspecter cette configuration réseau.

Ces outils peuvent être utiles si vous corrigez des problèmes de connectivité, étudiez des problèmes de débit du réseau ou explorez Kubernetes pour en apprendre plus sur son fonctionnement.

Si vous souhaitez en savoir plus sur Kubernetes en général, notre guideAn Introduction to Kubernetes couvre les bases. Pour un aperçu de Kubernetes spécifique au réseau, veuillez lireKubernetes Networking Under the Hood.

Commencer

Ce didacticiel suppose que vous disposez d'un cluster Kubernetes, aveckubectl installé localement et configuré pour se connecter au cluster.

Les sections suivantes contiennent de nombreuses commandes destinées à être exécutées sur un nœud Kubernetes. Ils vont ressembler à ceci:

echo 'this is a node command'

Les commandes devant être exécutées sur votre ordinateur local auront l'aspect suivant:

echo 'this is a local command'

[.note] #Note: La plupart des commandes de ce didacticiel devront être exécutées en tant qu'utilisateurroot. Si vous utilisez à la place un utilisateur sudo sur vos nœuds Kubernetes, ajoutezsudo pour exécuter les commandes si nécessaire.
#

Recherche d’une IP de cluster du pod

Pour trouver l'adresse IP du cluster d'un pod Kubernetes, utilisez la commandekubectl get pod sur votre machine locale, avec l'option-o wide. Cette option répertorie davantage d’informations, notamment le nœud sur lequel se trouve le pod et l’adresse IP du cluster du pod.

kubectl get pod -o wide
OutputNAME                           READY     STATUS    RESTARTS   AGE       IP            NODE
hello-world-5b446dd74b-7c7pk   1/1       Running   0          22m       10.244.18.4   node-one
hello-world-5b446dd74b-pxtzt   1/1       Running   0          22m       10.244.3.4    node-two

La colonneIP contiendra l'adresse IP du cluster interne pour chaque pod.

Si vous ne voyez pas le pod que vous recherchez, assurez-vous que vous êtes dans le bon espace de noms. Vous pouvez lister tous les pods dans tous les espaces de noms en ajoutant l'indicateur--all-namespaces.

Recherche de l’adresse IP d’un service

Nous pouvons également trouver une adresse IP de service en utilisantkubectl. Dans ce cas, nous listerons tous les services dans tous les espaces de noms:

kubectl get service --all-namespaces
OutputNAMESPACE     NAME                       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
default       kubernetes                 ClusterIP   10.32.0.1               443/TCP         6d
kube-system   csi-attacher-doplugin      ClusterIP   10.32.159.128           12345/TCP       6d
kube-system   csi-provisioner-doplugin   ClusterIP   10.32.61.61             12345/TCP       6d
kube-system   kube-dns                   ClusterIP   10.32.0.10              53/UDP,53/TCP   6d
kube-system   kubernetes-dashboard       ClusterIP   10.32.226.209           443/TCP         6d

L'adresse IP du service se trouve dans la colonneCLUSTER-IP.

Recherche et entrée d'espaces de noms de réseau de pod

Chaque pod Kubernetes se voit attribuer son propre espace de noms réseau. Les espaces de noms réseau (ou réseaux) sont une primitive réseau Linux qui fournit une isolation entre les périphériques réseau.

Il peut être utile d’exécuter des commandes à partir des réseaux d’un pod, pour vérifier la résolution DNS ou la connectivité générale du réseau. Pour ce faire, nous devons d’abord rechercher l’ID de processus de l’un des conteneurs d’un conteneur. Pour Docker, nous pouvons le faire avec une série de deux commandes. Commencez par répertorier les conteneurs s'exécutant sur un nœud:

docker ps
OutputCONTAINER ID        IMAGE                                   COMMAND                  CREATED             STATUS              PORTS               NAMES
173ee46a3926        gcr.io/google-samples/node-hello        "/bin/sh -c 'node se…"   9 days ago          Up 9 days                               k8s_hello-world_hello-world-5b446dd74b-pxtzt_default_386a9073-7e35-11e8-8a3d-bae97d2c1afd_0
11ad51cb72df        k8s.gcr.io/pause-amd64:3.1              "/pause"                 9 days ago          Up 9 days                               k8s_POD_hello-world-5b446dd74b-pxtzt_default_386a9073-7e35-11e8-8a3d-bae97d2c1afd_0
. . .

Recherchez lescontainer ID ouname de n'importe quel conteneur du pod qui vous intéresse. Dans la sortie ci-dessus, nous montrons deux conteneurs:

  • Le premier conteneur est l'applicationhello-world exécutée dans le podhello-world

  • Le second est un conteneurpause exécuté dans le podhello-world. Ce conteneur existe uniquement pour conserver l’espace de noms réseau du pod

Pour obtenir l'ID de processus de l'un ou l'autre conteneur, notez l'ID ou le nom du conteneur et utilisez-le dans la commandedocker suivante:

docker inspect --format '{{ .State.Pid }}' container-id-or-name
Output14552

Un identifiant de processus (ou PID) sera généré. Nous pouvons maintenant utiliser le programmensenter pour exécuter une commande dans l’espace de nom réseau de ce processus:

nsenter -t your-container-pid -n ip addr

Veillez à utiliser votre propre PID et remplacezip addr par la commande que vous souhaitez exécuter dans l’espace de nom réseau du pod.

[.note] #Note: Un avantage de l'utilisation densenter pour exécuter des commandes dans l'espace de noms d'un pod - par rapport à quelque chose commedocker exec - est que vous avez accès à toutes les commandes disponibles sur le nœud, au lieu de l'ensemble généralement limité de commandes installées dans les conteneurs.
#

Recherche de l’interface Ethernet virtuelle d’un pod

Chaque espace de noms réseau de chaque pod communique avec les réseaux racine du nœud via un canal Ethernet virtuel. Du côté du nœud, ce tube apparaît comme un périphérique qui commence généralement parveth et se termine par un identifiant unique, tel queveth77f2275 ouveth01. À l'intérieur du pod, ce tube apparaît sous la formeeth0.

Il peut être utile de corréler le périphériqueveth associé à un pod particulier. Pour ce faire, nous allons répertorier tous les périphériques réseau sur le nœud, puis les périphériques dans l’espace de noms réseau du pod. Nous pouvons ensuite corréler les numéros d'appareils entre les deux listes pour établir la connexion.

Tout d'abord, exécutezip addr dans l'espace de noms réseau du pod à l'aide densenter. Reportez-vous à la section précédenteFinding and Entering Pod Network Namespaces
pour plus de détails sur la façon de procéder:

nsenter -t your-container-pid -n ip addr
Output1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
10: eth0@if11:  mtu 1450 qdisc noqueue state UP group default
    link/ether 02:42:0a:f4:03:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.244.3.4/24 brd 10.244.3.255 scope global eth0
       valid_lft forever preferred_lft forever

La commande affichera une liste des interfaces du pod. Notez le nombreif11 aprèseth0@ dans l'exemple de sortie. Cela signifie que leeth0 de ce pod est lié à la 11e interface du nœud. Exécutez maintenantip addr dans l’espace de noms par défaut du nœud pour lister ses interfaces:

ip addr
Output1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever

. . .

7: veth77f2275@if6:  mtu 1450 qdisc noqueue master docker0 state UP group default
    link/ether 26:05:99:58:0d:b9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::2405:99ff:fe58:db9/64 scope link
       valid_lft forever preferred_lft forever
9: vethd36cef3@if8:  mtu 1450 qdisc noqueue master docker0 state UP group default
    link/ether ae:05:21:a2:9a:2b brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::ac05:21ff:fea2:9a2b/64 scope link
       valid_lft forever preferred_lft forever
11: veth4f7342d@if10:  mtu 1450 qdisc noqueue master docker0 state UP group default
    link/ether e6:4d:7b:6f:56:4c brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::e44d:7bff:fe6f:564c/64 scope link
       valid_lft forever preferred_lft forever

La 11ème interface estveth4f7342d dans cet exemple de sortie. C’est le canal Ethernet virtuel vers le pod sur lequel nous travaillons.

Inspection du suivi de la connexion Conntrack

Avant la version 1.11, Kubernetes utilisait le NAT iptables et le module de noyau conntrack pour suivre les connexions. Pour lister toutes les connexions en cours de suivi, utilisez la commandeconntrack:

conntrack -L

Pour surveiller en permanence les nouvelles connexions, utilisez l'indicateur-E:

conntrack -E

Pour répertorier les connexions suivies par conntrack à une adresse de destination particulière, utilisez l'indicateur-d:

conntrack -L -d 10.32.0.1

Si vos noeuds rencontrent des problèmes pour établir des connexions fiables aux services, il est possible que votre table de suivi des connexions soit saturée et que de nouvelles connexions soient abandonnées. Si tel est le cas, des messages tels que les suivants apparaissent dans les journaux de votre système:

/var/log/syslog

Jul 12 15:32:11 worker-528 kernel: nf_conntrack: table full, dropping packet.

Il existe un paramètre sysctl pour le nombre maximal de connexions à suivre. Vous pouvez lister votre valeur actuelle avec la commande suivante:

sysctl net.netfilter.nf_conntrack_max
Outputnet.netfilter.nf_conntrack_max = 131072

Pour définir une nouvelle valeur, utilisez l'indicateur-w:

sysctl -w net.netfilter.nf_conntrack_max=198000

Pour rendre ce paramètre permanent, ajoutez-le au fichiersysctl.conf:

/etc/sysctl.conf

. . .
net.ipv4.netfilter.ip_conntrack_max = 198000

Inspection des règles d'Iptables

Avant la version 1.11, Kubernetes utilisait le NAT iptables pour implémenter la traduction IP virtuelle et l'équilibrage de la charge pour les IP de service.

Pour vider toutes les règles iptables sur un nœud, utilisez la commandeiptables-save:

iptables-save

Comme la sortie peut être longue, vous souhaiterez peut-être diriger vers un fichier (iptables-save > output.txt) ou un pager (iptables-save | less) pour examiner plus facilement les règles.

Pour répertorier uniquement les règles NAT du service Kubernetes, utilisez la commandeiptables et l'indicateur-L pour spécifier la chaîne correcte:

iptables -t nat -L KUBE-SERVICES
OutputChain KUBE-SERVICES (2 references)
target     prot opt source               destination
KUBE-SVC-TCOU7JCQXEZGVUNU  udp  --  anywhere             10.32.0.10           /* kube-system/kube-dns:dns cluster IP */ udp dpt:domain
KUBE-SVC-ERIFXISQEP7F7OF4  tcp  --  anywhere             10.32.0.10           /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:domain
KUBE-SVC-XGLOHA7QRQ3V22RZ  tcp  --  anywhere             10.32.226.209        /* kube-system/kubernetes-dashboard: cluster IP */ tcp dpt:https
. . .

Interrogation du DNS du cluster

Une façon de déboguer la résolution DNS de votre cluster consiste à déployer un conteneur de débogage avec tous les outils dont vous avez besoin, puis à utiliserkubectl pour y exécuternslookup. Ceci est décrit dansthe official Kubernetes documentation.

Une autre façon d'interroger le DNS du cluster consiste à utiliserdig etnsenter à partir d'un nœud. Sidig n'est pas installé, il peut être installé avecapt sur les distributions Linux basées sur Debian:

apt install dnsutils

Tout d'abord, recherchez l'adresse IP du cluster du servicekube-dns:

kubectl get service -n kube-system kube-dns
OutputNAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.32.0.10           53/UDP,53/TCP   15d

L'IP du cluster est mis en évidence ci-dessus. Ensuite, nous utiliseronsnsenter pour exécuterdig dans l'espace de noms d'un conteneur. Regardez la sectionFinding and Entering Pod Network Namespaces pour plus d'informations à ce sujet:

nsenter -t 14346 -n dig kubernetes.default.svc.cluster.local @10.32.0.10

Cette commandedig recherche le nom de domaine complet du service deservice-name.namespace.svc.cluster.local et spécifie l'adresse IP de l'IP du service DNS du cluster (@10.32.0.10).

En regardant les détails IPVS

À partir de Kubernetes 1.11,kube-proxy peut configurer IPVS pour gérer la traduction des adresses IP de service virtuelles en IP de pod. Vous pouvez lister la table de traduction des adresses IP avecipvsadm:

ipvsadm -Ln
OutputIP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  100.64.0.1:443 rr
  -> 178.128.226.86:443           Masq    1      0          0
TCP  100.64.0.10:53 rr
  -> 100.96.1.3:53                Masq    1      0          0
  -> 100.96.1.4:53                Masq    1      0          0
UDP  100.64.0.10:53 rr
  -> 100.96.1.3:53                Masq    1      0          0
  -> 100.96.1.4:53                Masq    1      0          0

Pour afficher une seule adresse IP de service, utilisez l'option-t et spécifiez l'adresse IP souhaitée:

ipvsadm -Ln -t 100.64.0.10:53
OutputProt LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  100.64.0.10:53 rr
  -> 100.96.1.3:53                Masq    1      0          0
  -> 100.96.1.4:53                Masq    1      0          0

Conclusion

Dans cet article, nous avons examiné certaines commandes et techniques permettant d’explorer et d’analyser les détails du réseau de votre cluster Kubernetes. Pour plus d'informations sur Kubernetes, jetez un œil àour Kubernetes tutorials tag etthe official Kubernetes documentation.

Related