Cómo inspeccionar las redes de Kubernetes

Introducción

Kubernetes es un sistema de orquestación de contenedores que puede gestionar aplicaciones en contenedores a través de un clúster de nodos de servidor. Para el mantenimiento de la conectividad de red entre todos los contenedores de un clúster se requieren técnicas avanzadas de red. En este artículo, abordaremos brevemente algunas herramientas y técnicas para inspeccionar esta configuración de red.

Estas herramientas pueden ser útiles si depura errores de conectividad, investiga problemas de rendimiento de la red o explora Kubernetes para aprender cómo funciona.

Si desea conocer más sobre Kubernetes en general, en nuestra guía Introducción a Kubernetes se abarcan los aspectos básicos. Para acceder a una descripción general específica de Kubernetes, lea Análisis exhaustivo de las redes de Kubernetes.

Primeros pasos

Para este tutorial se espera que tenga un clúster de Kubernetes, con kubectl instalado localmente y configurado para conectarse al clúster.

Las siguientes secciones contienen muchos comandos pensados para ejecutarse en un nodo de Kubernetes. Tendrán el siguiente aspecto:

  • echo 'this is a node command'

Los comandos que deben ejecutarse en su máquina local tendrán el siguiente aspecto:

  • echo 'this is a local command'

Nota: La mayoría de los comandos de este tutorial deberán ejecutarse a través del usuario root. Si en su lugar utiliza un usuario habilitado para sudo en sus nodos de Kubernetes, añada sudo para ejecutar los comandos cuando sea necesario.

Encontrar el IP del clúster de un pod

Para encontrar la dirección IP del clúster de un pod de Kubernetes, utilice el comando kubectl get pod en su máquina local, con la opción -o wide. Esta opción mostrará más información, incluido el nodo en el que reside el pod y ek IP del clúster del 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 columna IP contendrá la dirección IP del clúster interno de cada pod.

Si no ve el pod que busca, asegúrese de estar posicionado en el espacio de nombres correcto. Puede listar todos los pods en todos los espacios de nombres añadiendo el indicador --all-namespaces.

Encontrar el IP de un servicio

También se puede encontrar un IP de servicio con kubectl. En este caso listaremos todos los servicios en todos los espacios de nombres:

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

El IP del servicio se encuentra en la columna CLUSTER-IP.

Buscar e ingresar espacios de nombres de red de pods

A cada pod de Kubernetes se le asigna su propio espacio de nombres de red. Los espacios de nombres de red (o netns) son una primitiva red de Linux que proporciona aislamiento entre dispositivos de red.

Puede ser útil ejecutar comandos desde dentro de los netns de un pod, para comprobar la resolución de DNS o la conectividad general de la red. Para ello, primero tenemos que buscar el ID de proceso de uno de los contenedores de un pod. En el caso de Docker, podemos hacerlo con una serie de dos comandos. Primero, listar los contenedores que se ejecutan en un nodo:

  • 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 . . . 

Encuentre el ID de contenedor *o *nombre de cualquier contenedor en el pod que le interese. En la imagen anterior, mostramos dos contenedores:

  • El primer contenedor es la aplicación hello-world que se ejecuta en el pod hello-world.
  • El segundo es un contenedor de pausa que funciona en el pod hello-world. Este contenedor existe únicamente para preservar el espacio de nombres de red del pod.

Para obtener el ID de proceso de cualquiera de los contenedores, tome nota del ID o nombre del contenedor y utilícelo en el siguiente comando docker.

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

Se emitirá un ID de proceso (o PID). Ahora podemos utilizar el programa nsenter para ejecutar un comando en el espacio de nombres de red de ese proceso:

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

Asegúrese de utilizar su propio PID, y reemplace ip addr por el comando que le gustaría ejecutar dentro del espacio de nombres de red del pod.

Nota: Una ventaja de utilizar nsenter para ejecutar comandos en el espacio de nombres de un pod (frente al uso de una opción como docker exec) es que se puede acceder a todos los comandos disponibles en el nodo, en lugar del conjunto normalmente limitado de comandos instalados en contenedores.

Encontrar la interfaz Ethernet virtual de un pod

El espacio de nombres de red de cada pod se comunica con netns root del nodo a través de un conducto Ethernet virtual. Del lado del nodo, este conducto aparece como un dispositivo que normalmente comienza con veth y termina en un identificador único, como veth77f2275 o veth01. Dentro del pod, este conducto aparece como eth0.

Puede ser útil para correlacionar el dispositivo veth que se empareja con un pod determinado. Para ello, listaremos todos los dispositivos de red del nodo y luego los dispositivos del espacio de nombres de red del pod. A continuación, podremos correlacionar los números de dispositivo entre los dos listados para realizar la conexión.

Primero, ejecute ip addr en el espacio de nombres de red del pod con nsenter. Consulte la sección anterior Buscar e ingresar espacios de nombres de red de pods para obtener información sobre cómo hacer esto:

  • nsenter -t your-container-pid -n ip addr
Output1: lo: <LOOPBACK,UP,LOWER_UP> 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: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> 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 

El comando emitirá una lista de las interfaces del pod. Observe el número if11 después de [email protected] en la imagen de ejemplo. Esto significa que el eth0 de este pod está vinculado a la interfaz 11 del nodo. Ahora ejecute ip addr en el espacio de nombres predeterminado del nodo para listar sus interfaces:

  • ip addr
Output1: lo: <LOOPBACK,UP,LOWER_UP> 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: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> 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: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> 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: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> 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 interfaz 11 es veth4f7342d en esta imagen de ejemplo. Este es el conducto Ethernet virtual al pod que investigaremos.

Inspeccionar el seguimiento de la conexión del conntrack

Antes de la versión 1.11, en Kubernetes se utilizaban iptables NAT y el módulo kernel del conntrack para controlar las conexiones. Para listar todas las conexiones actualmente controladas, utilice el comando conntrack:

  • conntrack -L

Para buscar continuamente nuevas conexiones, utilice el indicador -E:

  • conntrack -E

Para listar las conexiones controladas por conntrack a una dirección de destino concreta, utilice el indicador -d:

  • conntrack -L -d 10.32.0.1

Si sus nodos tienen problemas para establecer conexiones fiables con los servicios, es posible que la tabla de seguimiento de conexiones esté llena y que se inhabiliten las nuevas conexiones. En este caso, es posible que vea mensajes como los siguientes en sus registros de sistema:

/var/log/syslog

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

Existe una configuración de sysctl para el número máximo de conexiones que se controlarán. Puede hacer una lista de su valor actual con el siguiente comando:

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

Para establecer un nuevo valor, utilice el indicador -w:

  • sysctl -w net.netfilter.nf_conntrack_max=198000

Para que este ajuste sea permanente, agréguelo al archivo sysctl.conf:

/etc/sysctl.conf

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

Inspeccionar reglas de iptables

Antes de la versión 1.11, Kubernetes utilizaba iptables NAT para implementar la conversión de IP virtuales y el balanceo de carga para los IP de servicios.

Para volcar todas las reglas de iptables en un nodo, utilice el comando iptables-save:

  • iptables-save

Dado que el resultado puede ser muy extenso, es posible que desee realizar una transferencia a un archivo (iptables-save > output.txt) o a un localizador (iptables-save | less) para revisar más fácilmente las reglas.

Para listar solo las reglas de NAT del servicio de Kubernetes, utilice el comando iptables y el indicador -L a fin de especificar la cadena correcta:

  • 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 . . . 

Consultas al DNS del clúster

Una forma de depurar la resolución del DNS de su clúster es implementar un contenedor de depuración con todas las herramientas que necesite y utilizar kubectl para ejecutar nslookup en él. Esto se describe en la documentación oficial de Kubernetes.

Otra forma de consultar el clúster DNS es utilizar dig y nsenter de un nodo. Si dig no está instalado, puede instalarse con apt en las distribuciones de Linux basadas en Debian:

  • apt install dnsutils

Primero, busque el IP del clúster del servicio kube-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   <none>        53/UDP,53/TCP   15d 

El IP del clúster se resalta arriba. A continuación, utilizaremos nsenter para ejecutar dig en el espacio de nombres de un contenedor. Consulte la sección Encontrar e ingresar espacios de nombres de red de pod para obtener más información al respecto:

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

Este comando dig busca el nombre de dominio completo del servicio de service-name.namespace.svc.cluster.local y especifica el IP de servicio del DNS del clúster (@10.32.0.10) .

Revisión de la información de IPVS

A partir de la versión 1.11, kube-proxy puede configurar IPVS para gestionar la conversión de los IP de servicios virtuales a IP de pod. Puede listar la tabla de conversión de IP con ipvsadm:

  • 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 

Para mostrar un solo IP de servicio, utilice la opción -t y especifique el IP deseado:

  • 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 

Conclusión

A lo largo de este artículo, revisamos comandos y técnicas para explorar e inspeccionar los detalles de la red de su clúster de Kubernetes. Para obtener más información sobre Kubernetes, consulte el tema de nuestros tutoriales de Kubernetes y la documentación oficial de Kubernetes.