Resolva problemas de conetividade no seu cluster


Esta página mostra como resolver problemas de conetividade no seu cluster do Google Kubernetes Engine (GKE).

Problemas de conetividade relacionados com a captura de pacotes de rede no GKE

Esta secção descreve como resolver problemas de conetividade relacionados com a captura de pacotes de rede, incluindo sintomas como tempos limite de ligação, erros de ligação recusada ou comportamento inesperado da aplicação. Estes problemas de conetividade podem ocorrer ao nível do nó ou ao nível do pod.

Os problemas de conetividade na rede do cluster enquadram-se frequentemente nas seguintes categorias:

  • Pods não acessíveis: um Pod pode não estar acessível a partir do interior ou exterior do cluster devido a configurações incorretas da rede.
  • Interrupções do serviço: um serviço pode estar a sofrer interrupções ou atrasos.
  • Problemas de comunicação entre pods: os pods podem não conseguir comunicar entre si de forma eficaz.

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

  • Configurações incorretas da rede: políticas de rede, regras de firewall ou tabelas de encaminhamento incorretas.
  • Erros da aplicação: erros no código da aplicação que afetam as interações de rede.
  • Problemas de infraestrutura: congestão da rede, falhas de hardware ou limitações de recursos.

A secção seguinte mostra como resolver o problema nos nós ou nos pods problemáticos.

  1. Identifique o nó no qual o pod problemático está a ser executado através do seguinte comando:

    kubectl get pods POD_NAME -o=wide -n NAMESPACE
    

    Substitua o seguinte:

    • POD_NAME com o nome do agrupamento.
    • NAMESPACE com o espaço de nomes do Kubernetes.
  2. Estabeleça ligação ao nó:

    gcloud compute ssh NODE_NAME \
        --zone=ZONE
    

    Substitua o seguinte:

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

    ip route | grep POD_IP
    

    Substitua POD_IP pelo endereço IP do pod.

  4. Execute os comandos da caixa de ferramentas.

toolbox comandos

toolbox é um utilitário que fornece um ambiente em contentores nos seus nós do GKE para depuração e resolução de problemas. Esta secção descreve como instalar o utilitário toolbox e usá-lo para resolver problemas do nó.

  1. Com o nó ligado, inicie a ferramenta toolbox:

    toolbox
    

    Esta ação transfere os ficheiros que facilitam a utilidade toolbox.

  2. Na linha de comandos de toolbox root, instale o tcpdump:

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

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

      Se tiver um cluster privado sem o Cloud NAT, não pode instalar o tcpdump com o apt. Em alternativa, transfira os ficheiros libpcap e tcpdump de lançamento do repositório oficial e copie os ficheiros para a VM através do gcloud compute scp ou do gcloud storage cp. Em seguida, instale as bibliotecas manualmente através dos seguintes passos:

      # Copy the downloaded packages to a staging area
      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/
      
      # Extract the archives
      tar -xvzf tcpdump-VERSION.tar.gz
      tar -xvzf libpcap-VERSION.tar.gz
      
      # Build and install libpcap (a dependency for tcpdump)
      cd libpcap-VERSION
      ./configure ; make ; make install
      
      # Build and install tcpdump
      cd ../tcpdump-VERSION
      ./configure ; make ; make install
      
      # Verify tcpdump installation
      tcpdump --version
      

      Substitua o seguinte:

      • USER_NAME: o seu nome de utilizador no sistema onde os ficheiros estão localizados.
      • VERSION: o número da 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 o seguinte:

    • PORT: nome do número de portabilidade.
    • CAPTURE_FILE_NAME: nome do ficheiro de captura.
  4. Pare a captura de pacotes e interrompa o tcpdump.

  5. Saia da caixa de ferramentas escrevendo exit.

  6. Liste o ficheiro de captura de pacotes e verifique o respetivo tamanho:

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

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

    Substitua o seguinte:

    • NODE_NAME: nome do seu nó.
    • CAPTURE_FILE_NAME: nome do ficheiro de captura.
    • ZONE: nome da sua zona.

Comandos alternativos

Também pode usar as seguintes formas para resolver problemas de conetividade nos Pods problemáticos:

Problemas de conetividade de rede do pod

Conforme mencionado na discussão sobre a vista geral da rede, é importante compreender como os pods estão ligados dos respetivos espaços de nomes de rede ao espaço de nomes raiz no nó para resolver problemas de forma eficaz. Para a discussão seguinte, salvo indicação em contrário, partimos do princípio de que o cluster usa o CNI nativo do GKE em vez do CNI do Calico. Ou seja, não foi aplicada nenhuma política de rede.

Os pods em determinados nós não têm disponibilidade

Se os pods em determinados nós não tiverem conetividade de rede, certifique-se de que a ponte Linux está ativa:

ip address show cbr0

Se a ponte Linux estiver inativa, ative-a:

sudo ip link set cbr0 up

Certifique-se de que o nó está a aprender os endereços MAC dos pods anexados a cbr0:

arp -an

Os pods em determinados nós têm conetividade mínima

Se os pods em determinados nós tiverem uma conetividade mínima, deve confirmar primeiro se existem pacotes perdidos executando tcpdump no contentor da caixa de ferramentas:

sudo toolbox bash

Instale a app tcpdump na caixa de ferramentas, se ainda não o tiver feito:

apt install -y tcpdump

Executar tcpdump contra cbr0:

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

Se parecer que os pacotes grandes estão a ser ignorados a jusante da ponte (por exemplo, a negociação TCP é concluída, mas não são recebidos SSL hellos), certifique-se de que a MTU para cada interface do pod Linux está corretamente definida para a MTU da rede da VPC do cluster.

ip address show cbr0

Quando são usadas sobreposições (por exemplo, Weave ou Flannel), esta MTU tem de ser ainda mais reduzida para acomodar a sobrecarga de encapsulamento na sobreposição.

MTU do GKE

A MTU selecionada para uma interface de pod depende da interface de rede do contentor (CNI) usada pelos nós do cluster e da definição de MTU da VPC subjacente. Para mais informações, consulte o artigo Pods.

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

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

Ativada através da utilização da funcionalidade --enable-network-policy.

Para ver detalhes, consulte o artigo Controle a comunicação entre Pods e serviços através de políticas de rede.

netd Herdado Ativada através de qualquer uma das seguintes opções:
GKE Dataplane V2 Herdado

Ativada através da utilização da funcionalidade --enable-dataplane-v2.

Para obter detalhes, consulte o artigo Usar o GKE Dataplane V2.

Falhas de ligação intermitentes

As ligações de e para os pods são encaminhadas por iptables. Os fluxos são monitorizados como entradas na tabela conntrack e, quando existem muitas cargas de trabalho por nó, o esgotamento da tabela conntrack pode manifestar-se como uma falha. Estes podem ser registados na consola série do nó, por exemplo:

nf_conntrack: table full, dropping packet

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

Também pode usar o NodeLocal DNSCache para reduzir as entradas de acompanhamento de ligações.

"bind: Address already in use " comunicado para um contentor

Não é possível iniciar um contentor num pod porque, de acordo com os registos do contentor, a porta à qual a aplicação está a tentar associar-se já está reservada. O contentor está num ciclo de falhas. 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, por vezes, um contentor em execução fica para trás e fica obsoleto. O processo continua a ser executado no espaço de nomes de rede atribuído ao pod e a detetar na respetiva porta. Uma vez que o Docker e o kubelet não têm informações sobre o contentor obsoleto, tentam iniciar um novo contentor com um novo processo, que não consegue estabelecer ligação na porta, uma vez que é adicionado ao espaço de nomes de rede já associado ao Pod.

Para diagnosticar este problema:

  1. 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. Obtenha o resultado dos seguintes comandos a partir do nó:

    docker ps -a
    ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]
    
  3. Verifique os processos em execução a partir deste pod. Uma vez que o UUID dos espaços de nomes cgroup contém o UUID do pod, pode usar o comando grep para o UUID do pod no resultado de ps. Procure também a linha anterior para ter os docker-containerd-shim processos com o ID do contentor no argumento também. Corte o resto da coluna cgroup para obter um resultado 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. Nesta lista, pode ver os IDs dos contentores, que também devem estar visíveis em docker ps.

    Neste caso:

    • docker-containerd-shim 276e173b0846e24b704d4 para pausar
    • docker-containerd-shim ab4c7762f5abf40951770 para sh com sono (sleep-ctr)
    • docker-containerd-shim 44e76e50e5ef4156fd5d3 para nginx (echoserver-ctr)
  5. Verifique os seguintes elementos no resultado 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
    

    Em casos normais, vê todos os IDs de contentores de ps apresentados em docker ps. Se não vir nenhum, significa que é um contentor obsoleto e, provavelmente, verá um processo secundário do docker-containerd-shim process a ouvir na porta TCP que está a comunicar que já está em utilização.

    Para validar esta situação, execute netstat no espaço de nomes de rede do contentor. Obtenha o pid de qualquer processo de contentor (por isso, NÃO docker-containerd-shim) para o pod.

    Do exemplo anterior:

    • 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
    

    Também pode executar netstat usando ip netns, mas tem de associar o espaço de nomes da rede do processo manualmente, uma vez que o Docker não está a fazer a associação:

    # 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 a curto prazo consiste em identificar processos desatualizados através do método descrito anteriormente e terminar os processos com o comando kill [PID].

A mitigação a longo prazo envolve identificar o motivo pelo qual o Docker está a falhar e corrigi-lo. Os motivos possíveis incluem:

  • Processos zombie a acumular-se, o que faz com que os espaços de nomes PID se esgotem
  • Erro no Docker
  • Pressão de recursos / OOM

O que se segue?