Execute cargas de trabalho com tolerância a falhas a custos mais baixos em Spot Pods

Esta página mostra como executar cargas de trabalho tolerantes a falhas a custos mais baixos através de pods de instância instantânea nos clusters do Autopilot do Google Kubernetes Engine (GKE).

Vista geral

Nos clusters do GKE Autopilot, os pods de capacidade instantânea são pods que são executados em nós suportados por VMs de capacidade instantânea do Compute Engine. Os Spot Pods têm um preço inferior ao dos Autopilot Pods padrão, mas podem ser desalojados pelo GKE sempre que forem necessários recursos de computação para executar Pods padrão.

Os Spot Pods são ideais para executar cargas de trabalho sem estado, em lote ou com tolerância a falhas a custos mais baixos em comparação com a execução dessas cargas de trabalho como Pods padrão. Para usar Spot Pods em clusters do Autopilot, modifique o manifesto com a especificação do pod para pedir Spot Pods.

Pode executar Spot Pods na classe de computação Autopilot de uso geral predefinida, bem como em classes de computação especializadas que cumprem requisitos de hardware específicos. Para ver informações sobre estas classes de computação, consulte o artigo Classes de computação no Autopilot.

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

Os Spot Pods estão excluídos do contrato de nível de serviço do Autopilot.

Vantagens

A utilização de Spot Pods nos seus clusters do Autopilot oferece-lhe as seguintes vantagens:

  • Preços mais baixos do que a execução das mesmas cargas de trabalho em Autopilot Pods padrão.
  • O GKE gere automaticamente a escala automática e o agendamento.
  • O GKE contamina automaticamente os nós que executam pods de spot para garantir que os pods padrão, como as suas cargas de trabalho críticas, não são agendados nesses nós. As suas implementações que usam Spot Pods são atualizadas automaticamente com uma tolerância correspondente.

Antes de começar

Antes de começar, certifique-se de que realizou as seguintes tarefas:

  • Ative a API Google Kubernetes Engine.
  • Ative a API Google Kubernetes Engine
  • Se quiser usar a CLI gcloud para esta tarefa, instale-a e, em seguida, inicialize-a. Se instalou anteriormente a CLI gcloud, execute o comando gcloud components update para obter a versão mais recente. As versões anteriores da CLI gcloud podem não suportar a execução dos comandos neste documento.

Peça Spot Pods nas suas cargas de trabalho do Autopilot

Para pedir que os seus Pods sejam executados como Spot Pods, use a etiqueta cloud.google.com/gke-spot=true num nodeSelector ou numa nodeAffinity na especificação do seu Pod. O GKE aprovisiona automaticamente nós que podem executar pods spot.

Os Spot Pods podem ser desalojados e terminados em qualquer altura, por exemplo, se os recursos de computação forem necessários noutro local em Google Cloud. Quando ocorre uma rescisão, os Spot Pods no nó de rescisão podem pedir um período de tolerância de até 15 segundos antes da rescisão, que é concedido com base no melhor esforço, especificando o campo terminationGracePeriodSeconds.

O período de tolerância máximo concedido aos Spot Pods durante a preempção é de 15 segundos. Pedir mais de 15 segundos em terminationGracePeriodSeconds não concede mais de 15 segundos durante a preempção. Na expulsão, o seu pod recebe o sinal SIGTERM e deve tomar medidas para encerrar durante o período de tolerância.

Para o Autopilot, o GKE também marca automaticamente os nós criados para executar pods Spot e modifica essas cargas de trabalho com a tolerância correspondente. A restrição impede que os pods padrão sejam agendados em nós que executam pods de instância de custo reduzido.

Use um nodeSelector para exigir pods spot

Pode usar um nodeSelector para exigir Spot Pods numa implementação. Adicione a etiqueta cloud.google.com/gke-spot=true à sua implementação, como no seguinte exemplo:

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

Use a afinidade de nós para pedir pods spot

Em alternativa, pode usar a afinidade de nós para pedir Spot Pods. A afinidade de nós oferece uma forma mais extensível de selecionar nós para executar as suas cargas de trabalho. Por exemplo, pode combinar vários critérios de seleção para ter um controlo mais preciso sobre onde os seus pods são executados. Quando usa a afinidade de nós para pedir Spot Pods, pode especificar o tipo de afinidade de nós a usar, da seguinte forma:

  • requiredDuringSchedulingIgnoredDuringExecution: tem de usar Spot Pods.
  • preferredDuringSchedulingIgnoredDuringExecution: use Spot Pods com base no melhor esforço.

Para usar a afinidade de nós para exigir Spot Pods numa implementação, adicione a seguinte regra nodeAffinity ao manifesto de implementaçã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

Pedir Spot Pods com base no melhor esforço

Para usar a afinidade de nós para pedir Spot Pods com base no melhor esforço, use preferredDuringSchedulingIgnoredDuringExecution. Quando pede Spot Pods numa base preferencial, o GKE agenda os seus pods com base na seguinte ordem:

  1. Nós existentes que podem executar Spot Pods com capacidade atribuível disponível.
  2. Nós padrão existentes com capacidade atribuível disponível.
  3. Novos nós que podem executar pods de spot, se os recursos de computação estiverem disponíveis.
  4. Novos nós padrão.

Uma vez que o GKE prefere nós padrão existentes com capacidade atribuível à criação de novos nós para pods de spot, pode reparar que mais pods são executados como pods padrão do que como pods de spot, o que impede que tire total partido dos preços mais baixos dos pods de spot.

Pedidos de agrupamentos preemptivos

Os clusters do Autopilot suportam pedidos de pods preemptíveis através do seletor cloud.google.com/gke-preemptible. Os pods que usam este seletor são migrados automaticamente para pods de spot, e o seletor é alterado para cloud.google.com/gke-spot.

Encontre e elimine pods terminados

Durante o encerramento gracioso do pod, o kubelet atribui um estado Failed e um motivo Shutdown aos pods encerrados. Quando o número de pods terminados atinge um limite de 1000, a recolha de lixo limpa os pods. Também pode eliminar manualmente os pods encerrados através do seguinte comando:

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

Impeça que as cargas de trabalho usem pods do Spot

Se tiver Spot Pods existentes que quer atualizar para serem executados como Pods padrão, pode usar um dos seguintes métodos:

  • Recrie a carga de trabalho: elimine a implementação, remova as linhas no manifesto que selecionam pods Spot e, em seguida, aplique o manifesto de implementação atualizado ao cluster.
  • Edite a carga de trabalho: edite a especificação de implementação enquanto os pods estão a ser executados no cluster.

Com ambos os métodos, pode sentir pequenas interrupções na carga de trabalho.

Recrie a carga de trabalho

Os passos seguintes mostram como eliminar a implementação existente e aplicar um manifesto atualizado ao cluster. Também pode usar estes passos para outros tipos de cargas de trabalho do Kubernetes, como Jobs.

Para garantir que o GKE coloca os pods atualizados no tipo correto de nó, tem de exportar o estado existente da carga de trabalho do servidor da API Kubernetes para um ficheiro e editar esse ficheiro.

  1. Escreva a especificação da carga de trabalho num ficheiro YAML:

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

    Substitua DEPLOYMENT_NAME pelo nome da sua implementaçã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 ficheiro YAML num editor de texto:

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

    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
    

    Tem de remover a tolerância e o nodeSelector para indicar ao GKE que os pods têm de ser executados em nós a pedido em vez de em nós Spot.

  4. Guarde o manifesto atualizado.

  5. Elimine e volte a aplicar o manifesto de implementação ao cluster:

    kubectl replace -f DEPLOYMENT_NAME-on-demand.yaml
    

    A duração desta operação depende do número de pods que o GKE tem de terminar e limpar.

Edite a carga de trabalho no local

Os passos seguintes mostram como editar uma implementação em execução no local para indicar ao GKE que os pods têm de ser executados em nós a pedido. Também pode usar estes passos para outros tipos de cargas de trabalho do Kubernetes, como Jobs.

Tem de editar o objeto de carga de trabalho na API Kubernetes porque o GKE adiciona automaticamente uma tolerância para pods de spot à especificação da carga de trabalho durante a admissão da carga de trabalho.

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

    kubectl edit deployment/DEPLOYMENT_NAME
    

    Substitua DEPLOYMENT_NAME pelo nome da implementação. 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, elimine o seletor de nós ou a regra de afinidade de nós para os Spot Pods e a tolerância que o GKE adicionou ao manifesto, como no exemplo seguinte:

    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. Guarde o manifesto atualizado e feche o editor de texto. A configuração do objeto atualizada indica ao GKE que os pods têm de ser executados em nós a pedido. O GKE recria os pods para os colocar em novos nós a pedido.

Verifique se as cargas de trabalho são executadas em nós a pedido

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

  • Inspecione a carga de trabalho:

    kubectl describe deployment DEPLOYMENT_NAME
    

O resultado não apresenta uma entrada para cloud.google.com/gke-spot no campo spec.tolerations.

O que se segue?