Resolver problemas em pools de nós padrão do GKE


Nesta página, mostramos como resolver problemas com pools de nós do modo padrão do GKE.

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

Problemas de criação de pool de nós

Nesta seção, listamos problemas que podem ocorrer ao criar novos pools de nós em clusters padrão e fornecemos sugestões de como corrigi-los.

Problema: a criação do pool de nós falha devido a recursos insuficientes

O problema a seguir ocorre quando você cria um pool de nós com hardware específico em uma zona do Google Cloud que não tem hardware suficiente disponível para atender aos requisitos.

Para validar se a criação do pool de nós falhou porque uma zona não tinha recursos suficientes, verifique se há mensagens de erro relevantes nos registros.

  1. Acesse a Análise de registros no console do Google Cloud.

    Acessar a Análise de registros

  2. No campo Consulta, insira a seguinte consulta:

    log_id(cloudaudit.googleapis.com/activity)
    resource.labels.cluster_name="CLUSTER_NAME"
    protoPayload.status.message:("ZONE_RESOURCE_POOL_EXHAUSTED" OR "does not have enough resources available to fulfill the request" OR "resource pool exhausted" OR "does not exist in zone")
    

    Substitua CLUSTER_NAME pelo nome do cluster do GKE.

  3. Clique em Executar consulta.

Talvez você verá uma das seguintes mensagens de erro:

  • resource pool exhausted
  • The zone does not have enough resources available to fulfill the request. Try a different zone, or try again later.
  • ZONE_RESOURCE_POOL_EXHAUSTED
  • ZONE_RESOURCE_POOL_EXHAUSTED_WITH_DETAILS
  • Machine type with name 'MACHINE_NAME' does not exist in zone 'ZONE_NAME'

Para resolver esse problema, tente o seguinte:

  • Verifique se a região ou zona selecionada do Google Cloud tem o hardware específico de que você precisa. Use a tabela de disponibilidade do Compute Engine para verificar se determinadas zonas aceitam hardware específico. Escolha uma região ou zona do Google Cloud diferente para os nós que possam ter melhor disponibilidade do hardware necessário.
  • Crie o pool de nós com tipos de máquina menores. Aumente o número de nós no pool para que a capacidade de computação total permaneça a mesma.
  • Use a reserva de capacidade do Compute Engine para reservar os recursos com antecedência.
  • Use o provisionamento de melhor esforço, descrito na seção a seguir, para criar o pool de nós se ele puder provisionar pelo menos um número mínimo especificado de nós do número solicitado.

Provisionamento de melhor esforço

Para determinados hardwares, é possível usar o provisionamento de melhor esforço, que diz ao GKE para criar o pool de nós se ele puder provisionar pelo menos um número mínimo de nós. O GKE continua tentando provisionar os nós restantes para atender à solicitação original ao longo do tempo. Para instruir o GKE a usar o provisionamento de melhor esforço, use o seguinte comando:

gcloud container node-pools create NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --node-locations=ZONE1,ZONE2,... \
    --machine-type=MACHINE_TYPE
    --best-effort-provision \
    --min-provision-nodes=MINIMUM_NODES

Substitua:

  • NODE_POOL_NAME: o nome do novo pool de nós.
  • ZONE1,ZONE2,...: as zonas do Compute Engine para os nós. Essas zonas precisam ser compatíveis com o hardware selecionado.
  • MACHINE_TYPE: o tipo de máquina do Compute Engine para os nós. Por exemplo, a2-highgpu-1g.
  • MINIMUM_NODES: o número mínimo de nós para o GKE provisionar e criar o pool de nós. Se omitido, o padrão é 1.

Por exemplo, considere um cenário em que você precisa de 10 nós com GPUs NVIDIA® A100 de 40 GB anexadas a us-central1-c. De acordo com a tabela de disponibilidade de regiões e zonas de GPU, essa zona é compatível com GPUs A100. Para evitar a falha na criação do pool de nós se 10 máquinas de GPU não estiverem disponíveis, use o provisionamento de melhor esforço.

gcloud container node-pools create a100-nodes \
    --cluster=ml-cluster \
    --node-locations=us-central1-c \
    --num-nodes=10 \
    --machine-type=a2-highgpu-1g \
    --accelerator=type=nvidia-tesla-a100,count=1 \
    --best-effort-provision \
    --min-provision-nodes=5

O GKE cria o pool de nós mesmo que apenas cinco GPUs estejam disponíveis em us-central1-c. Com o tempo, o GKE tenta provisionar mais nós até que haja 10 nós no pool.

Erro: a instância não contém metadados "modelo de instância"

Talvez você encontre o seguinte erro como um status de um pool de nós que falha ao fazer upgrade, escalonar ou realizar o reparo automático de nós:

Instance INSTANCE_NAME does not contain 'instance-template' metadata

Esse erro 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, recomendamos que você os recupere recriando 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 seguinte:

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

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

Migrar cargas de trabalho entre pools de nós

Use as instruções a seguir para migrar cargas de trabalho de um pool de nós para outro. Se você quiser alterar os atributos de máquina dos nós no pool de nós, consulte Escalonar verticalmente alterando os atributos da máquina de nós.

Como migrar pods para um novo pool de nós

Para migrar pods para um novo pool de nós, faça o seguinte:

  1. Restrinja os nós no pool de nós atual: com essa operação, os nós no pool atual são marcados como não programáveis. O Kubernetes para de programar novos pods para esses nós quando você os marca como não programáveis.

  2. Esvazie os nós no pool de nós atual: essa operação remove as cargas de trabalho em execução nos nós do pool de nós atual normalmente.

Essas etapas, realizadas individualmente para cada nó, fazem com que os pods em execução no pool de nós atual sejam encerrados de maneira prática. O Kubernetes faz a reprogramação delas em outros nós disponíveis.

Para garantir que o Kubernetes encerre seus aplicativos normalmente, seus contêineres devem manipular o sinal SIGTERM. Use essa abordagem para fechar conexões ativas com clientes e confirmar ou reverter transações de banco de dados de maneira limpa. No manifesto do pod, use o campo spec.terminationGracePeriodSeconds para especificar quanto tempo o Kubernetes precisa aguardar antes de interromper os contêineres no pod. O padrão é 30 segundos. Leia mais sobre o encerramento de pods na documentação do Kubernetes.

Você pode restringir e drenar nós usando os comandos kubectl cordon e kubectl drain.

Criar pool de nós e migrar cargas de trabalho

Para migrar as cargas de trabalho para um novo pool de nós, crie o novo pool de nós e, em seguida, restrinja e esvazie os nós no pool atual:

  1. Adicione um pool de nós ao cluster.

    Para verificar se o novo pool de nós foi criado, execute o seguinte comando:

    gcloud container node-pools list --cluster CLUSTER_NAME
    
  2. Execute o seguinte comando para ver em qual nó os pods são executados. Consulte a coluna NODE:

    kubectl get pods -o=wide
    
  3. Receba uma lista de nós no pool de nós atual, substituindo EXISTING_NODE_POOL_NAME pelo nome:

    kubectl get nodes -l cloud.google.com/gke-nodepool=EXISTING_NODE_POOL_NAME
    
  4. Execute o comando kubectl cordon NODE. Substitua NODE pelos nomes do comando anterior. O comando do shell a seguir itera cada nó no pool de nós atual e os marca como não programáveis:

    for node in $(kubectl get nodes -l cloud.google.com/gke-nodepool=EXISTING_NODE_POOL_NAME -o=name); do
      kubectl cordon "$node";
    done
    
  5. 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.

  6. Drene cada nó removendo pods com um período de encerramento normal de 10 segundos:

    for node in $(kubectl get nodes -l cloud.google.com/gke-nodepool=EXISTING_NODE_POOL_NAME -o=name); do
      kubectl drain --force --ignore-daemonsets --delete-emptydir-data --grace-period=GRACEFUL_TERMINATION_SECONDS  "$node";
    done
    

    Substitua GRACEFUL_TERMINATION_PERIOD_SECONDS pelo tempo necessário para o encerramento normal.

  7. Execute o comando a seguir para ver se os nós no pool atual têm o status SchedulingDisabled na lista de nós:

    kubectl get nodes
    

    Além disso, você vai notar que os pods agora estão em execução nos nós no novo pool de nós:

    kubectl get pods -o=wide
    
  8. Exclua o pool de nós atual se não precisar mais dele:

    gcloud container node-pools delete default-pool --cluster CLUSTER_NAME
    

A seguir

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