Solução de problemas

Saiba mais sobre as etapas de solução de problemas que poderão ser úteis se você encontrar problemas ao usar o Google Kubernetes Engine.

Como depurar recursos do Kubernetes

Se você tiver um problema relacionado ao cluster, consulte Como solucionar problemas de clusters (em inglês) na documentação do Kubernetes.

Se você está tendo um problema com o aplicativo, os pods ou o objeto controlador, consulte Como solucionar problemas de aplicativos (em inglês).

Comando kubectl não encontrado

Primeiro, instale o binário kubectl executando o seguinte comando:

sudo gcloud components update kubectl

Responda "sim" quando a modificação da variável de ambiente $PATH for solicitada no instalador. Quando essas variáveis são modificadas, você consegue usar os comandos kubectl sem digitar o caminho completo do arquivo.

Outra alternativa é adicionar a seguinte linha ao ~/.bashrc (ou ~/.bash_profile no macOS ou sempre que o shell armazenar variáveis de ambiente):

export PATH=$PATH:/usr/local/share/google/google-cloud-sdk/bin/

Por fim, execute o seguinte comando para carregar o arquivo atualizado do .bashrc (ou .bash_profile):

source ~/.bashrc

Os comandos kubectl retornam o erro "conexão recusada"

Defina o contexto do cluster com o seguinte comando:

gcloud container clusters get-credentials [CLUSTER_NAME]

Se não tiver certeza sobre o que inserir em CLUSTER_NAME, use o comando a seguir para listar os clusters:

gcloud container clusters list

Os comandos kubectl retornam o erro "falha ao negociar versão da API"

Verifique se kubectl tem credenciais de autenticação:

gcloud auth application-default login

Os comandos kubectl logs, attach, exec e port-forward ficam suspensos

Esses comandos dependem de o mestre do cluster conseguir acessar os nós no cluster. Porém, como o mestre não está na mesma rede do Compute Engine que os nós do cluster, dependemos dos túneis SSH para ativar a comunicação segura.

O GKE salva um arquivo de chave pública SSH nos metadados do projeto do Compute Engine. Todas as VMs do Compute Engine que usam as imagens fornecidas pelo Google verificam regularmente os metadados comuns do projeto e os metadados da instância em busca das chaves SSH para adicionar à lista de usuários autorizados da VM. Além disso, o GKE adiciona uma regra de firewall à rede do Compute Engine, o que permite o acesso SSH do endereço IP do mestre a cada nó no cluster.

Se algum dos comandos kubectl acima não for executado, é provável que o mestre não consiga abrir os túneis SSH com os nós. Verifique as possíveis causas:

  1. O cluster não tem nó algum.

    Se você reduziu o número de nós no cluster a zero, os túneis SSH não funcionam.

    Para corrigir esse problema, redimensione o cluster para ter pelo menos um nó.

  2. Os pods no cluster estão paralisados em um estado de encerramento e impedem a remoção dos nós que não existem mais do cluster.

    Esse é um problema que afeta somente o Kubernetes versão 1.1, mas ele pode ser causado pelo redimensionamento repetido do cluster.

    Para corrigi-lo, exclua os pods que estão no estado de encerramento há mais de alguns minutos. Os nós antigos são então removidos da API do mestre e substituídos pelos novos nós.

  3. As regras de firewall da rede não permitem acesso SSH ao mestre.

    Todas as redes do Compute Engine são criadas com uma regra de firewall denominada "default-allow-ssh" que permite acesso SSH de todos os endereços IP (o que certamente requer uma chave privada válida). O GKE também insere uma regra SSH para cada cluster do formulário gke-<cluster_name>-<random-characters>-ssh que permite especificamente o acesso SSH do IP mestre do cluster aos nós do cluster. Se não houver uma dessas regras, o mestre não poderá abrir os túneis SSH.

    Para corrigir isso, adicione novamente uma regra de firewall que permita acesso às VMs com a tag que está em todos os nós do cluster do endereço IP do mestre.

  4. A entrada de metadados comuns do projeto "ssh-keys" está cheia.

    Se a entrada de metadados do projeto denominada "ssh-keys" estiver próxima do limite de tamanho de 32 KiB, o GKE não poderá adicionar a própria chave SSH para permitir a abertura de túneis SSH. Veja os metadados do projeto executando gcloud compute project-info describe [--project=PROJECT] e, em seguida, verifique o comprimento da lista de ssh-keys.

    Para corrigir isso, exclua algumas chaves SSH que não são mais necessárias.

  5. Você definiu um campo de metadados com a chave “ssh-keys” nas VMs no cluster.

    O agente de nó nas VMs prefere as ssh-keys por instância a chaves SSH do projeto inteiro. Portanto, se você definiu quaisquer chaves SSH especificamente nos nós do cluster, os nós não respeitarão a chave SSH do mestre nos metadados do projeto. Para verificar isso, execute gcloud compute instances describe <VM-name> e procure um campo "ssh-keys" nos metadados.

    Para corrigir esse problema, exclua as chaves SSH por instância dos metadados da instância.

Esses recursos não são necessários para o funcionamento correto do cluster. Se você preferir manter a rede do cluster bloqueada contra qualquer acesso externo, saiba que recursos como esse não funcionarão.

Métricas do cluster não exibidas no Stackdriver

Verifique se você ativou a API do Stackdriver Monitoring e a API do Stackdriver Logging no projeto. Além disso, veja se o projeto aparece no Stackdriver Monitoring (páginas em inglês).

Se o problema continuar, verifique estas possíveis causas:

  1. Verifique se o monitoramento está ativado no cluster.

    O monitoramento é ativado por padrão para clusters criados no Developers Console e na ferramenta de linha de comando gcloud, mas é possível verificar isso executando o seguinte comando ou clicando nos detalhes do cluster no Developers Console:

    gcloud container clusters describe cluster-name

    A saída da ferramenta de linha de comando gcloud deve declarar que "monitoringService" é "monitoring.googleapis.com", e o Cloud Monitoring deve ser ativado no Developers Console.

    Se o monitoramento não estiver ativado, execute o seguinte comando para ativá-lo:

    gcloud container clusters update cluster-name --monitoring-service=monitoring.googleapis.com
  2. Quanto tempo faz desde que o cluster foi criado ou que o monitoramento foi ativado?

    Pode levar até uma hora para as métricas do novo cluster começarem a aparecer no Stackdriver Monitoring.

  3. Há um heapster em execução no cluster, no namespace "kube-system"?

    Talvez esse pod não consiga programar cargas de trabalho porque o cluster pode estar com poucos recursos. Verifique se o heapster está em execução chamando kubectl get pods --namespace=kube-system e verificando pods com heapster no nome.

  4. O mestre do cluster pode se comunicar com os nós?

    O Stackdriver Monitoring depende disso. Verifique se esse é o caso executando kubectl logs [POD-NAME]. Se esse comando retornar um erro, os túneis SSH podem estar causando o problema. Consulte esta seção.

Se você está com algum problema relacionado ao agente do Stackdriver Logging, consulte a documentação de solução de problemas dele.

Para mais informações, consulte a documentação do Stackdriver.

Erro 404: recurso "não encontrado" ao chamar comandos gcloud container

Faça a autenticação novamente na ferramenta de linha de comando gcloud:

gcloud auth login

Erro 400/403: permissões de edição ausentes na conta

A conta de serviço padrão do Compute Engine ou a conta de serviço associada ao GKE foi excluída ou editada manualmente.

Quando você ativa a API do Compute Engine ou do Kubernetes Engine, uma conta de serviço é criada e recebe permissões de edição em seu projeto. Se, a qualquer momento, você editar as permissões, remover a conta totalmente ou desativar a API, a criação de cluster e toda a funcionalidade de gerenciamento falharão.

O nome da sua conta de serviço do Google Kubernetes Engine é:

service-[PROJECT_NUMBER]@container-engine-robot.iam.gserviceaccount.com

em que [PROJECT_NUMBER] é o número do projeto.

Para resolver o problema, você precisa reativar a API do Kubernetes Engine. Isso restaurará corretamente suas contas e permissões de serviço.

  1. Acesse a página APIs e serviços.
  2. Selecione o projeto.
  3. Clique em Ativar APIs e serviços.
  4. Procure pelo Kubernetes e selecione a API nos resultados da pesquisa.
  5. Clique em Ativar. Se você já tiver ativado a API, primeiro desative-a e, em seguida, reative-a. Pode levar alguns minutos para que a API e os serviços relacionados sejam ativados.

Outra alternativa é usar a ferramenta de linha de comando gcloud:

gcloud services enable container.googleapis.com

Como replicar as regras de firewall automáticas 1.8.x (e anteriores) no 1.9.x e posterior

Se seu cluster estiver executando o Kubernetes versão 1.9.x, as regras de firewall automáticas foram alteradas para não permitir cargas de trabalho em um cluster GKE para iniciar a comunicação com outras VMs do Compute Engine que estejam fora do cluster, mas na mesma rede.

Replique o comportamento automático de regras de firewall de um cluster 1.8.x (e anterior) executando as seguintes etapas:

Primeiro, encontre a rede do seu cluster:

gcloud container clusters describe [CLUSTER_NAME] --format=get"(network)"

Em seguida, consiga o CIDR IPv4 do cluster usado para os contêineres:

gcloud container clusters describe [CLUSTER_NAME] --format=get"(clusterIpv4Cidr)"

Por fim, crie uma regra de firewall para a rede (com o CIDR como o intervalo de origem) e permita todos os protocolos:

gcloud compute firewall-rules create "[CLUSTER_NAME]-to-all-vms-on-network" --network="[NETWORK]" --source-ranges="[CLUSTER_IPV4_CIDR]" --allow=tcp,udp,icmp,esp,ah,sctp

Restaurar conta de serviço padrão para seu projeto do GCP

A conta de serviço padrão do GKE, container-engine-robot, pode ser acidentalmente desassociada de um projeto. Agente de serviço do GKE é uma função do Cloud Identity and Access Management (Cloud IAM) que concede à conta de serviço as permissões para gerenciar recursos de cluster. Se você remover essa vinculação de papel da conta de serviço, a conta de serviço padrão ficará desvinculada do projeto, o que poderá impedir a implantação de aplicativos e a execução de outras operações de cluster.

Verifique se a conta de serviço foi removida do projeto executando gcloud projects get-iam-policy [PROJECT_ID] ou visitando a página Cloud IAM & admin no Console do Google Cloud. Se o comando ou o painel não exibe container-engine-robot entre as contas de serviço, a conta de serviço está desassociada.

Se você removeu a vinculação de papel do Agente de serviço do GKE, execute os seguintes comandos para restaurar a vinculação de papel:

PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format "value(projectNumber)")
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
  --member "serviceAccount:service-${PROJECT_NUMBER}@container-engine-robot.iam.gserviceaccount.com" \
  --role roles/container.serviceAgent

Para confirmar se a vinculação de papel foi concedida:

gcloud projects get-iam-policy $PROJECT_ID

Se o nome da conta de serviço estiver com a função container.serviceAgent, a vinculação de papel foi concedida. Por exemplo:

- members:
  - serviceAccount:service-1234567890@container-engine-robot.iam.gserviceaccount.com
  role: roles/container.serviceAgent

A chave KMS está desativada.

A conta de serviço padrão do GKE não pode usar uma chave KMS desativada para criptografia de secrets no nível do aplicativo.

Para reativar uma chave desativada, consulte Ativar uma versão de chave desativada.

Solução de problemas com cargas de trabalho implantadas

O GKE retornará um erro se houver problemas com os pods de uma carga de trabalho. Verifique o status de um pod usando a ferramenta de linha de comando kubectl ou o Console do Google Cloud.

kubectl

Para ver todos os pods em execução no cluster, execute o seguinte comando:

kubectl get pods

Saída:

NAME            READY   STATUS              RESTARTS    AGE
[POD_NAME]      0/1     CrashLoopBackOff    23          8d

Para ver mais informações detalhadas sobre um pod específico:

kubectl describe pod [POD_NAME]

Console

Siga as etapas abaixo:

  1. Acesse o painel de cargas de trabalho do GKE no Console do Cloud.

    Acesse o painel de cargas de trabalho do GKE

  2. Selecione a carga de trabalho desejada. A guia Visão geral exibe o status da carga de trabalho.

  3. Na seção Gerenciar pods, clique na mensagem de status de erro.

Veja nas seções a seguir alguns erros comuns retornados por cargas de trabalho e como resolvê-los.

CrashLoopBackOff

CrashLoopBackOff indica que um contêiner está repetidamente falhando após a reinicialização. Um contêiner pode falhar por vários motivos. Verificar os registros de um pod ajuda na solução de problemas da causa raiz.

Por padrão, os contêineres com falha são reiniciados com um atraso exponencial limitado a cinco minutos. Altere esse comportamento configurando o campo restartPolicy Especificação do pod de implantação em spec: restartPolicy. O valor padrão do campo é Always.

Descubra o motivo da falha no contêiner do pod usando a ferramenta de linha de comando kubectl ou o Console do Cloud.

kubectl

Para ver todos os pods em execução no cluster, execute o seguinte comando:

kubectl get pods

Procure o pod com o erro CrashLoopBackOff.

Para ver os registros do pod, execute:

kubectl logs [POD_NAME]

em que [POD_NAME] é o nome do pod problemático.

Também é possível transferir a sinalização -p para ter os registros da instância anterior do contêiner do pod, se houver.

Console

Siga as etapas abaixo:

  1. Acesse o painel de cargas de trabalho do GKE no Console do Cloud.

    Acesse o painel de cargas de trabalho do GKE

  2. Selecione a carga de trabalho desejada. A guia Visão geral exibe o status da carga de trabalho.

  3. Na seção Gerenciar Pods, clique no Pod problemático.

  4. No menu do pod, clique na guia Registros.

Verificar o "código de saída" do contêiner com falha

Encontre-o na saída de kubectl describe pod [POD_NAME] no campo containers: [CONTAINER_NAME]: last state: exit code.

  • Se o código de saída for 1, o contêiner falhou porque o aplicativo falhou.
  • Se o código de saída for 0, verifique por quanto tempo seu aplicativo estava sendo executado. Os contêineres saem quando o processo principal do aplicativo é encerrado. Se seu aplicativo concluir a execução muito rapidamente, o contêiner poderá continuar sendo reiniciado.

Conectar-se a um contêiner em execução

Abra um shell para o pod:

kubectl exec -it [POD_NAME] -- /bin/bash

Se houver mais de um contêiner no pod, adicione -c [CONTAINER_NAME].

Agora, é possível executar comandos bash no contêiner: teste a rede ou verifique se você tem acesso a arquivos ou bancos de dados usados pelo aplicativo.

ImagePullBackOff e ErrImagePull

ImagePullBackOff e ErrImagePull indicam que a imagem usada por um contêiner não pode ser carregada do registro de imagem.

Verifique esse problema usando o Console do Cloud ou a ferramenta de linha de comando kubectl.

kubectl

Para mais informações sobre a imagem do contêiner do pod, execute o seguinte comando:

kubectl describe pod [POD_NAME]

Console

Siga as etapas abaixo:

  1. Acesse o painel de cargas de trabalho do GKE no Console do Cloud.

    Acesse o painel de cargas de trabalho do GKE

  2. Selecione a carga de trabalho desejada. A guia Visão geral exibe o status da carga de trabalho.

  3. Na seção Gerenciar Pods, clique no Pod problemático.

  4. No menu do Pod, clique na guia Eventos.

Se a imagem não for encontrada

Se sua imagem não for encontrada:

  1. Verifique se o nome da imagem está correto.
  2. Verifique se a tag da imagem está correta. (Tente :latest ou nenhuma tag para extrair a imagem mais recente).
  3. Se a imagem tiver um caminho de registro completo, verifique se ela existe no registro do Docker que você está usando. Se você fornecer apenas o nome da imagem, verifique o registro do Docker Hub.
  4. Tente extrair a imagem do docker manualmente:

    • SSH no nó:
      Por exemplo, para SSH em example-instance na zona us-central1-a:

      gcloud compute ssh example-instance --zone us-central1-a
    • Execute docker pull [IMAGE_NAME].
      Se essa opção funcionar, você provavelmente precisará especificar ImagePullSecrets em um pod. Os pods só podem referenciar segredos de extração de imagem nos próprios namespaces. Portanto, esse processo precisa ser feito uma vez por namespace.

Se você encontrar um erro de "permissão negada" ou "sem acesso para extrair", verifique se você está conectado e/ou tem acesso à imagem.

Se você estiver usando um registro particular, isso pode exigir chaves para ler imagens.

Se a imagem estiver hospedada no Google Container Registry, a conta de serviço associada ao seu pool de nós precisa de acesso de leitura ao intervalo do Google Cloud Storage que contém a imagem. Consulte a documentação do Google Container Registry para mais detalhes.

Pod não programável

PodUnschedulable indica que seu pod não pode ser programado devido a recursos insuficientes ou a algum erro de configuração.

Recursos insuficientes

Talvez você encontre um erro indicando falta de CPU, memória ou outro recurso. Por exemplo: "não há nós disponíveis que correspondam a todos os predicados: CPU insuficiente (2)", o que indica que em dois nós não há CPU suficiente disponível para atender às solicitações de um pod.

A solicitação de CPU padrão é 100m ou 10% de uma CPU (ou um núcleo). Se quiser solicitar mais ou menos recursos, especifique o valor na especificação do pod em spec: containers: resources: requests

MatchNodeSelector

MatchNodeSelector indica que não há nós que correspondam ao seletor de rótulos do pod.

Para verificar isso, confira os rótulos especificados no campo nodeSelector da especificação do pod, em spec: nodeSelector.

Para ver como os nós no cluster são rotulados, execute o seguinte comando:

kubectl get nodes --show-labels

Para anexar um rótulo a um nó:

kubectl label nodes [NODE_NAME] [LABEL_KEY]=[LABEL_VALUE]

Para mais informações, consulte Como atribuir pods a nós.

PodToleratesNodeTaints

PodToleratesNodeTaints indica que o pod não pode ser programado para qualquer nó porque nenhum deles atualmente tolera o taint do nó.

Para verificar se esse é o caso, execute o seguinte comando:

kubectl describe nodes [NODE_NAME]

Na saída, verifique o campo Taints, que lista pares de valor-chave e efeitos de programação.

Se o efeito listado for NoSchedule, nenhum pod poderá ser programado nesse nó, a menos que tenha uma tolerância correspondente.

Uma maneira de resolver esse problema é remover o taint. Por exemplo, para remover um taint do NoSchedule:

kubectl taint nodes [NODE_NAME] key:NoSchedule-

PodFitsHostPorts

PodFitsHostPorts indica que uma porta que um nó está tentando usar já está em uso.

Para resolver esse problema, verifique o valor hostPort da especificação do pod em spec: containers: ports: hostPort. Pode ser necessário alterar esse valor para outra porta.

Não há disponibilidade mínima

Se um nó tiver recursos adequados, mas ainda exibir a mensagem Does not have minimum availability, verifique o status do pod. Se o status for SchedulingDisabled ou Cordoned, o nó não poderá programar novos pods. Para verificar o status de um nó:

kubectl

Para receber o status dos seus nós, execute o seguinte comando:

kubectl get nodes

Para ativar a programação no nó, execute:

kubectl uncordon [NODE_NAME]

Console

Siga as etapas abaixo:

  1. Acesse o painel de cargas de trabalho do GKE no Console do Cloud.

    Acessar o painel do GKE Clusters

  2. Selecione o cluster desejado. A guia Nós exibe os nós e o status deles.

Para ativar a programação no nó, execute as seguintes etapas:

  1. Na lista, clique no nó desejado.

  2. Em Detalhes do nó, clique no botão Não programável.

Problemas de conectividade

Conforme mencionado em 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 não estiver, 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 em relação a cbr0:

tcpdump -ni cbr0 host [HOSTNAME] and port [PORT_NUMBER] and [tcp|udp|icmp]

Caso pareça que grandes pacotes estão sendo descartados da ponte (por exemplo, o handshake TCP é completado, mas nenhum SSL é recebido), assegure-se de que a MTU de ponte do Linux esteja configurada corretamente para 1460 ou inferior:

ip address show cbr0

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

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

Para evitar isso tudo, use um cluster nativo de VPC sem NAT.

"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 Stackdriver 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, você precisa do UUID do pod, 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

Também é possível receber os seguintes comandos do nó:

  • docker ps -a
  • ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]

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 também na linha anterior, assim poderá ter os processos docker-containerd-shim com o código 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

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)

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   k8s.gcr.io/pause-amd64:3.1

Nos casos normais, você vê todos os códigos dos contêineres de ps aparecendo em docker ps. Se houver algum que não apareça, é um contêiner obsoleto, e provavelmente você verá um processo filho do docker-containerd-shim process escutando a porta TCP que está relatando como já 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.

Do exemplo acima:

  • 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 pelo método descrito acima e os elimina usando kill [PID].

Mitigação de longo prazo consiste em identificar por que o Docker está falhando e corrigir isso. 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