Resolver problemas de conectividade no cluster


Nesta página, mostramos como resolver problemas de conectividade no cluster.

Problemas de conectividade relacionados à captura de pacotes de rede no GKE

Esta seção descreve como resolver problemas de conectividade relacionados à captura pacotes de rede, incluindo sintomas como tempo limite de conexão, conexão recusada erros ou comportamento inesperado do aplicativo. Estes problemas de conectividade podem ocorrer no nível do nó ou do pod.

Os problemas de conectividade na rede do cluster geralmente estão nos seguintes categorias:

  • Os pods não estão acessíveis: um pod pode não ser acessível de dentro ou de fora do cluster devido a configurações incorretas da rede.
  • Interrupções no serviço: um serviço pode estar com interrupções ou atrasos.
  • Problemas de comunicação entre pods: os pods podem não conseguir se comunicar de maneira eficaz.

Os problemas de conectividade no cluster do GKE podem ter várias causas, incluindo as seguintes:

  • Configurações incorretas de rede: políticas de rede, regras de firewall, ou tabelas de roteamento.
  • Bugs do aplicativo: erros no código do aplicativo que afetam as interações de rede.
  • Problemas de infraestrutura: congestionamento de rede, falhas de hardware ou limitações de recursos.

A seção a seguir mostra como resolver o problema nos nós ou nós problemáticos os pods.

  1. Identifique o nó em que o pod problemático está em execução usando o seguinte comando:

    kubectl get pods POD_NAME -o=wide -n NAMESPACE
    

    Substitua:

    • POD_NAME pelo nome do pod.
    • NAMESPACE pelo namespace do Kubernetes.
  2. Conectar-se ao nós:

    gcloud compute ssh NODE_NAME \
        --zone=ZONE
    

    Substitua:

    • NODE_NAME: nome do nó.
    • ZONE: nome da zona em que o nó é executado.
  3. Para depurar um pod específico, identifique a interface veth associada a ele:

    ip route | grep POD_IP
    

    Substitua POD_IP pelo endereço IP do pod.

  4. Execute os comandos da caixa de ferramentas.

toolbox commands

O toolbox é um utilitário que fornece um ambiente conteinerizado no seu nós do GKE para depuração e solução de problemas. Isso descreve como instalar o utilitário toolbox e usá-lo para resolver problemas do nó.

  1. Enquanto conectado ao nó, inicie a ferramenta toolbox:

    toolbox
    

    Isso faz o download dos arquivos que facilitam o utilitário toolbox.

  2. No prompt raiz toolbox, instale tcpdump:

    • Para clusters com endereços IP externos ou Cloud NAT:

      apt update -y && apt install -y tcpdump
      
    • Para clusters particulares sem o Cloud NAT:

      Se você tiver um cluster particular sem o Cloud NAT, não será possível instalar tcpdump usando apt. Em vez disso, faça o download dos arquivos de lançamento libpcap e tcpdump do repositório oficial e copie os arquivos para a VM usando gcloud compute scp ou gsutil. Em seguida, instale as bibliotecas manualmente seguindo estas etapas:

      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
      

      Substitua:

      • USER_NAME: seu nome de usuário no sistema em que os arquivos estão localizados.
      • VERSION: o número de versão específico dos pacotes tcpdump e libpcap.
  3. Inicie a captura de pacotes:

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

    Substitua:

    • PORT: nome do número da porta.
    • CAPTURE_FILE_NAME: nome do arquivo de captura.
  4. Interrompa a captura de pacote e interrompa o tcpdump.

  5. Para sair da caixa de ferramentas, digite exit.

  6. Liste o arquivo de captura de pacotes e verifique o tamanho dele:

    ls -ltr /mnt/stateful_partition/CAPTURE_FILE_NAME
    
  7. Copie a captura de pacotes do nó para o diretório de trabalho atual no computador:

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

    Substitua:

    • NODE_NAME: nome do nó.
    • CAPTURE_FILE_NAME: nome do arquivo de captura.
    • ZONE: nome da zona.

Comandos alternativos

Você também pode usar as seguintes maneiras para resolver problemas de conectividade no pods problemáticos:

Problemas de conectividade de rede do pod

Conforme mencionado na discussão Visão geral da rede, é importante entender como os pods são conectados desde os namespaces de rede até o namespace raiz no nó para solucionar problemas com eficiência. Para a discussão a seguir, salvo indicação em contrário, suponha que o cluster use CNI nativa do GKE, em vez do Calico. Ou seja, nenhuma política de rede foi aplicada.

Pods em nós selecionados sem disponibilidade

Se os Pods em nós selecionados não tiverem conectividade de rede, verifique se a ponte do Linux está ativa:

ip address show cbr0

Se a ponte do Linux estiver inativa, ative-a:

sudo ip link set cbr0 up

Assegure que o nó esteja aprendendo os endereços MAC do Pod anexados ao cbr0:

arp -an

Pods em nós selecionados com conectividade mínima

Se os pods em nós selecionados tiverem conectividade mínima, primeiro é preciso confirmar se há algum pacote perdido executando tcpdump no contêiner da caixa de ferramentas:

sudo toolbox bash

Instale tcpdump na caixa de ferramentas se ainda não tiver feito isso:

apt install -y tcpdump

Execute tcpdump com cbr0:

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

Se parecer que grandes pacotes estão sendo descartados da ponte (por exemplo, o handshake TCP é concluído, mas nenhum SSL é recebido), verifique se a MTU de cada interface de pod do Linux está definida corretamente como { 101}a MTU doà rede VPC do cluster de dois minutos.

ip address show cbr0

Quando forem usadas sobreposições (por exemplo, Weave ou Flannel), essa MTU precisará ser ainda mais reduzida para acomodar a sobrecarga de encapsulamento.

MTU do GKE

A MTU selecionada para uma interface de pod depende da interface de rede de contêiner (CNI, na sigla em inglês) usada pelos nós do cluster e da configuração de MTU da VPC subjacente. Para mais informações, consulte Pods.

O valor da MTU da interface do pod é 1460 ou herdado da interface principal do nó.

CNI MTU GKE Standard
kubenet 1460 Padrão
kubenet
(GKE versão 1.26.1 e posterior)
Herdado Padrão
Calico 1460

Ativado usando --enable-network-policy.

Para detalhes, consulte Controlar a comunicação entre pods e Serviços usando políticas de rede.

netd Herdado Ativado usando uma destas opções:
GKE Dataplane V2 Herdado

Ativado usando --enable-dataplane-v2.

Para mais detalhes, consulte Como usar o GKE Dataplane V2.

Conexões com falha intermitente

Conexões de e para Pods são encaminhadas pelo iptables. Os fluxos são rastreados como entradas na tabela conntrack e, havendo muitas cargas de trabalho por nó, o esgotamento da tabela conntrack pode se manifestar como uma falha. Isso pode ser registrado no console serial do nó, por exemplo:

nf_conntrack: table full, dropping packet

Se você consegue determinar que problemas intermitentes são causados por esgotamento de conntrack, aumente o tamanho do cluster (reduzindo assim o número de cargas de trabalho e fluxos por nó) ou aumente o 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

Também é possível usar o DNSCache NodeLocal para reduzir as entradas de rastreamento de conexão.

"vincular: endereço já está em uso" relatado para um contêiner

Um contêiner em um Pod não pode iniciar porque, de acordo com os registros de contêiner, a porta em que o aplicativo está tentando se vincular já está reservada. O contêiner está em um ciclo de falha. Por exemplo, no 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

Quando o Docker falha, às vezes um contêiner em execução é deixado para trás e fica obsoleto. O processo ainda está executando no namespace de rede alocado para o Pod e escutando nessa porta. Como o Docker e o Kubelet desconhecem o contêiner obsoleto, eles tentam iniciar um novo contêiner com um novo processo, que não pode ser vinculado à porta já que está adicionado ao namespace de rede associada ao pod.

Para diagnosticar esse problema:

  1. Você precisa do UUID do pod no 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. Você recebe uma saída do nó com os seguintes comandos:

    docker ps -a
    ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]
    
  3. Verifique processos em execução desse pod. Como o UUID dos namespaces do cgroup contém o UUID do pod, execute grep para o UUID do pod na saída ps. Execute grep na linha anterior. Assim, poderá ter os processos docker-containerd-shim, além do ID do contêiner no argumento. Elimine o restante da coluna cgroup para conseguir uma saída mais simples:

    # 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. Nessa lista, é possível ver os IDs dos contêineres, que também devem estar visíveis no docker ps.

    Nesse caso:

    • docker-containerd-shim 276e173b0846e24b704d4 para pausar
    • docker-containerd-shim ab4c7762f5abf40951770 para sh com suspensão (sleep-ctr)
    • docker-containerd-shim 44e76e50e5ef4156fd5d3 para nginx (echoserver-ctr)
  5. Verifique os que estão na saída 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
    

    Nos casos normais, você vê todos os códigos dos contêineres de ps aparecendo em docker ps. Se algum deles não aparece, trata-se de um contêiner obsoleto, e provavelmente você verá um processo filho do docker-containerd-shim process detectando a porta TCP que informa já estar em uso.

    Para verificar isso, execute netstat no namespace de rede do contêiner. Receba o pid de qualquer processo de contêiner (diferente de docker-containerd-shim) para o pod.

    No exemplo anterior:

    • 1283107 - pausar
    • 1283169 - sh
    • 1283185 - suspensão
    • 1283263 - mestre nginx
    • 1283282 - worker 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
    

    Também é possível executar netstat usando ip netns, mas é necessário vincular manualmente o namespace de rede do processo porque o Docker não está fazendo o vínculo:

    # 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
    

Mitigação:

A mitigação de curto prazo identifica processos obsoletos usando o método descrito acima e os encerra por meio do comando kill [PID].

A mitigação de longo prazo consiste em identificar por que o Docker está falhando e corrigir esse problema. Entre as possíveis razões estão:

  • Processos zumbi se acumulando, esgotando assim os namespaces PID
  • Bug no Docker
  • Pressão de recurso/OOM

A seguir