Resolva problemas com node pools padrão do GKE


Esta página mostra-lhe como resolver problemas com os conjuntos de nós do modo padrão do GKE.

Problemas de criação do node pool

Esta secção apresenta uma lista de problemas que podem ocorrer ao criar novos node pools em clusters padrão e fornece sugestões sobre como os pode corrigir.

Problema: a criação do node pool falha devido a recursos insuficientes

O seguinte problema ocorre quando cria um node pool com hardware específico numa zona que não tem hardware suficiente disponível para satisfazer os seus requisitos. Google Cloud

Para validar se a criação do conjunto de nós falhou porque uma zona não tinha recursos suficientes, verifique os registos para ver se existem mensagens de erro relevantes.

  1. Aceda ao Explorador de registos na Google Cloud consola:

    Aceda ao Explorador de registos

  2. No campo Consulta, especifique 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.

Pode 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 este problema, experimente as seguintes sugestões:

  • Certifique-se de que a Google Cloud região ou a zona selecionada tem o hardware específico de que precisa. Use a tabela de disponibilidade do Compute Engine para verificar se zonas específicas suportam hardware específico. Escolha uma Google Cloud região ou uma zona diferente para os seus nós que possa ter uma melhor disponibilidade do hardware de que precisa.
  • Crie o node pool com tipos de máquinas mais pequenos. Aumentar o número de nós no conjunto de nós para que a capacidade de computação total permaneça igual.
  • Use a reserva de capacidade do Compute Engine para reservar os recursos antecipadamente.
  • Use o aprovisionamento de melhor esforço, descrito na secção seguinte, para criar com êxito o conjunto de nós se puder aprovisionar, pelo menos, um número mínimo especificado de nós a partir do número pedido.

Aprovisionamento com o melhor esforço

Para determinado hardware, pode usar o aprovisionamento de melhor esforço, que indica ao GKE para criar com êxito o conjunto de nós se conseguir aprovisionar pelo menos um número mínimo especificado de nós. O GKE continua a tentar aprovisionar os nós restantes para satisfazer o pedido original ao longo do tempo. Para indicar ao GKE que use o aprovisionamento de melhor esforço, use o seguinte comando:

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

Substitua o seguinte:

  • NODE_POOL_NAME: o nome do novo node pool.
  • CONTROL_PLANE_LOCATION: a localização do Compute Engine do plano de controlo do seu cluster. Indique uma região para clusters regionais ou uma zona para clusters zonais.
  • ZONE1,ZONE2,...: as zonas do Compute Engine para os nós. Estas zonas têm de suportar 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 aprovisionar e criar com êxito o conjunto de nós. Se for omitido, o valor predefinido é 1.

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

gcloud container node-pools create a100-nodes \
    --cluster=ml-cluster \
    --location=us-central1 \
    --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 node pool, mesmo que apenas cinco GPUs estejam disponíveis em us-central1-c. Ao longo do tempo, o GKE tenta aprovisionar mais nós até existirem 10 nós no conjunto de nós.

Erro: a instância não contém metadados "instance-template"

Pode ver o seguinte erro como estado de um conjunto de nós que não consegue atualizar, dimensionar nem realizar a reparação automática de nós:

Instance INSTANCE_NAME does not contain 'instance-template' metadata

Este erro indica que os metadados das instâncias de VM, atribuídos pelo GKE, foram danificados. Normalmente, isto acontece quando a automatização ou os scripts criados pelo utilizador tentam adicionar novos metadados de instâncias (como block-project-ssh-keys) e, em vez de apenas adicionar ou atualizar valores, também eliminam os metadados existentes. Pode ler acerca dos metadados da instância de VM em 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) tenha sido eliminado, o nó ou todo o conjunto de nós pode ficar num estado instável, uma vez que estes valores são cruciais para as operações do GKE.

Se os metadados da instância estiverem danificados, recomendamos que recupere os metadados recriando o conjunto de nós que contém as instâncias de VMs danificadas. Tem de adicionar um conjunto de nós ao cluster e aumentar o número de nós no novo conjunto de nós, ao mesmo tempo que isola e remove nós noutro. Consulte as instruções para migrar cargas de trabalho entre pools de nós.

Para saber quem e quando os metadados da instância foram editados, pode rever as informações de registo de auditoria do Compute Engine ou encontrar registos através do Explorador de registos com uma consulta de pesquisa semelhante à seguinte:

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

Nos registos, pode encontrar o endereço IP e o agente do utilizador do originador do pedido. Por exemplo:

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

Migre cargas de trabalho entre node pools

Siga as instruções abaixo para migrar cargas de trabalho de um node pool para outro. Se quiser alterar os atributos da máquina dos nós no seu conjunto de nós, consulte o artigo Escale verticalmente alterando os atributos da máquina dos nós.

Compreenda como migrar agrupamentos para um novo conjunto de nós

Para migrar pods para um novo conjunto de nós, tem de fazer o seguinte:

  1. Isolar os nós no conjunto de nós existente: esta operação marca os nós no conjunto de nós existente como não agendáveis. O Kubernetes deixa de agendar novos pods para estes nós assim que os marcar como não agendáveis.

  2. Esvazie os nós no node pool existente: esta operação desalojar os volumes de trabalho em execução nos nós do node pool existente de forma graciosa.

Estes passos, realizados individualmente para cada nó, fazem com que os pods em execução no seu conjunto de nós existente terminem normalmente. O Kubernetes reagenda-os para outros nós disponíveis.

Para garantir que o Kubernetes termina as suas aplicações corretamente, os contentores devem processar o sinal SIGTERM. Use esta abordagem para fechar as ligações ativas aos clientes e confirmar ou reverter as transações da base de dados de forma limpa. No manifesto do Pod, pode usar o campo spec.terminationGracePeriodSeconds para especificar quanto tempo o Kubernetes tem de esperar antes de parar os contentores no Pod. A predefinição é 30 segundos. Pode ler mais acerca da terminação de pods na documentação do Kubernetes.

Pode isolar e esvaziar nós com os comandos kubectl cordon e kubectl drain.

Crie um node pool e migre cargas de trabalho

Para migrar as suas cargas de trabalho para um novo node pool, crie o novo node pool e, de seguida, isole e esvazie os nós no node pool existente:

  1. Adicione um grupo de nós ao seu cluster.

    Execute o seguinte comando para verificar se o novo conjunto de nós foi criado:

    gcloud container node-pools list --cluster CLUSTER_NAME
    
  2. Para desativar o redimensionamento automático no conjunto de nós existente, se estiver ativado, execute o seguinte comando:

    gcloud container clusters update CLUSTER_NAME
        --location=CONTROL_PLANE_LOCATION \
        --no-enable-autoscaling \
        --node-pool=EXISTING_NODE_POOL_NAME
    

    Substitua CONTROL_PLANE_LOCATION pela localização do Compute Engine do plano de controlo do seu cluster. Indique uma região para clusters regionais ou uma zona para clusters zonais.

  3. Execute o seguinte comando para ver em que nó os pods estão a ser executados (consulte a coluna NODE):

    kubectl get pods -o=wide
    
  4. Obtenha uma lista de nós no conjunto de nós existente, substituindo EXISTING_NODE_POOL_NAME pelo nome:

    kubectl get nodes -l cloud.google.com/gke-nodepool=EXISTING_NODE_POOL_NAME
    
  5. Execute o comando kubectl cordon NODE (substitua NODE pelos nomes do comando anterior). O seguinte comando de shell itera cada nó no conjunto de nós existente e marca-os como não agendáveis:

    for node in $(kubectl get nodes -l cloud.google.com/gke-nodepool=EXISTING_NODE_POOL_NAME -o=name); do
      kubectl cordon "$node";
    done
    
  6. Opcionalmente, atualize as cargas de trabalho em execução no node pool existente para adicionar um nodeSelector para a etiqueta cloud.google.com/gke-nodepool:NEW_NODE_POOL_NAME, onde NEW_NODE_POOL_NAME é o nome do novo node pool. Isto garante que o GKE coloca essas cargas de trabalho em nós no novo conjunto de nós.

  7. Esvazie cada nó removendo todos os pods com um período de encerramento gracioso atribuído 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 pela quantidade de tempo necessária para o encerramento normal.

  8. Confirme se os nós no conjunto de nós existente têm o estado SchedulingDisabled na lista de nós executando o seguinte comando:

    kubectl get nodes
    

    Além disso, deve ver que os pods são agora executados nos nós no novo conjunto de nós:

    kubectl get pods -o=wide
    
  9. Elimine o node pool existente se não precisar dele:

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

O que se segue?