Soluciona los problemas de conectividad en tu clúster


En esta página, se muestra cómo resolver problemas de conectividad en tu clúster.

Problemas de conectividad relacionados con la captura de paquetes de red en GKE

En esta sección, se describe cómo solucionar problemas de conectividad relacionados con la captura de paquetes de red, incluidos los síntomas como los tiempos de espera de conexión, los errores de conexión rechazada o el comportamiento inesperado de la aplicación. Estos problemas de conectividad pueden ocurrir a nivel del nodo o del pod.

Los problemas de conectividad en la red de tu clúster suelen estar en las siguientes categorías:

  • No se puede acceder a los Pods: Es posible que no se pueda acceder a un Pod desde el interior ni el exterior del clúster debido a una configuración incorrecta de la red.
  • Interrupciones del servicio: Un servicio puede estar experimentando interrupciones o retrasos.
  • Problemas de comunicación entre Pods: Es posible que los Pods no puedan comunicarse entre sí de manera eficaz.

Los problemas de conectividad en tu clúster de GKE pueden originarse por varias causas, incluidas las siguientes:

  • Parámetros de configuración incorrectos de la red: Políticas de red, reglas de firewall o tablas de enrutamiento incorrectas
  • Errores de la aplicación: Errores en el código de la aplicación que afectan las interacciones de red.
  • Problemas de infraestructura: Congestión de red, fallas de hardware o limitaciones de recursos.

En la siguiente sección, se muestra cómo resolver el problema en los nodos o Pods problemáticos.

  1. Identifica el nodo en el que se ejecuta el Pod problemático con el siguiente comando:

    kubectl get pods POD_NAME -o=wide -n NAMESPACE
    

    Reemplaza lo siguiente:

    • POD_NAME por el nombre del Pod.
    • NAMESPACE por el espacio de nombres de Kubernetes.
  2. Conéctate al nodo:

    gcloud compute ssh NODE_NAME \
        --zone=ZONE
    

    Reemplaza lo siguiente:

    • NODE_NAME: el nombre de tu nodo.
    • ZONE: el nombre de la zona en la que se ejecuta el nodo.
  3. Para depurar un Pod específico, identifica la interfaz veth asociada con el Pod:

    ip route | grep POD_IP
    

    Reemplaza POD_IP por la dirección IP del Pod.

  4. Ejecuta los comandos de la caja de herramientas.

Comandos toolbox

toolbox es una utilidad que proporciona un entorno alojado en contenedores dentro de tus nodos de GKE para depurar y solucionar problemas. En esta sección, se describe cómo instalar la utilidad toolbox y usarla para solucionar problemas del nodo.

  1. Cuando estés conectado al nodo, inicia la herramienta de toolbox:

    toolbox
    

    Esta acción descarga los archivos que facilitan la utilidad toolbox.

  2. En el mensaje raíz toolbox, instala tcpdump:

    • Para clústeres con direcciones IP externas o Cloud NAT:

      apt update -y && apt install -y tcpdump
      
    • Para clústeres privados sin Cloud NAT:

      Si tienes un clúster privado sin Cloud NAT, no puedes instalar tcpdump mediante apt. En su lugar, descarga los archivos de actualización libpcap y tcpdump del repositorio oficial y copia los archivos en la VM mediante gcloud compute scp o gsutil. Luego, instala las bibliotecas manualmente con los siguientes pasos:

      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
      

      Reemplaza lo siguiente:

      • USER_NAME: Tu nombre de usuario en el sistema en el que se encuentran los archivos.
      • VERSION: El número de versión específico de los paquetes tcpdump y libpcap.
  3. Inicia la captura de paquetes:

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

    Reemplaza lo siguiente:

    • PORT: el nombre de tu número de puerto.
    • CAPTURE_FILE_NAME: el nombre de tu archivo de captura.
  4. Detén la captura de paquetes e interrumpe el tcpdump.

  5. Para salir de la caja de herramientas, escribe exit.

  6. Enumera el archivo de captura de paquetes y verifica su tamaño:

    ls -ltr /mnt/stateful_partition/CAPTURE_FILE_NAME
    
  7. Copia la captura de paquetes del nodo al directorio de trabajo actual de tu computadora:

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

    Reemplaza lo siguiente:

    • NODE_NAME: el nombre de tu nodo.
    • CAPTURE_FILE_NAME: el nombre de tu archivo de captura.
    • ZONE: el nombre de tu zona.

Comandos alternativos

También puedes usar las siguientes formas para solucionar problemas de conectividad en los Pods problemáticos:

Problemas de conectividad de red del pod

Como se mencionó en el debate de Descripción general de la red, es importante comprender cómo los Pods están conectados desde sus espacios de nombres de red con el espacio de nombres raíz en el nodo para solucionar problemas de manera efectiva. En el siguiente debate, supone que el clúster usa el CNI nativo de GKE en lugar del de Calico, a menos que se indique lo contrario. Es decir, no se aplicó ninguna política de red.

Los pods en nodos seleccionados no tienen disponibilidad

Si los pods en nodos seleccionados no tienen conectividad de red, asegúrate de que el puente de Linux esté activo:

ip address show cbr0

En caso contrario, actívalo:

sudo ip link set cbr0 up

Asegúrate de que el nodo esté aprendiendo las direcciones MAC de pod adjuntas en cbr0:

arp -an

Los pods en los nodos seleccionados tienen conectividad mínima

Si los pods en los nodos seleccionados tienen una conectividad mínima, primero debes confirmar si hay paquetes perdidos. Para ello, ejecuta tcpdump en el contenedor de la caja de herramientas:

sudo toolbox bash

Instala tcpdump en la caja de herramientas si aún no lo hiciste:

apt install -y tcpdump

Ejecuta tcpdump para cbr0:

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

Si parece que los paquetes grandes se descartan más adelante en el puente (por ejemplo, el protocolo de enlace TCP se completa, pero no se reciben saludos SSL), asegúrate de que la MTU para cada interfaz de Pod de Linux esté configurada de manera correcta en la MTU de la red de VPC del clúster.

ip address show cbr0

Cuando se utilizan superposiciones (por ejemplo, Weave o Flannel), esta MTU debe reducirse aún más para acomodar la sobrecarga de encapsulación en la superposición.

MTU de GKE

La MTU seleccionada para una interfaz de Pod depende de la Interfaz de red de contenedor (CNI) que usan los nodos del clúster y la configuración de MTU de VPC subyacente. Para obtener más información, consulta Pods.

El valor de MTU de la interfaz del Pod es 1460 o se hereda de la interfaz principal del nodo.

CNI MTU GKE Standard
kubenet 1,460 Predeterminado
kubenet
(GKE versión 1.26.1 y posteriores)
Heredada Predeterminado
Calico 1,460

Se habilita mediante --enable-network-policy.

Para obtener más información, consulta Controla la comunicación entre Pods y Services mediante las políticas de red.

netd Heredada Se habilita mediante cualquiera de las siguientes opciones:
GKE Dataplane V2 Heredada

Se habilita mediante --enable-dataplane-v2.

Para obtener más información, consulta Usa GKE Dataplane V2.

Conexiones fallidas intermitentes

iptables reenvía las conexiones hacia y desde los pods. Los flujos se registran como entradas en la tabla conntrack y, cuando hay muchas cargas de trabajo por nodo, el agotamiento de la tabla de conntrack puede manifestarse como un error. Estos se pueden registrar en la consola en serie del nodo, por ejemplo:

nf_conntrack: table full, dropping packet

Si puedes determinar que los problemas intermitentes se generan debido al agotamiento de conntrack, es recomendable aumentar el tamaño del clúster (y así reducir la cantidad de cargas de trabajo y flujos por nodo) o aumentar 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

También puedes usar NodeLocal DNSCache para reducir las entradas de seguimiento de conexiones.

Se informa un mensaje que dice "vincular: la dirección ya está en uso" para un contenedor

Un contenedor en un pod no puede iniciarse porque, de acuerdo con los registros del contenedor, el puerto al que la aplicación intenta vincularse ya está reservado. El contenedor entra en una falla de repetición. Por ejemplo, en Cloud Logging, se muestra lo siguiente:

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

Cuando Docker falla, a veces un contenedor en ejecución se retrasa y queda inactivo. El proceso todavía se está ejecutando en el espacio de nombres de red asignado para el pod, y está escuchando en su puerto. Debido a que Docker y el kubelet no saben sobre el contenedor inactivo, intentan iniciar un nuevo contenedor con un proceso nuevo, que no puede vincularse en el puerto, ya que se agrega al espacio de nombres de red ya asociado con el pod.

Para diagnosticar este problema, haz lo siguiente:

  1. Necesitas el UUID del pod en el campo .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. Obtén el resultado de los siguientes comandos del nodo:

    docker ps -a
    ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]
    
  3. Verifica los procesos en ejecución de este pod. Debido a que el UUID de los espacios de nombres de cgroup contiene el UUID del pod, puedes usar el comando grep para buscar el UUID del pod en el resultado ps. Usa también el comando grep para analizar la línea anterior, de modo que obtengas los procesos docker-containerd-shim que tienen el ID del contenedor en el argumento. Corta el resto de la columna cgroup para obtener un resultado más simple:

    # 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. En esta lista, puedes ver los ID de contenedor, que también deben estar visibles en docker ps.

    En este caso, ocurre lo siguiente:

    • docker-containerd-shim 276e173b0846e24b704d4 para pausar
    • docker-containerd-shim ab4c7762f5abf40951770 para SH con sleep (sleep-ctr)
    • docker-containerd-shim 44e76e50e5ef4156fd5d3 para nginx (echoserver-ctr)
  5. Verifica aquellos en el resultado 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
    

    En casos normales, verás todos los ID de contenedor de ps que aparecen en docker ps. Si hay uno que no ves, es un contenedor inactivo, y es probable que veas un proceso secundario del proceso docker-containerd-shim process a la escucha en el puerto TCP que informa que ya está en uso.

    Para verificar esto, ejecuta netstat en el espacio de nombres de red del contenedor. Obtén el pid de cualquier proceso de contenedor (así que NO docker-containerd-shim) del pod.

    En el ejemplo anterior, se incluye lo siguiente:

    • 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
    

    También puedes ejecutar netstat mediante ip netns, pero necesitas vincular el espacio de nombres de red del proceso de forma manual, ya que Docker no realiza la vinculación:

    # 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
    

Mitigación:

La mitigación a corto plazo consiste en identificar procesos inactivos con el método descrito antes y finalizar los procesos mediante el comando kill [PID].

La mitigación a largo plazo implica identificar por qué Docker falla y solucionar el problema. Algunos motivos posibles son los siguientes:

  • Los procesos zombie se acumulan, por lo que no hay espacios de nombres PID
  • Error en Docker
  • Presión de recursos / OOM

¿Qué sigue?