Execute cargas de trabalho tolerantes a falhas a custos menores em pods do Spot

Nesta página, mostramos como executar cargas de trabalho tolerantes a falhas a custos menores usando pods do Spot nos clusters Autopilot do Google Kubernetes Engine (GKE).

Visão geral

Nos clusters do Autopilot do GKE, os pods do Spot são pods executados em nós com suporte de VMs do Spot do Compute Engine. Os pods do Spot têm um preço menor do que os do Autopilot padrão, mas podem ser removidos pelo GKE sempre que os recursos de computação forem necessários para executar os pods padrão.

Os pods do Spot são ideais para executar cargas de trabalho sem estado, em lote ou tolerantes a falhas a custos menores em comparação com a execução dessas cargas de trabalho como pods padrão. Para usar pods do Spot em clusters do Autopilot, modifique o manifesto com sua especificação do pod para solicitar pods do Spot.

É possível executar pods do Spot na classe de computação padrão de uso geral do Autopilot, bem como em classes de computação especializadas que atendam a requisitos específicos de hardware. Para mais informações sobre essas classes de computação, consulte Classes de computação no Autopilot.

Para saber mais sobre os preços dos pods do Spot em clusters do Autopilot, consulte Preços do Google Kubernetes Engine.

Os pods do Spot são excluídos do Contrato de nível de serviço do Autopilot.

Benefícios

O uso de pods do Spot nos clusters do Autopilot oferece os seguintes benefícios:

  • preços mais baixos do que a execução das mesmas cargas de trabalho em pods padrão do Autopilot;
  • o GKE gerencia automaticamente o escalonamento automático e a programação;
  • O GKE faz um taint automaticamente dos nós que executam pods do Spot para garantir que os pods padrão, como suas cargas de trabalho críticas, não sejam programados nesses nós; As implantações que usam pods do Spot são atualizadas automaticamente com uma tolerância correspondente.

Antes de começar

Antes de começar, verifique se você realizou as tarefas a seguir:

  • Ativar a API Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Se você quiser usar a CLI do Google Cloud para essa tarefa, instale e inicialize a gcloud CLI. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando o comando gcloud components update. Talvez as versões anteriores da CLI gcloud não sejam compatíveis com a execução dos comandos neste documento.

Solicitar pods do Spot nas cargas de trabalho do Autopilot

Para solicitar que os pods sejam executados como pods do Spot, use o rótulo cloud.google.com/gke-spot=true em um nodeSelector ou afinidade de nó na especificação do pod. O GKE provisiona automaticamente os nós que podem executar pods do Spot.

Os pods do Spot podem ser removidos e encerrados a qualquer momento, por exemplo, se os recursos de computação forem necessários em outro lugar no Google Cloud. Quando ocorre um encerramento, os pods do Spot no nó de encerramento podem solicitar um período de carência de 15 segundos antes do encerramento, o que é concedido da melhor maneira possível, especificando o campo terminationGracePeriodSeconds.

O período de carência máximo concedido aos pods do Spot durante a preempção é de 15 segundos. Solicitando mais de 15 segundos em terminationGracePeriodSeconds não concede mais de 15 segundos durante a preempção. Na remoção, o pod recebe o sinal de SIGTERM e precisa seguir etapas para o encerramento durante o período de carência.

Para o Autopilot, o GKE também faz taint automaticamente dos nós criados para executar pods do Spot e modifica essas cargas de trabalho com a tolerância correspondente. O taint impede que os pods padrão sejam programados em nós que executam pods do Spot.

Usar um nodeSelector para exigir pods do Spot

Use um nodeSelector para exigir pods do Spot em uma implantação. Adicione o rótulo cloud.google.com/gke-spot=true à implantação, como no exemplo a seguir:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    metadata:
      labels:
        app: pi
    spec:
      nodeSelector:
        cloud.google.com/gke-spot: "true"
      terminationGracePeriodSeconds: 15
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

Usar a afinidade de nó para solicitar pods do Spot

Como alternativa, é possível usar a afinidade de nó para solicitar pods do Spot. A afinidade de nó oferece uma maneira mais extensível de selecionar nós para executar as cargas de trabalho. Por exemplo, é possível combinar vários critérios de seleção para ter um controle mais preciso sobre onde seus pods são executados. Ao usar a afinidade de nó para solicitar pods do Spot, é possível especificar o tipo de afinidade de nó a ser usado da seguinte maneira:

  • requiredDuringSchedulingIgnoredDuringExecution: precisa usar pods do Spot.
  • preferredDuringSchedulingIgnoredDuringExecution: usar os pods do Spot da melhor forma possível.

Para usar a afinidade de nó para exigir pods do Spot em uma implantação, adicione a seguinte regra nodeAffinity ao manifesto de implantação:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    metadata:
      labels:
        app: pi
    spec:
      terminationGracePeriodSeconds: 15
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: cloud.google.com/gke-spot
                operator: In
                values:
                - "true"
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

Como solicitar pods do Spot da melhor forma possível

Para usar a afinidade de nó para solicitar pods do Spot da melhor forma possível, use preferredDuringSchedulingIgnoredDuringExecution. Quando você solicita pods do Spot da forma que prefere, o GKE programa seus pods com base na seguinte ordem:

  1. nós existentes que podem executar pods do Spot que têm capacidade alocável disponível;
  2. nós padrão existentes que têm capacidade alocável disponível;
  3. novos nós que poderão executar pods do Spot, se os recursos de computação estiverem disponíveis;
  4. novos nós padrão.

Como o GKE prefere os nós padrão existentes que têm capacidade alocável em vez de criar novos nós para os pods do Spot, talvez você perceba mais pods em execução como pods padrão do que os pods do Spot, o que impede que você aproveite ao máximo preços mais baixos para pods do Spot.

Solicitações de pods preemptivos

Os clusters do Autopilot aceitam solicitações de pods preemptivos usando o seletor cloud.google.com/gke-preemptible. Os pods que usam esse seletor são migrados automaticamente para os pods do Spot, e o seletor é alterado para cloud.google.com/gke-spot.

Encontrar e excluir pods encerrados

Durante o encerramento do pod, o kubelet atribui um status Failed e um motivo Shutdown aos pods encerrados. Quando o número de pods encerrados atinge um limite de 1.000, a coleta de lixo limpa os pods. Também é possível excluir pods de desligamento manualmente usando o seguinte comando:

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

Impedir que as cargas de trabalho usem pods spot

Se você tiver pods do Spot que quer atualizar para serem executados como pods padrão, use um dos seguintes métodos:

  • Recrie a carga de trabalho: exclua a implantação, remova as linhas do manifesto que selecionam pods Spot e aplique o manifesto de implantação atualizado ao cluster.
  • Edite a carga de trabalho: edite a especificação da implantação enquanto os pods estão em execução no cluster.

Com esses dois métodos, você pode ter pequenas interrupções na carga de trabalho.

Recriar a carga de trabalho

As etapas a seguir mostram como excluir a implantação atual e aplicar um manifesto atualizado ao cluster. Você também pode usar essas etapas para outros tipos de cargas de trabalho do Kubernetes, como Jobs.

Para garantir que o GKE coloque os pods atualizados no tipo correto de nó, exporte o estado atual da carga de trabalho do servidor de API do Kubernetes para um arquivo e edite esse arquivo.

  1. Grave a especificação da carga de trabalho em um arquivo YAML:

    kubectl get deployment DEPLOYMENT_NAME -o yaml > DEPLOYMENT_NAME-on-demand.yaml
    

    Substitua DEPLOYMENT_NAME pelo nome da sua implantação. Para outros tipos de cargas de trabalho, como jobs ou pods, use o nome do recurso correspondente no comando kubectl get, como kubectl get pod.

  2. Abra o arquivo YAML em um editor de texto:

    vi DEPLOYMENT_NAME-on-demand.yaml
    
  3. Remova o nodeSelector para pods Spot e a tolerância que o GKE adicionou para pods Spot do arquivo:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
      # lines omitted for clarity
    spec:
      progressDeadlineSeconds: 600
      replicas: 6
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          pod: nginx-pod
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
        # lines omitted for clarity
        spec:
          containers:
          - image: nginx
            imagePullPolicy: Always
            name: web-server
            resources:
              limits:
                ephemeral-storage: 1Gi
              requests:
                cpu: 500m
                ephemeral-storage: 1Gi
                memory: 2Gi
            securityContext:
              capabilities:
                drop:
                - NET_RAW
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          nodeSelector:
            cloud.google.com/gke-spot: "true"
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext:
            seccompProfile:
              type: RuntimeDefault
          terminationGracePeriodSeconds: 15
          tolerations:
          - effect: NoSchedule
            key: kubernetes.io/arch
            operator: Equal
            value: amd64
          - effect: NoSchedule
            key: cloud.google.com/gke-spot
            operator: Equal
            value: "true"
    status:
      #lines omitted for clarity
    

    Remova a tolerância e o nodeSelector para indicar ao GKE que os pods precisam ser executados em nós sob demanda em vez de em nós do Spot.

  4. Salve o manifesto atualizado.

  5. Exclua e reaplique o manifesto de implantação ao cluster:

    kubectl replace -f DEPLOYMENT_NAME-on-demand.yaml
    

    A duração dessa operação depende do número de pods que o GKE precisa encerrar e limpar.

Editar a carga de trabalho no local

As etapas a seguir mostram como editar uma implantação em execução no local para indicar ao GKE que os pods precisam ser executados em nós sob demanda. Você também pode usar essas etapas para outros tipos de cargas de trabalho do Kubernetes, como Jobs.

É necessário editar o objeto de carga de trabalho na API Kubernetes porque o GKE adiciona automaticamente uma tolerância para pods do Spot à especificação de carga de trabalho durante a admissão.

  1. Abra o manifesto da carga de trabalho para edição em um editor de texto:

    kubectl edit deployment/DEPLOYMENT_NAME
    

    Substitua DEPLOYMENT_NAME pelo nome do Deployment. Para outros tipos de cargas de trabalho, como jobs ou pods, use o nome do recurso correspondente no comando kubectl edit, como kubectl edit pod/POD_NAME.

  2. No editor de texto, exclua o seletor de nós ou a regra de afinidade de nós para pods do Spot e a tolerância que o GKE adicionou ao manifesto, como no exemplo a seguir:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-deployment
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          type: dev
      template:
        metadata:
          labels:
            type: dev
        spec:
          nodeSelector:
            cloud.google.com/gke-spot: "true"
          tolerations:
          - effect: NoSchedule
            key: cloud.google.com/gke-spot
            operator: Equal
            value: "true"
          containers:
          - name: nginx
            image: nginx
            ports:
            - containerPort: 80
    
  3. Salve o manifesto atualizado e feche o editor de texto. A configuração atualizada do objeto indica ao GKE que os pods precisam ser executados em nós sob demanda. O GKE recria os pods para colocá-los em novos nós sob demanda.

Verificar se as cargas de trabalho são executadas em nós sob demanda

Para verificar se as cargas de trabalho atualizadas não são mais executadas em pods do Spot, inspecione a carga de trabalho e procure a tolerância para pods do Spot:

  • Inspecione a carga de trabalho:

    kubectl describe deployment DEPLOYMENT_NAME
    

A saída não mostra uma entrada para cloud.google.com/gke-spot no campo spec.tolerations.

A seguir