Solução de problemas


Saiba mais sobre as etapas de solução de problemas que podem ser úteis se você tiver dúvidas ao usar o Google Kubernetes Engine (GKE).

Se precisar de mais ajuda, entre em contato com o Cloud Customer Care.

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

Se você estiver com problemas relacionados à conectividade entre as VMs do Compute Engine que estão na mesma rede de nuvem privada virtual (VPC) ou em duas redes VPC conectadas com o peering de rede VPC, consulte Como solucionar problemas conectividade entre instâncias de máquinas virtuais (VM) com endereços IP internos.

Se você estiver enfrentando perda de pacotes ao enviar tráfego de um cluster para um endereço IP externo usando o Cloud NAT, clusters nativos de VPC ou Agente de mascaramento de IP, consulte Como solucionar problemas de perda de pacotes do Cloud NAT em um cluster do GKE.

Solução de problemas com o comando kubectl

Comando kubectl não encontrado

  1. Instale o kubectl binário executando o seguinte comando:

    gcloud components update kubectl
    
  2. 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 (~/.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/
    
  3. Execute o seguinte comando para carregar seu arquivo .bashrc (ou .bash_profile) atualizado:

    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 você não tiver certeza sobre o que inserir em CLUSTER_NAME, use o comando a seguir para listar os clusters:

gcloud container clusters list

O comando kubectl expira

Depois de criar um cluster, a tentativa de executar o comando kubectl no cluster retorna um erro, como Unable to connect to the server: dial tcp IP_ADDRESS: connect: connection timed out ou Unable to connect to the server: dial tcp IP_ADDRESS: i/o timeout.

Isso pode ocorrer quando kubectl não consegue se comunicar com o plano de controle do cluster.

Para resolver esse problema, verifique o contexto em que o cluster está definido:

  1. Acesse $HOME/.kube/config ou execute o comando kubectl config view para verificar se o arquivo de configuração contém o contexto do cluster e o endereço IP externo do plano de controle.

  2. Defina as credenciais do cluster:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=COMPUTE_LOCATION \
        --project=PROJECT_ID
    

    Substitua:

    • CLUSTER_NAME: o nome do cluster.
    • COMPUTE_LOCATION: o local do Compute Engine.
    • PROJECT_ID: ID do projeto em que o cluster do GKE foi criado.
  3. Se o cluster for um cluster particular do GKE, verifique se o IP de saída da máquina de onde você está tentando se conectar está incluído na lista de redes autorizadas atuais. É possível encontrar suas redes autorizadas no console ou executando o seguinte comando:

    gcloud container clusters describe CLUSTER_NAME \
        --location=COMPUTE_LOCATION \
        --project=PROJECT_ID \
        --format "flattened(masterAuthorizedNetworksConfig.cidrBlocks[])"
    

Se o IP de saída da máquina não estiver incluído na lista de redes autorizadas na saída do comando acima, siga as etapas em Não é possível acessar o plano de controle de um cluster particular ou Como usar o Cloud Shell para acessar um cluster particular ao se conectar pelo Cloud Shell.

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

Verifique se o kubectl tem as credenciais de autenticação:

gcloud auth application-default login

Os comandos kubectl, logs, attach, exec e port-forward pararam de responder

Esses comandos dependem do plano de controle do cluster (mestre) ser capaz de se comunicar com os nós no cluster. No entanto, como o plano de controle não está na mesma rede do Compute Engine que os nós do cluster, usamos túneis SSH ou de proxy de conectividade para ativar 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 plano de controle a cada nó no cluster.

Se algum dos comandos kubectl acima não for executado, é provável que o servidor da API não consiga se comunicar com os nós. Verifique as seguintes causas possíveis:

  • O cluster não tem nenhum nó.

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

SSH

  • As regras de firewall da rede não permitem acesso SSH ao plano de controle.

    Todas as redes do Compute Engine são criadas com uma regra de firewall chamada default-allow-ssh, que permite o acesso SSH de todos os endereços IP, certamente com uma chave privada válida. O GKE também insere uma regra SSH em cada cluster público no formato gke-CLUSTER_NAME-RANDOM_CHARACTERS-ssh, que permite o acesso SSH especificamente do plano de controle do cluster aos nós do cluster. Se não houver nenhuma dessas regras, o plano de controle 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 plano de controle.

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

    Se a entrada de metadados do projeto chamada "ssh-keys" estiver próxima do limite máximo de tamanho, o GKE não poderá adicionar a própria chave SSH para ativá-la e abrir túneis SSH. Veja os metadados do seu projeto executando o seguinte comando:

    gcloud compute project-info describe [--project=PROJECT_ID]
    

    Em seguida, verifique o tamanho da lista de ssh-keys.

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

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

    O agente de nó nas VMs prefere as chaves SSH por instância do que do projeto inteiro. Portanto, se você definiu essas chaves especificamente nos nós do cluster, a chave SSH do plano de controle nos metadados do projeto não será usada pelos nós. 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.

Proxy Konnectivity

  • Para determinar se o cluster usa o proxy Konnectivity, verifique a seguinte implantação do sistema:

    kubectl get deployments konnectivity-agent --namespace kube-system
    
  • As regras de firewall da rede não permitem o acesso do agente Konnectivity ao plano de controle.

    Na criação do cluster, os pods do agente Konnectivity estabelecem e mantêm uma conexão com o plano de controle na porta 8132. Quando um dos comandos kubectl é executado, o servidor da API usa essa conexão para se comunicar com o cluster.

    Se as regras de firewall da rede tiverem regras de negação de saída, elas poderão impedir a conexão do agente. É preciso permitir o tráfego de saída para o plano de controle do cluster na porta 8132. (Para comparação, o servidor da API usa 443).

  • A política de rede do cluster bloqueia a entrada do namespace kube-system para o namespace workload. Para encontrar as políticas de rede no namespace afetado, execute o seguinte comando:

    kubectl get networkpolicy --namespace AFFECTED_NAMESPACE
    

    Para resolver o problema, adicione o seguinte ao campo spec.ingress das políticas de rede:

    - from:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: kube-system
        podSelector:
          matchLabels:
            k8s-app: konnectivity-agent
    

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.

Como solucionar problemas de erro 4xx

Erros de autenticação e autorização ao se conectar a clusters do GKE

Esse problema pode ocorrer quando você tenta executar um comando kubectl no cluster do GKE em um ambiente local. O comando falha e exibe uma mensagem de erro, geralmente com o código de status HTTP 401 (não autorizado).

A causa desse problema pode ser uma das seguintes:

  • O plug-in de autenticação gke-gcloud-auth-plugin não está instalado ou configurado corretamente.
  • Você não tem as permissões para se conectar ao servidor da API do cluster e executar comandos kubectl.

Para diagnosticar a causa, faça o seguinte:

Conecte-se ao cluster usando curl

O uso de curl ignora a CLI kubectl e o plug-in gke-gcloud-auth-plugin.

  1. Defina as variáveis de ambiente:

    APISERVER=https://$(gcloud container clusters describe CLUSTER_NAME --location=COMPUTE_LOCATION --format "value(endpoint)")
    TOKEN=$(gcloud auth print-access-token)
    
  2. Verifique se o token de acesso é válido:

    curl https://oauth2.googleapis.com/tokeninfo?access_token=$TOKEN
    
  3. Verifique se é possível se conectar ao endpoint principal da API no servidor da API:

    gcloud container clusters describe CLUSTER_NAME --location=COMPUTE_LOCATION --format "value(masterAuth.clusterCaCertificate)" | base64 -d > /tmp/ca.crt
    curl -s -X GET "${APISERVER}/api/v1/namespaces" --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt
    

Se o comando curl falhar com uma saída semelhante à seguinte, verifique se você tem as permissões corretas para acessar o cluster:

{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}

Se o comando curl for bem-sucedido, verifique se o plug-in é a causa.

Configurar o plug-in no kubeconfig

As etapas a seguir configuram seu ambiente local para ignorar o binário gke-gcloud-auth-plugin ao autenticar no cluster. Nos clientes do Kubernetes com a versão 1.25 e mais recentes, o binário gke-gcloud-auth-plugin é obrigatório. Portanto, use estas etapas se quiser acessar o cluster sem precisar do plug-in.

  1. Instale a CLI kubectl versão 1.24 usando curl:

    curl -LO https://dl.k8s.io/release/v1.24.0/bin/linux/amd64/kubectl
    

    É possível usar qualquer CLI kubectl versão 1.24 ou anterior.

  2. Abra o arquivo de script de inicialização do shell, como .bashrc para o shell Bash, em um editor de texto:

    vi ~/.bashrc
    
  3. Adicione a seguinte linha ao arquivo e salve-o:

    export USE_GKE_GCLOUD_AUTH_PLUGIN=False
    
  4. Execute o script de inicialização:

    source ~/.bashrc
    
  5. Receba credenciais para o cluster, que configura o arquivo .kube/config:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=COMPUTE_LOCATION
    

    Substitua:

  6. Execute um comando kubectl:

    kubectl cluster-info
    

Se você receber um erro 401 ou um erro de autorização semelhante, verifique se tem as permissões corretas para executar a operação.

Erro 400: o pool de nós requer recriação

O problema a seguir ocorre quando você tenta executar uma ação que recria o plano de controle e os nós, por exemplo, quando você conclui uma rotação de credenciais em andamento.

A operação falha porque o GKE não recriou um ou mais pools de nós no cluster. No back-end, os pools de nós são marcados para recriação, mas a operação de recriação real pode levar algum tempo para começar.

A mensagem de erro é semelhante a esta:

ERROR: (gcloud.container.clusters.update) ResponseError: code=400, message=Node pool "test-pool-1" requires recreation.

Para resolver esse problema, faça uma das seguintes ações:

  • Espere a recriação acontecer. Isso pode levar horas, dias ou semanas, dependendo de fatores como janelas de manutenção e exclusões atuais.
  • Inicie manualmente uma recriação dos pools de nós afetados iniciando um upgrade para a mesma versão do plano de controle. Para iniciar uma recriação, execute o seguinte comando:

    gcloud container clusters upgrade CLUSTER_NAME \
        --node-pool=POOL_NAME
    

    Quando o upgrade for concluído, tente a operação novamente.

Erro 403: permissões insuficientes

O erro a seguir ocorre quando você tenta se conectar a um cluster do GKE usando gcloud container clusters get-credentials, mas a conta não tem permissão para acessar o servidor da API Kubernetes.

ERROR: (gcloud.container.clusters.get-credentials) ResponseError: code=403, message=Required "container.clusters.get" permission(s) for "projects/<your-project>/locations/<region>/clusters/<your-cluster>".

Para resolver esse problema, faça o seguinte:

  1. Identifique a conta com problema de acesso:

    gcloud auth list
    
  2. Conceda o acesso necessário à conta seguindo as instruções em Como autenticar no servidor da API Kubernetes.

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

Faça a autenticação novamente na Google Cloud CLI:

gcloud auth login

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

Sua conta de serviço padrão do Compute Engine, o Agente de serviço de APIs do Google ou a conta de serviço associada ao GKE foi excluída. ou editados manualmente.

Quando você ativa a API Compute Engine ou Kubernetes Engine, o Google Cloud cria as seguintes contas de serviço e agentes:

  • Conta de serviço padrão do Compute Engine com permissões para edição no projeto.
  • O Agente de serviço de APIs do Google com permissões para edição no projeto.
  • Conta de serviço do Google Kubernetes Engine com o papel de Agente de serviço do Kubernetes Engine no projeto.

Se você editar essas permissões, remova as vinculações de papéis do projeto, remova completamente a conta de serviço ou desative a API, a criação de clusters e toda a funcionalidade de gerenciamento falharão.

O nome da sua conta de serviço do Google Kubernetes Engine é da maneira vista a seguir, em que PROJECT_NUMBER é o número do projeto:

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

O comando a seguir pode ser usado para verificar se a conta de serviço do Google Kubernetes Engine tem o papel Agente de serviço do Kubernetes Engine atribuído no projeto:

gcloud projects get-iam-policy PROJECT_ID

Substitua PROJECT_ID pela ID do seu projeto.

Para resolver o problema, caso você tenha removido o papel do Agente de serviço do Kubernetes Engine da sua conta de serviço do Google Kubernetes Engine, adicione-o novamente. Caso contrário, você precisará reativar a API do Kubernetes Engine, que vai restaurar corretamente suas contas de serviço e permissões.

Console

  1. Acesse a página APIs e serviços no Console do Google Cloud.

    Acessar 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 já tiver ativado a API, você precisa primeiro desativá-la e, em seguida, reativá-la. Pode levar alguns minutos para que a API e os serviços relacionados sejam ativados.

gcloud

Execute o seguinte comando na CLI gcloud para adicionar novamente a conta de serviço:

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

Solução de problemas com a criação de clusters do GKE

Erro Condition_NOT_MET: restrição constraints/compute.vmExternalIpAccess violada

Você tem a restrição da política da organização constraints/compute.vmExternalIpAccess configurada como Deny All ou para restringir IPs externos a instâncias de VM específicas no nível da organização, da pasta ou do projeto em que está tentando criar um cluster público do GKE.

Quando você cria clusters públicos do GKE, as VMs subjacentes do Compute Engine, que compõem os nós de trabalho desse cluster, têm endereços IP externos atribuídos. Se você configurar a restrição constraints/compute.vmExternalIpAccess da política da organização para Deny All ou restringir IPs externos a instâncias de VM específicas, a política vai impedir que os nós de trabalho do GKE recebam endereços IP externos, o que resulta na falha na criação do cluster.

Para encontrar os registros da operação de criação de cluster, confira os registros de auditoria das operações de cluster do GKE usando o Explorador de registros com uma consulta de pesquisa semelhante a esta:

resource.type="gke_cluster"
logName="projects/test-last-gke-sa/logs/cloudaudit.googleapis.com%2Factivity"
protoPayload.methodName="google.container.v1beta1.ClusterManager.CreateCluster"
resource.labels.cluster_name="CLUSTER_NAME"
resource.labels.project_id="PROJECT_ID"

Para resolver esse problema, verifique se a política efetiva para a restrição constraints/compute.vmExternalIpAccess é Allow All no projeto em que você está tentando criar um cluster público do GKE. Consulte Como restringir endereços IP externos a instâncias de VM específicas para saber como trabalhar com essa restrição. Depois de definir a restrição como Allow All, exclua o cluster com falha e crie um novo. Isso é necessário porque não é possível reparar o cluster com falha.

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 mais informações sobre um pod específico, execute o seguinte comando:

kubectl describe pod POD_NAME

Substitua POD_NAME pelo nome do pod que você quer.

Console

Siga as etapas abaixo:

  1. Acesse a página Cargas de trabalho no console do Google Cloud.

    Acesse "Cargas de trabalho"

  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.

É possível resolver erros CrashLoopBackOff usando o console do Google Cloud:

  1. Acesse o manual interativo de pods com loop de falhas:

    Acessar o manual

  2. Em Cluster, insira o nome do cluster que você quer solucionar.

  3. Em Namespace, insira o namespace que você quer solucionar.

  4. (Opcional) Crie um alerta para receber notificações sobre futuros erros do CrashLoopBackOff:

    1. Na seção Dicas de mitigação futura, selecione Criar um alerta.

Inspecionar registros

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 receber os registros do pod, execute o seguinte comando:

kubectl logs POD_NAME

Substitua POD_NAME pelo nome do pod problemático.

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

Console

Siga as etapas abaixo:

  1. Acesse a página Cargas de trabalho no console do Google Cloud.

    Acesse "Cargas de trabalho"

  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

Para encontrar o código de saída, execute as seguintes tarefas:

  1. Execute este comando:

    kubectl describe pod POD_NAME
    

    Substitua POD_NAME pelo nome do pod.

  2. Revise o valor 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 rápido demais, o contêiner pode continuar reiniciando.

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 Google 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 a página Cargas de trabalho no console do Google Cloud.

    Acesse "Cargas de trabalho"

  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:

    • Use SSH para acessar o nó:

      Por exemplo, para se conectar a uma VM por SSH:

      gcloud compute ssh VM_NAME --zone=ZONE_NAME
      

      Substitua:

    • Execute docker-credential-gcr configure-docker. Esse comando gera um arquivo de configuração em /home/[USER]/.docker/config.json. Verifique se esse arquivo inclui o registro da imagem no campo credHelpers. Por exemplo, o arquivo a seguir inclui informações de autenticação para imagens hospedadas em asia.gcr.io, eu.gcr.io, gcr.io, marketplace.gcr.io e us.gcr.io:

      {
        "auths": {},
        "credHelpers": {
          "asia.gcr.io": "gcr",
          "eu.gcr.io": "gcr",
          "gcr.io": "gcr",
          "marketplace.gcr.io": "gcr",
          "us.gcr.io": "gcr"
        }
      }
      
    • 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.

Erro de permissão negada

Se você encontrar um erro de "permissão negada" ou "sem acesso para extrair", verifique se você está conectado e/ou tem acesso à imagem. Tente um dos métodos a seguir, dependendo do registro em que você hospeda as imagens.

Artifact Registry

Se a imagem estiver no Artifact Registry, a conta de serviço do pool de nós precisará de acesso de leitura ao repositório que contém a imagem.

Conceda o papel artifactregistry.reader à conta de serviço.

gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
    --location=REPOSITORY_LOCATION \
    --member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
    --role="roles/artifactregistry.reader"

Substitua:

  • REPOSITORY_NAME: o nome do repositório do Artifact Registry
  • REPOSITORY_LOCATION: a região do repositório do Artifact Registry
  • SERVICE_ACCOUNT_EMAIL: o endereço de e-mail da conta de serviço do IAM associada ao pool de nós.

Container Registry

Se a imagem estiver no Container Registry, a conta de serviço do pool de nós precisará de acesso de leitura ao bucket do Cloud Storage que contém a imagem.

Conceda o papel roles/storage.objectViewer à conta de serviço para que ela possa ler o bucket:

gsutil iam ch \
serviceAccount:SERVICE_ACCOUNT_EMAIL:roles/storage.objectViewer \
  gs://BUCKET_NAME

Substitua:

  • SERVICE_ACCOUNT_EMAIL: o e-mail da conta de serviço associada ao pool de nós. Liste todas as contas de serviço no seu projeto usando gcloud iam service-accounts list.
  • BUCKET_NAME: o nome do bucket do Cloud Storage que contém as imagens. É possível listar todos os buckets no seu projeto usando gsutil ls.

Se o administrador de registro configurar repositórios gcr.io no Artifact Registry para armazenar imagens para o domínio gcr.io em vez do Container Registry, será preciso conceder acesso de leitura a Artifact Registry, em vez do Container Registry.

Registro particular

Se a imagem estiver em um registro particular, talvez você precise de chaves para acessar as imagens. Consulte Como usar registros privados para mais informações.

401 Não autorizado: não é possível extrair imagens do repositório particular do Container Registry

Um erro semelhante ao seguinte pode ocorrer ao extrair uma imagem de um repositório particular do Container Registry:

gcr.io/PROJECT_ID/IMAGE:TAG: rpc error: code = Unknown desc = failed to pull and
unpack image gcr.io/PROJECT_ID/IMAGE:TAG: failed to resolve reference
gcr.io/PROJECT_ID/IMAGE]:TAG: unexpected status code [manifests 1.0]: 401 Unauthorized

Warning  Failed     3m39s (x4 over 5m12s)  kubelet            Error: ErrImagePull
Warning  Failed     3m9s (x6 over 5m12s)   kubelet            Error: ImagePullBackOff
Normal   BackOff    2s (x18 over 5m12s)    kubelet            Back-off pulling image
  1. Identifique o nó que executa o pod:

    kubectl describe pod POD_NAME | grep "Node:"
    
  2. Verifique se o nó tem o escopo de armazenamento:

    gcloud compute instances describe NODE_NAME \
        --zone=COMPUTE_ZONE --format="flattened(serviceAccounts[].scopes)"
    

    O escopo de acesso do nó precisa conter pelo menos um dos itens a seguir:

    serviceAccounts[0].scopes[0]: https://www.googleapis.com/auth/devstorage.read_only
    serviceAccounts[0].scopes[0]: https://www.googleapis.com/auth/cloud-platform
    
  3. Recrie o pool de nós ao qual o nó pertence com escopo suficiente. Não é possível modificar os nós atuais. Você precisa recriar o nó com o escopo correto.

    • Recomendado: crie um novo pool de nós com o escopo gke-default:

      gcloud container node-pools create NODE_POOL_NAME \
          --cluster=CLUSTER_NAME \
          --zone=COMPUTE_ZONE \
          --scopes="gke-default"
      
    • Crie um novo pool de nós apenas com o escopo de armazenamento:

      gcloud container node-pools create NODE_POOL_NAME \
          --cluster=CLUSTER_NAME \
          --zone=COMPUTE_ZONE \
          --scopes="https://www.googleapis.com/auth/devstorage.read_only"
      

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.

Se você tiver configurado seu cluster do GKE para enviar métricas do servidor da API Kubernetes e do programador do Kubernetes ao Cloud Monitoring, veja mais informações sobre esses erros em métricas do programador e Métricas do servidor de API de dois minutos.

É possível resolver erros PodUnschedulable usando o console do Google Cloud:

  1. Acesse o manual interativo de pods não programáveis:

    Acessar o manual

  2. Em Cluster, insira o nome do cluster que você quer solucionar.

  3. Em Namespace, insira o namespace que você quer solucionar.

  4. (Opcional) Crie um alerta para receber notificações sobre futuros erros do PodUnschedulable:

    1. Na seção Dicas de mitigação futura, selecione Criar um alerta.

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.

Se as solicitações de recursos do pod excederem o de um único nó de qualquer pool de nós qualificado, o GKE não vai programar o pod e também não acionará o escalonamento vertical para adicionar um novo nó. Para que o GKE programe o pod, é necessário solicitar menos recursos para o pod ou criar um novo pool de nós com recursos suficientes.

Também é possível ativar o provisionamento automático de nós para que o GKE possa criar automaticamente pools de nós com nós em que os pods não programados podem ser executados.

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ó, execute o seguinte comando:

kubectl label nodes NODE_NAME LABEL_KEY=LABEL_VALUE

Substitua:

  • NODE_NAME: o nó que você quer;
  • LABEL_KEY: a chave do rótulo.
  • LABEL_VALUE: o valor do rótulo.

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 exista uma tolerância correspondente.

Uma maneira de resolver esse problema é remover o taint. Para remover um taint NoSchedule, execute o seguinte comando:

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. É possível verificar o status de um nó usando o console do Google Cloud ou a ferramenta de linha de comando kubectl.

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 a página Google Kubernetes Engine no console do Google Cloud.

    Acessar o Google Kubernetes Engine

  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.

O limite máximo de pods por nó foi atingido

Se o limite Máximo de pods por nó for atingido por todos os nós no cluster, os pods ficarão presos no estado não programável. Na guia Eventos do pod, é mostrada uma mensagem incluindo a frase Too many pods.

  1. Verifique a configuração de Maximum pods per node na guia "Nós" nos detalhes do cluster do GKE no console do Google Cloud.

  2. Consulte uma lista de nós:

    kubectl get nodes
    
  3. Para cada nó, verifique o número de pods em execução nele:

    kubectl get pods -o wide | grep NODE_NAME | wc -l
    
  4. Se o limite for atingido, adicione um novo pool de nós ou adicione mais nós ao atual.

Tamanho máximo do pool de nós atingido com o escalonador automático de clusters ativado

Se o pool de nós atingir seutamanho máximo De acordo com a configuração do escalonador automático de cluster, o GKE não aciona o escalonamento vertical do pod que seria programado com esse pool de nós. Se você quiser que o pod seja programado com esse pool de nós, altere a configuração do escalonador automático de clusters.

Tamanho máximo do pool de nós atingido com o escalonador automático de cluster desativado

Se o pool de nós atingir o número máximo de nós e o escalonador automático de cluster estiver desativado, o GKE não poderá programar o pod com o pool de nós. Aumente o tamanho do pool de nós ou ative o escalonador automático de clusters para que o GKE redimensione seu cluster automaticamente.

Desvincular PersistentVolumeClaims

Unbound PersistentVolumeClaims indica que o pod se refere a uma PersistentVolumeClaim não vinculada. Esse erro pode acontecer caso seu PersistentVolume falhe ao provisionar. É possível verificar se o provisionamento falhou procurando por erros nos eventos do seu PersistentVolumeClaim.

Para acessar eventos, execute o seguinte comando:

kubectl describe pvc STATEFULSET_NAME-PVC_NAME-0

Substitua:

  • STATEFULSET_NAME: o nome do objeto StatefulSet.
  • PVC_NAME: o nome do objeto PersistentVolumeClaim.

Isso também pode acontecer se houver um erro de configuração durante o pré-provisionamento manual de um PersistentVolume e sua vinculação a um PersistentVolumeClaim. É possível tentar pré-aprovisionar o volume novamente.

Cota insuficiente

Verifique se o projeto tem cota suficiente do Compute Engine para o GKE escalonar verticalmente o cluster. Se o GKE tentar adicionar um nó ao cluster para programar o pod e o escalonamento vertical exceder a cota disponível do projeto, você receberá a mensagem de erro scale.up.error.quota.exceeded.

Para saber mais, consulte Erros de ScaleUp.

APIs obsoletas

Verifique se você não está usando APIs descontinuadas que foram removidas com a versão secundária do seu cluster. Para saber mais, consulte Descontinuações do GKE.

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 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 Default
kubenet
(GKE versão 1.26.1 e posterior)
Herdado Default
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 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
    
  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.

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

Erro: "falha ao alocar para o intervalo 0: nenhum endereço IP no conjunto do intervalo"

Versão 1.18.17 do GKE e versões mais recentes corrigiram um problema em que eventos de falta de memória (OOM, na sigla em inglês) resultavam na remoção incorreta do pod se o pod fosse excluído antes de seus contêineres serem iniciados. Essa remoção incorreta pode resultar em pods órfãos que continuaram tendo endereços IP reservados do intervalo de nós alocado. Com o tempo, o GKE ficou sem endereços IP para alocar a novos pods por causa da criação de pods órfãos. Isso levou à mensagem de erro failed to allocate for range 0: no IP addresses in range set, porque o intervalo de nós alocado não tinha IPs disponíveis para atribuir a novos pods.

Para resolver esse problema, faça upgrade dos pools de nós e do cluster para a versão 1.18.17 ou posterior do GKE.

Para evitar esse problema e resolvê-lo em clusters com versões do GKE anteriores à 1.18.17, aumente seus limites de recursos para evitar eventos de OOM no futuro e, em seguida, recupere os endereços IP removendo os pods órfãos.

Também é possível ver os insights de uso do endereço IP do GKE.

Remova os pods órfãos dos nós afetados

Para remover os pods órfãos, esvazie o nó, faça upgrade do pool de nós ou mova os diretórios afetados.

Drenar o nó (recomendado)

  1. Restrinja o nó para evitar que novos pods sejam programados nele:

     kubectl cordon NODE
    

    Substitua NODE pelo nome do nó que você quer drenar.

  2. Drene o nó. O GKE reprograma automaticamente os pods gerenciados por implantações em outros nós. Use a sinalização --force para drenar pods órfãos que não tenham um recurso de gerenciamento.

     kubectl drain NODE --force
    
  3. Remova a restrição do nó para permitir que o GKE programe novos pods nele:

     kubectl uncordon NODE
    

Como mover os diretórios afetados

É possível identificar diretórios de pods órfãos em /var/lib/kubelet/pods e retirá-los do diretório principal para permitir que o GKE encerre os pods.

Solução de problemas com o encerramento de recursos

Namespace travado no estado Terminating

Os namespaces usam os finalizadores do Kubernetes para evitar a exclusão quando um ou mais recursos em um namespace ainda existem. Quando você exclui um namespace usando o comando kubectl delete, ele entra no estado Terminating até que o Kubernetes exclua os recursos dependentes e apague todos os finalizadores. O controlador de ciclo de vida do namespace primeiro lista todos os recursos no namespace que o GKE precisa excluir. Se o GKE não puder excluir um recurso dependente ou se o controlador de ciclo de vida do namespace não puder verificar se o namespace está vazio, o namespace permanecerá no estado Terminating até que você resolva o problema. de dois minutos.

Para resolver um namespace travado no estado Terminating, você precisa identificar e remover os componentes não íntegros que bloqueiam a exclusão. Tente uma das seguintes soluções.

Encontrar e remover serviços de API indisponíveis

  1. Liste os serviços de API indisponíveis:

    kubectl get apiservice | grep False
    
  2. Solucione os serviços que não respondem:

    kubectl describe apiservice API_SERVICE
    

    Substitua API_SERVICE pelo nome do serviço que não responde.

  3. Verifique se o namespace ainda está sendo encerrado:

    kubectl get ns | grep Terminating
    

Encontrar e remover recursos restantes

  1. Liste todos os recursos restantes no namespace de encerramento:

    kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get -n NAMESPACE
    

    Substitua NAMESPACE pelo nome do escopo que você quer excluir.

  2. Remova todos os recursos exibidos na saída.

  3. Verifique se o namespace ainda está sendo encerrado:

    kubectl get ns | grep Terminating
    

Forçar a exclusão do namespace

Remova os finalizadores que bloqueiam a exclusão do namespace para forçar o encerramento.

  1. Salve o seguinte manifesto como um arquivo YAML:

    kubectl get ns NAMESPACE -o yaml > ns-terminating.yml
    
  2. Abra o manifesto em um editor de texto e remova todos os valores do campo spec.finalizers:

    vi ns-terminating.yml
    
  3. Verifique se o campo finalizadores está vazio:

    cat ns-terminating.yml
    

    A saída será semelhante a esta:

    apiVersion: v1
    kind: Namespace
    metadata:
      annotations:
      name: NAMESPACE
    spec:
      finalizers:
    status:
      phase: Terminating
    
  4. Inicie um proxy HTTP para acessar a API Kubernetes:

    kubectl proxy
    
  5. Substitua o manifesto do namespace usando curl:

    curl -H "Content-Type: application/yaml" -X PUT --data-binary @ns-terminating.yml http://127.0.0.1:8001/api/v1/namespaces/NAMESPACE/finalize
    
  6. Verifique se o namespace ainda está sendo encerrado:

    kubectl get ns | grep Terminating
    

Como solucionar problemas da perda de pacotes do Cloud NAT de um cluster do GKE

As VMs de nós em clusters particulares do GKE nativos de VPC não têm endereços IP externos e não podem se conectar à Internet por conta própria. É possível usar o Cloud NAT para alocar as portas e os endereços IP externos que permitem que os clusters particulares façam conexões públicas.

Se uma VM do nó ficar sem sua alocação de portas externas e endereços IP do Cloud NAT, os pacotes serão descartados. Para evitar isso, reduza a taxa de pacotes de saída ou aumente a alocação de endereços IP e portas de origem do Cloud NAT disponíveis. As seções a seguir descrevem como diagnosticar e solucionar problemas de perda de pacotes do Cloud NAT no contexto de clusters particulares do GKE.

Como diagnosticar a perda de pacotes

Nesta seção, explicamos como registrar pacotes descartados usando o Cloud Logging e diagnosticar a causa deles usando o Cloud Monitoring.

Como registrar pacotes descartados

Registre pacotes descartados com a seguinte consulta no Cloud Logging:

resource.type="nat_gateway"
resource.labels.region=REGION
resource.labels.gateway_name=GATEWAY_NAME
jsonPayload.allocation_status="DROPPED"
  • REGION: o nome da região em que o cluster está.
  • GATEWAY_NAME: o nome do gateway do Cloud NAT.

Esse comando retorna uma lista de todos os pacotes descartados por um gateway do Cloud NAT, mas não identifica a causa.

Como monitorar causas de perda de pacotes

Para identificar as causas de pacotes descartados, consulte o Observador de métricas no Cloud Monitoring. Os pacotes são descartados por um destes três motivos:

Para identificar pacotes descartados devido a códigos de erro OUT_OF_RESOURCES ou ENDPOINT_ALLOCATION_FAILED, use a seguinte consulta:

fetch nat_gateway
  metric 'router.googleapis.com/nat/dropped_sent_packets_count'
  filter (resource.gateway_name == NAT_NAME)
  align rate(1m)
  every 1m
  group_by [metric.reason],
    [value_dropped_sent_packets_count_aggregate:
       aggregate(value.dropped_sent_packets_count)]

Para identificar pacotes descartados devido ao código de erro NAT_ALLOCATION_FAILED, use a seguinte consulta:

fetch nat_gateway
  metric 'router.googleapis.com/nat/nat_allocation_failed'
  group_by 1m,
    [value_nat_allocation_failed_count_true:
       count_true(value.nat_allocation_failed)]
  every 1m

Como solucionar problemas do Cloud NAT com mascaramento de IP do GKE

Se as consultas anteriores retornarem resultados vazios e os pods do GKE não conseguirem se comunicar com endereços IP externos, resolva o problema da configuração:

Configuração Solução de problemas
Cloud NAT configurado para ser aplicado somente ao intervalo de endereços IP primário da sub-rede. Quando o Cloud NAT é configurado apenas para o intervalo de endereços IP primário da sub-rede, os pacotes enviados do cluster para endereços IP externos precisam ter um endereço IP do nó de origem. Nesta configuração do Cloud NAT:
  • Os pods poderão enviar pacotes para endereços IP externos se esses destinos estiverem sujeitos a mascaramento de IP. Ao implantar o ip-masq-agent, verifique se a lista nonMasqueradeCIDRs não contém o endereço IP e a porta de destino. Os pacotes enviados para esses destinos são primeiro convertidos em endereços IP do nó de origem antes de serem processados pelo Cloud NAT.
  • Para permitir que os pods se conectem a todos os endereços IP externos com essa configuração do Cloud NAT, verifique se o ip-masq-agent é implantado e que o nonMasqueradeCIDRs contém apenas os intervalos de endereços IP do nó e do pod do cluster. Os pacotes enviados para destinos fora do cluster são primeiro convertidos em endereços IP do nó de origem antes de serem processados pelo Cloud NAT.
  • Para impedir que os pods enviem pacotes para alguns endereços IP externos, é necessário bloquear explicitamente esses endereços para que não sejam mascarados. Com o ip-masq-agent implantado, adicione os endereços IP externos que você quer bloquear à lista nonMasqueradeCIDRs. Os pacotes enviados para esses destinos saem do nó com as origens de endereços IP originais do pod. Os endereços IP do pod são provenientes de um intervalo de endereços IP secundário da sub-rede do cluster. Nessa configuração, o Cloud NAT não opera nesse intervalo secundário.
Cloud NAT configurado para ser aplicado apenas ao intervalo de endereços IP secundário da sub-rede usado para IPs de pod.

Quando o Cloud NAT é configurado apenas para o intervalo de endereços IP secundário da sub-rede usado pelos IPs de pod do cluster, os pacotes enviados do cluster para os endereços IP externos precisam ter um endereço IP do pod de origem. Nesta configuração do Cloud NAT:

  • Usar um agente de mascaramento de IP faz com que os pacotes percam o endereço IP do pod de origem quando processados pelo Cloud NAT. Para manter o endereço IP do pod de origem, especifique os intervalos de endereços IP de destino em uma lista nonMasqueradeCIDRs. Com o ip-masq-agent implantado, todos os pacotes enviados aos destinos na lista nonMasqueradeCIDRs mantêm os endereços IP do pod de origem antes de serem processados pelo Cloud NAT.
  • Para permitir que os pods se conectem a todos os endereços IP externos com essa configuração do Cloud NAT, verifique se ip-masq-agent foi implantado e se a lista nonMasqueradeCIDRs é a maior possível (0.0.0.0/0 especifica todos os destinos de endereços IP). Os pacotes enviados a todos os destinos retêm os endereços IP do pod de origem antes de serem processados pelo Cloud NAT.

Otimizações para evitar a perda de pacotes

Você pode interromper a perda de pacotes das seguintes formas:

Otimizar o aplicativo

Quando um aplicativo cria várias conexões de saída para a mesma porta e endereço IP de destino, ele pode consumir rapidamente todas as conexões que o Cloud NAT pode fazer para esse destino usando o número de endereços de origem NAT alocados e as tuplas de porta de origem. de dois minutos. Nesse cenário, a redução da taxa de pacotes de saída do aplicativo ajuda a diminuir a perda de pacotes.

Para detalhes sobre como o Cloud NAT usa endereços e portas de origem NAT para fazer conexões, incluindo os limites no número de conexões simultâneas com um destino, consulte Portas e conexões.

Reduzir a taxa de conexões de saída do aplicativo pode ajudar a reduzir a perda de pacotes. Você pode fazer isso reutilizando conexões abertas. Os métodos comuns de reutilização de conexões incluem o pooling, a multiplexação de conexões usando protocolos como HTTP/2 ou o estabelecimento de conexões persistentes reutilizadas para várias solicitações. Para mais informações, consulte Portas e conexões.

A versão do nó não é compatível com a versão do plano de controle

Verifique qual versão do Kubernetes o plano de controle do cluster está em execução e verifique qual versão do Kubernetes os pools de nós do cluster estão em execução. Se algum dos pools de nós do cluster tiver mais de duas versões secundárias mais antigas que o plano de controle, isso pode causar problemas com o cluster.

Periodicamente, a equipe do GKE realiza upgrades do plano de controle de cluster em seu nome. Os planos de controle são atualizados para versões estáveis mais recentes do Kubernetes. Por padrão, os nós de um cluster têm o upgrade automático ativado e é recomendável que ele não seja desativado.

Se o upgrade automático estiver desativado para os nós de um cluster e você não fizer o upgrade manual da versão do pool de nós para uma versão compatível com o plano de controle, seu controle. ele se tornará incompatível com os nós, já que o plano de controle é atualizado automaticamente ao longo do tempo. A incompatibilidade entre o plano de controle do cluster e os nós pode causar problemas inesperados.

A versão do Kubernetes e a política de suporte de diferença de versão garantem que os planos de controle sejam compatíveis com nós de até duas versões secundárias mais antigas que o plano de controle. Por exemplo, os planos de controle do Kubernetes 1.19 são compatíveis com os nós do Kubernetes 1.19, 1.18 e 1.17. Para resolver esse problema, faça upgrade manual da versão do pool de nós para uma que seja compatível com o plano de controle.

Se você acha que o processo de upgrade está causando a interrupção das cargas de trabalho em execução nos nós afetados, siga as etapas abaixo para migrar as cargas de trabalho para um novo pool de nós:

  1. Crie um novo pool de nós com uma versão compatível.
  2. Demarque os nós do pool de nós existente.
  3. Se quiser, atualize as cargas de trabalho em execução no pool de nós atual para adicionar um nodeSelector para o rótulo cloud.google.com/gke-nodepool:NEW_NODE_POOL_NAME, em que NEW_NODE_POOL_NAME é o nome do novo pool de nós. Isso garante que o GKE coloque essas cargas de trabalho em nós no novo pool de nós.
  4. Esvazie o pool de nós atual.
  5. Verifique se as cargas de trabalho estão sendo executadas corretamente no novo pool de nós. Se estiverem, exclua o antigo pool de nós. Se você notar interrupções de carga de trabalho, reprograme as cargas de trabalho nos nós atuais removendo a restrição dos nós no pool de nós atual e drenando os novos nós. Resolva o problema e tente novamente.

As métricas do cluster não são exibidas no Cloud Monitoring

Certifique-se de que você ativou a API Cloud Monitoring e a API Cloud Logging do seu projeto e que consegue visualizá-lo no Cloud Monitoring.

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

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

    O Monitoring é ativado por padrão para clusters criados a partir do Console do Google Cloud e da ferramenta de linha de comando , mas você pode conferir executando o comando a seguir ou clicando nos detalhes do cluster no Console do Google Cloud:

    gcloud container clusters describe CLUSTER_NAME
    

    A saída desse comando precisa incluir SYSTEM_COMPONENTS na lista de enableComponents na seção monitoringConfig semelhante a esta:

    monitoringConfig:
      componentConfig:
        enableComponents:
        - SYSTEM_COMPONENTS
    

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

    gcloud container clusters update CLUSTER_NAME --monitoring=SYSTEM
    
  2. Quanto tempo faz desde que o cluster foi criado ou que o monitoramento foi ativado?

    Pode levar até uma hora para que as métricas de um novo cluster comecem a aparecer no Cloud Monitoring.

  3. Um heapster ou gke-metrics-agent (o Coletor OpenTelemetry) está em execução no seu cluster, no namespace "kube-system"?

    Talvez esse pod não consiga programar cargas de trabalho porque seu cluster deve estar com poucos recursos. Confira se o Heapster ou o OpenTelemetry está em execução chamando kubectl get pods --namespace=kube-system e verificando os pods com heapster ou gke-metrics-agent no nome.

  4. O plano de controle do cluster pode se comunicar com os nós?

    O Cloud Monitoring depende disso. Para verificar se esse é o caso, execute o seguinte comando:

    kubectl logs POD_NAME
    

    Se esse comando retornar um erro, os túneis SSH podem estar causando o problema. Consulte esta seção para mais informações.

Se você tiver um problema relacionado ao agente do Cloud Logging, consulte a documentação de solução de problemas.

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

Permissões ausentes na conta para clusters de VPC compartilhada

Para clusters de VPC compartilhada, verifique se a conta de serviço do GKE do projeto de serviço tem uma vinculação com o papel Usuário do agente de serviço de host no projeto host. É possível fazer isso usando a CLI gcloud.

Para verificar se a vinculação de papel existe, execute o seguinte comando no projeto host:

gcloud projects get-iam-policy PROJECT_ID \
  --flatten="bindings[].members" \
  --format='table(bindings.role)' \
  --filter="bindings.members:SERVICE_ACCOUNT_NAME

Substitua:

  • PROJECT_ID: o ID do projeto host.
  • SERVICE_ACCOUNT_NAME: o nome da conta de serviço do GKE.

Na saída, procure o papel roles/container.hostServiceAgentUser.

ROLE
...
roles/container.hostServiceAgentUser
...

Se o papel hostServiceAgentUser não estiver na lista, siga as instruções em Como conceder o papel de usuário do agente de serviço de host para adicionar a vinculação à conta de serviço.

Restaurar a conta de serviço padrão para seu projeto do Google Cloud

A conta de serviço padrão do GKE, container-engine-robot, pode ser acidentalmente desassociada de um projeto. O Agente de serviços do GKE é um papel de gerenciamento de identidade e acesso (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.

É possível verificar se a conta de serviço foi removida do seu projeto usando a CLI gcloud ou o Console do Google Cloud.

gcloud

Execute este comando:

gcloud projects get-iam-policy PROJECT_ID

Substitua PROJECT_ID pelo ID do projeto.

Console

Acesse a página IAM e administrador no console do Google Cloud.

Se o comando ou o painel não exibe container-engine-robot nas suas contas de serviço, a conta de serviço está desvinculada.

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_NUMBER=$(gcloud projects describe "PROJECT_ID" --format 'get(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. Exemplo:

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

Ativar a conta de serviço padrão do Compute Engine

Os nós podem não ser registrados no cluster se a conta de serviço usada para o pool de nós estiver desativada, que geralmente é a conta de serviço padrão do Compute Engine.

É possível verificar se a conta de serviço foi desativada no seu projeto usando a CLI gcloud ou o console do Google Cloud.

gcloud

Execute este comando:

gcloud iam service-accounts list  --filter="NAME~'compute' AND disabled=true"

Console

Acesse a página IAM e administrador no Console do Google Cloud.

Se o comando ou o painel mostrar que a conta de serviço está desativada, execute o seguinte comando para ativá-la:

gcloud iam service-accounts enable PROJECT_ID-compute@developer.gserviceaccount.com

Substitua PROJECT_ID pela ID do seu projeto.

Se isso não resolver os problemas de registro de nós, consulte Resolver problemas no registro de nós para ver mais instruções de solução de problemas.

Pods travados em estado pendente após a ativação do nó alocável

Se você estiver enfrentando problemas com pods travados no estado pendente depois de ativar o Node Alocável, observe o seguinte:

A partir da versão 1.7.6, o GKE reserva CPU e memória para sobrecarga do Kubernetes, incluindo o Docker e o sistema operacional. Consulte Arquitetura de cluster para saber quanto de cada tipo de máquina pode ser programado pelos pods.

Se os pods estiverem pendentes após um upgrade, sugerimos o seguinte:

A autoridade de certificação raiz do cluster expirará em breve

A autoridade de certificação raiz do cluster expira em breve. Para evitar que operações normais do cluster sejam interrompidas, é necessário executar uma rotação de credenciais.

Estou recebendo o erro "A instância 'Foo' não contém metadados do 'modelo de instância'"

Talvez você veja o erro "A instância 'Foo' não contém metadados 'modelo de instância'" como um status de um pool de nós que falha ao fazer upgrade, escalonar ou realizar o reparo automático de nós.

Essa mensagem indica que os metadados das instâncias de VM, alocados pelo GKE, foram corrompidos. Isso normalmente acontece quando scripts ou automação criados sob medida tentam adicionar novos metadados de instância (como block-project-ssh-keys) e, em vez de apenas adicionar ou atualizar valores, também exclui os metadados metadados. Leia sobre metadados de instância de VM em Como definir metadados personalizados.

Caso algum dos valores de metadados críticos, entre outros: instance-template, kube-labels, kubelet-config, kubeconfig, cluster-name, configure-sh, cluster-uid) foram excluídos, o nó ou o pool de nós inteiro pode ficar em um estado instável, já que esses valores são cruciais para as operações do GKE.

Se os metadados da instância foram corrompidos, a melhor maneira de recuperá-los é recriar o pool de nós que contém as instâncias de VM corrompidas. Você precisará adicionar um pool de nós ao cluster e aumentar a contagem de nós no novo pool de nós, além de restringir e remover nós em outro. Consulte as instruções para migrar cargas de trabalho entre pools de nós.

Para descobrir quem e quando os metadados da instância foram editados, consulte as informações de geração de registros de auditoria do Compute Engine ou use o Explorador de registros com a pesquisa semelhante a esta:

resource.type="gce_instance_group_manager"
protoPayload.methodName="v1.compute.instanceGroupManagers.setInstanceTemplate"

Nos registros, você pode encontrar o endereço IP do criador da solicitação e o user agent:

requestMetadata: {
  callerIp: "REDACTED"
  callerSuppliedUserAgent: "google-api-go-client/0.5 GoogleContainerEngine/v1"
}

Chave do Cloud KMS desativada

A mensagem de erro a seguir será exibida se a conta de serviço padrão do GKE não puder acessar a chave do Cloud KMS.

Cluster problem detected (Kubernetes Engine Service Agent account unable to use CloudKMS key configured for Application Level encryption).

Para resolver esse problema, reative a chave desativada.

Para mais informações sobre secrets no GKE, consulte Criptografar secrets na camada do aplicativo.