Usar VMs preemptivas para executar cargas de trabalho tolerantes a falhas


Nesta página, mostramos como usar VMs preemptivas no Google Kubernetes Engine (GKE).

Informações gerais

As VMs preemptivas são instâncias de VM do Compute Engine com um preço menor que o das VMs padrão e que não oferecem garantia de disponibilidade. As VMs preemptivas oferecem funcionalidade semelhante à do Spot, mas duram apenas 24 horas após a criação.

Em alguns casos, uma VM preemptiva pode durar mais de 24 horas. Isso ocorre quando a nova instância do Compute Engine chega muito rápido e o Kubernetes não reconhece que uma VM do Compute Engine diferente foi criada. A instância subjacente do Compute Engine terá uma duração máxima de 24 horas e seguir o comportamento esperado de VM preemptiva.

Comparação com VMs do Spot

As VMs preemptivas compartilham muitas semelhanças com as VMs do Spot, incluindo:

Ao contrário das VMs do Spot, que não têm prazo de validade máximo, as VMs preemptivas duram somente por 24 horas após a criação.

É possível ativar VMs preemptivas em novos clusters e pools de nós, usar nodeSelector ou afinidade do nó para controlar a programação e usar taints e tolerâncias para evitar problemas com as cargas de trabalho do sistema quando os nós são interrompidos.

Encerramento e encerramento otimizado das VMs preemptivas

Quando o Compute Engine precisa recuperar os recursos usados pelas VMs preemptivas, um aviso de preempção é enviado para o GKE. As VMs preemptivas são encerradas 30 segundos após o recebimento de um aviso de encerramento.

Nos clusters que executam o GKE versão 1.20 e mais recente, o recurso de encerramento de nó otimizado do kubelet está ativado por padrão. O kubelet detecta o aviso de encerramento e encerra corretamente os pods em execução no nó. Se os pods fizerem parte de uma implantação, o controlador vai criar e programar novos pods para substituir os pods encerrados.

Com base no melhor esforço, o kubelet concede o seguinte período de encerramento sem complicações com base na versão do GKE do pool de nós:

  • Versão posterior a 1.22.8-gke.200: 15 segundos para pods sem sistema, após os pods do sistema (com as classes de prioridade system-cluster-critical ou system-node-critical) ter 15 segundos para encerrar sem complicações.
  • Versão anterior a 1.22.8-gke.200: 25 segundos para pods que não são do sistema, após os pods do sistema (com as classes de prioridade system-cluster-critical ou system-node-critical) ter 15 segundos para encerrar sem complicações.

Durante o encerramento normal dos nós, o kubelet atualiza o status deles, atribuindo uma fase Failed e um motivo Terminated.

Quando o número de pods encerrados atinge um limite de 1.000 para clusters com menos de 100 nós ou 5.000 para clusters com 100 nós ou mais, a coleta de lixo limpa os pods.

Também é possível excluir pods encerrados manualmente usando os seguintes comandos:

  kubectl get pods --all-namespaces | grep -i NodeShutdown | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n
  kubectl get pods --all-namespaces | grep -i Terminated | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n

Alterações no comportamento do Kubernetes

O uso de VMs preemptivas no GKE altera algumas garantias e restrições que o Kubernetes fornece, como:

  • O GKE encerra as VMs preemptivas sem um período de encerramento para os pods, 30 segundos após receber um aviso de preempção do Compute Engine.

  • A recuperação de VMs preemptivas é involuntária e não está coberta pelas garantias de PodDisruptionBudgets. Pode haver indisponibilidade maior do que o PodDisruptionBudget configurado.

Limitações

Criar um cluster ou pool de nós com VMs preemptivas

É possível usar a CLI do Google Cloud para criar um cluster ou pool de nós com VMs preemptivas.

Para criar um cluster com VMs preemptivas, execute o comando a seguir:

gcloud container clusters create CLUSTER_NAME \
    --preemptible

Substitua CLUSTER_NAME pelo nome do novo bucket.

Para criar um pool de nós com VMs preemptivas, execute o seguinte comando:

gcloud container node-pools create POOL_NAME \
    --cluster=CLUSTER_NAME \
    --preemptible

Substitua POOL_NAME pelo nome do novo pool de nós.

Usar o nodeSelector para programar pods em VMs preemptivas

O GKE adiciona os identificadores cloud.google.com/gke-preemptible=true e cloud.google.com/gke-provisioning=preemptible (para nós que executam a versão 1.25.5-gke.2500 ou posterior do GKE) aos nós que usam VMs preemptivas. Use um nodeSelector nas implantações para instruir o GKE a programar pods em VMs preemptivas.

Por exemplo, os seguintes filtros de implantação para VMs preemptivas usando o identificador cloud.google.com/gke-preemptible:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
      - name: hello-app
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
        resources:
          requests:
            cpu: 200m
      nodeSelector:
        cloud.google.com/gke-preemptible: "true"

Usar taints de nó para VMs preemptivas

É possível usar taint de nós que usam VMs preemptivas para que o GKE coloque apenas pods com tolerância correspondente nesses nós.

Para adicionar um taint a um pool de nós que usa VMs preemptivas, use a sinalização --node-taints ao criar o pool de nós, semelhante ao seguinte comando:

gcloud container node-pools create POOL2_NAME \
    --cluster=CLUSTER_NAME \
    --node-taints=cloud.google.com/gke-preemptible="true":NoSchedule

Agora, apenas os pods que toleram o taint serão programados no nó.

Para adicionar a tolerância relevante aos pods, modifique as implantações e adicione o seguinte à especificação do pod:

tolerations:
- key: cloud.google.com/gke-preemptible
  operator: Equal
  value: "true"
  effect: NoSchedule

Taints de nó para VMs preemptivas de GPU

As VMs preemptivas são compatíveis com GPUs. Crie pelo menos um outro pool de nós no cluster que não use VMs preemptivas antes de adicionar um pool de nós de GPU que use VMs preemptivas. Ter um pool de nós padrão garante que o GKE possa colocar componentes do sistema com segurança, como DNS.

Se você criar um novo cluster com pools de nós de GPU que usam VMs preemptivas ou se adicionar um novo pool de nós de GPU que use VMs preemptivas a um cluster que ainda não tem um pool de nós sob demanda, o GKE não adiciona automaticamente o taint nvidia.com/gpu=present:NoSchedule aos nós. O GKE pode programar pods do sistema nas VMs preemptivas, o que pode gerar interrupções. Esse comportamento também aumenta o consumo de recursos, porque os nós do GPU são mais caros do que os nós não-GPU.

A seguir