Provisionar capacidade de computação extra para escalonamento rápido de pods


Nesta página, mostramos como reservar capacidade de computação extra nos clusters do Google Kubernetes Engine (GKE) para que suas cargas de trabalho possam ser escalonadas rapidamente durante eventos de alto tráfego sem esperar que novos nós sejam iniciados. Use estas instruções para reservar sobrecarga de computação de forma consistente e disponível ou antes de eventos específicos.

Por que o provisionamento de capacidade extra é útil

Os clusters do GKE Autopilot e os clusters padrão com provisionamento automático de nós criam novos nós quando não há nós com capacidade para executar novos pods. Cada novo nó leva aproximadamente de 80 a 120 segundos para ser inicializado. O GKE aguarda até que o nó seja iniciado antes de colocar pods pendentes no novo nó. Depois disso, os pods podem ser inicializados. Em clusters padrão, é possível criar um novo pool de nós manualmente, com a capacidade extra necessária para executar novos pods. Esta página se aplica a clusters que usam um mecanismo de escalonamento automático de nós, como o Autopilot ou o provisionamento automático de nós.

Em alguns casos, convém inicializar seus pods mais rapidamente durante eventos de escalonamento vertical. Por exemplo, se você estiver lançando uma nova expansão para seu famoso jogo multijogador de serviço ao vivo, os tempos de inicialização mais rápidos para os pods do servidor do jogo podem reduzir os tempos de fila para que os jogadores façam login no dia do lançamento. Como outro exemplo, se você executar uma plataforma de comércio eletrônico e estiver planejando uma oferta relâmpago por tempo limitado, espera-se bursts de tráfego durante a oferta.

O provisionamento de capacidade extra é compatível com o bursting de pods, o que permite que os pods usem temporariamente recursos solicitados por outros pods no nó, se essa capacidade estiver disponível e não for usada por outros pods. Para usar o bursting, defina limites de recursos mais altos do que as solicitações de recursos ou não defina limites de recursos. Para mais detalhes, acesse Configurar o bursting de pods no GKE.

Como funciona o provisionamento de capacidade extra no GKE

Para provisionar capacidade extra, é possível usar Kubernetes PriorityClasses do Kubernetes e pods de marcador. Uma PriorityClass permite dizer ao GKE que algumas cargas de trabalho têm prioridade mais baixa do que outras. É possível implantar pods de marcador que usam uma PriorityClass de baixa prioridade e solicitar a capacidade de computação que você precisa reservar. O GKE adiciona capacidade ao cluster criando novos nós para acomodar os pods de marcador.

Quando as cargas de trabalho de produção são ampliadas, o GKE remove os pods de marcador de prioridade mais baixa e programa as novas réplicas dos pods de produção (que usam uma PriorityClass de prioridade mais alta) no lugar deles. Se você tiver vários pods de baixa prioridade com níveis de prioridade diferentes, o GKE removerá os pods de menor prioridade primeiro.

Métodos de provisionamento de capacidade

Dependendo do seu caso de uso, é possível provisionar capacidade extra nos clusters do GKE de uma das seguintes maneiras:

  • Provisionamento consistente de capacidade: use uma implantação para criar uma quantidade específica de pods de marcador de prioridade baixa, que são executados constantemente no cluster. Quando o GKE remove esses pods para executar suas cargas de trabalho de produção, o controlador de implantação garante que o GKE provisione mais capacidade para recriar os pods de baixa prioridade removidos. Esse método fornece sobrecarga de capacidade consistente em vários eventos de aumento e redução até que você exclua a implantação.
  • Provisionamento de capacidade de uso único: use um job para executar uma quantidade específica de pods de marcador paralelo de baixa prioridade por um período específico. Quando esse tempo tiver passado ou quando o GKE remover todas as réplicas do job, a capacidade reservada deixará de estar disponível. Esse método fornece uma quantidade específica de capacidade disponível por um período específico.

Preços

No GKE Autopilot, você é cobrado pelas solicitações de recursos dos pods em execução, incluindo as cargas de trabalho de baixa prioridade que são implantadas. Para mais detalhes, consulte Preços do Autopilot.

No GKE Standard, você é cobrado pelas VMs subjacentes do Compute Engine provisionadas pelo GKE, independentemente de os pods usarem essa capacidade. Para mais detalhes, consulte Preços padrão.

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 Google Cloud CLI para essa tarefa, instale e, em seguida, inicialize a CLI gcloud. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando gcloud components update.
  • Verifique se você tem um cluster do GKE Autopilot ou um cluster do GKE Standard com provisionamento automático de nós ativado.
  • Leia Considerações sobre o provisionamento de capacidade para garantir que você escolha os valores apropriados nas solicitações de capacidade.

Criar uma PriorityClass

Para usar um dos métodos descritos em Métodos de provisionamento de capacidade, primeiro você precisa criar as seguintes PriorityClasses:

  • DefaultClass padrão: uma PriorityClass padrão global que é atribuída a qualquer pod que não define explicitamente uma PriorityClass diferente na especificação do pod. Os pods com essa PriorityClass padrão podem remover pods que usam uma PriorityClass mais baixa.
  • PriorityClass baixa: uma PriorityClass não padrão definida como a prioridade mais baixa possível no GKE. Os pods com essa PriorityClass podem ser removidos para executar pods com PriorityClasses mais altas.
  1. Salve o seguinte manifesto como priorityclasses.yaml:

    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata:
      name: low-priority
    value: -10
    preemptionPolicy: Never
    globalDefault: false
    description: "Low priority workloads"
    ---
    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata:
      name: default-priority
    value: 0
    preemptionPolicy: PreemptLowerPriority
    globalDefault: true
    description: "The global default priority."
    

    Esse manifesto inclui os seguintes campos:

    • preemptionPolicy: especifica se os pods que usam uma PriorityClass podem remover pods de prioridade mais baixa. A PriorityClass low-priority usa Never, e a PriorityClass default usa PreemptLowerPriority.
    • value: a prioridade dos pods que usam a PriorityClass. A PriorityClass default usa 0. A PriorityClass low-priority usa -1. No Autopilot, é possível definir isso como qualquer valor menor que a prioridade PriorityClass default.

      Por padrão, se você definir esse valor como menos de -10, os pods que usam essa classe prioritária não acionarão a criação de novos nós e permanecerão em Pendente.

      Se quiser ajuda para decidir valores adequados para a prioridade, consulte Escolher uma prioridade.

    • globalDefault: especifica se o GKE atribui ou não a PriorityClass aos pods que não definem explicitamente uma PriorityClass na especificação do pod. A PriorityClass low-priority usa false, e a PriorityClass default usa true.

  2. Aplique o manifesto:

    kubectl apply -f priorityclasses.yaml
    

Provisionar capacidade extra de computação

As seções a seguir mostram um exemplo em que você provisiona capacidade para um único evento ou de forma consistente ao longo do tempo.

Usar uma implantação para provisionamento de capacidade consistente

  1. Salve o seguinte manifesto como capacity-res-deployment.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: capacity-res-deploy
    spec:
      replicas: 10
      selector:
        matchLabels:
          app: reservation
      template:
        metadata:
          labels:
            app: reservation
        spec:
          priorityClassName: low-priority
          terminationGracePeriodSeconds: 0
          containers:
          - name: ubuntu
            image: ubuntu
            command: ["sleep"]
            args: ["infinity"]
            resources:
              requests:
                cpu: 500m
                memory: 500Mi
    

    Esse manifesto inclui os seguintes campos:

    • spec.replicas: altere esse valor para atender aos seus requisitos.
    • spec.resources.requests: altere as solicitações de CPU e memória para atender aos seus requisitos. Use as orientações em Escolher o dimensionamento da capacidade para ajudar você a decidir os valores de solicitação apropriados.
    • spec.containers.command e spec.containers.args: diga aos pods para permanecerem ativos até serem removidos pelo GKE.
  2. Aplique o manifesto:

    kubectl apply -f capacity-res-deployment.yaml
    
  3. Receba o status do pod:

    kubectl get pods -l app=reservation
    

    Aguarde até que todas as réplicas tenham o status Running.

Usar um job para provisionamento de capacidade de evento único

  1. Salve o seguinte manifesto como capacity-res-job.yaml:

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: capacity-res-job
    spec:
      parallelism: 4
      backoffLimit: 0
      template:
        spec:
          priorityClassName: low-priority
          terminationGracePeriodSeconds: 0
          containers:
          - name: ubuntu-container
            image: ubuntu
            command: ["sleep"]
            args: ["36000"]
            resources:
              requests:
                cpu: "16"
          restartPolicy: Never
    

    Esse manifesto inclui os seguintes campos:

    • spec.parallelism: altere para o número de jobs que você quer executar em paralelo para reservar capacidade.
    • spec.backoffLimit: 0: impede que o controlador do job recrie jobs removidos.
    • template.spec.resources.requests: altere as solicitações de CPU e memória para atender aos seus requisitos. Use as orientações em Considerações para ajudar você a decidir sobre os valores apropriados.
    • template.spec.containers.command e template.spec.containers.args: instrua os jobs a permanecer ativos pelo período de tempo, em segundos, durante os quais você precisa da capacidade extra.
  2. Aplique o manifesto:

    kubectl apply -f capacity-res-job.yaml
    
  3. Ver o status da tarefa:

    kubectl get jobs
    

    Aguarde até que todos os jobs tenham o status Running.

Testar o provisionamento de capacidade e a remoção

Para verificar se o provisionamento de capacidade funciona conforme o esperado, faça o seguinte:

  1. No terminal, observe o status das cargas de trabalho de provisionamento de capacidade:

    1. Para implantações, execute o seguinte comando:

      kubectl get pods --label=app=reservation -w
      
    2. Para jobs, execute o seguinte comando:

      kubectl get Jobs -w
      
  2. Abra uma nova janela do terminal e faça o seguinte:

    1. Salve o seguinte manifesto como test-deployment.yaml:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: helloweb
        labels:
          app: hello
      spec:
        replicas: 5
        selector:
          matchLabels:
            app: hello
            tier: web
        template:
          metadata:
            labels:
              app: hello
              tier: web
          spec:
            containers:
            - name: hello-app
              image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
              ports:
              - containerPort: 8080
              resources:
                requests:
                  cpu: 400m
                  memory: 400Mi
      
    2. Aplique o manifesto:

      kubectl apply -f test-deployment.yaml
      
  3. Na janela do terminal original, observe que o GKE encerra algumas das cargas de trabalho de provisionamento de capacidade para programar suas novas réplicas, semelhante ao exemplo a seguir:

    NAME                                         READY   STATUS    RESTARTS   AGE
    capacity-res-deploy-6bd9b54ffc-5p6wc         1/1     Running   0          7m25s
    capacity-res-deploy-6bd9b54ffc-9tjbt         1/1     Running   0          7m26s
    capacity-res-deploy-6bd9b54ffc-kvqr8         1/1     Running   0          2m32s
    capacity-res-deploy-6bd9b54ffc-n7zn4         1/1     Running   0          2m33s
    capacity-res-deploy-6bd9b54ffc-pgw2n         1/1     Running   0          2m32s
    capacity-res-deploy-6bd9b54ffc-t5t57         1/1     Running   0          2m32s
    capacity-res-deploy-6bd9b54ffc-v4f5f         1/1     Running   0          7m24s
    helloweb-85df88c986-zmk4f                    0/1     Pending   0          0s
    helloweb-85df88c986-lllbd                    0/1     Pending   0          0s
    helloweb-85df88c986-bw7x4                    0/1     Pending   0          0s
    helloweb-85df88c986-gh8q8                    0/1     Pending   0          0s
    helloweb-85df88c986-74jrl                    0/1     Pending   0          0s
    capacity-res-deploy-6bd9b54ffc-v6dtk   1/1     Terminating   0          2m47s
    capacity-res-deploy-6bd9b54ffc-kvqr8   1/1     Terminating   0          2m47s
    capacity-res-deploy-6bd9b54ffc-pgw2n   1/1     Terminating   0          2m47s
    capacity-res-deploy-6bd9b54ffc-n7zn4   1/1     Terminating   0          2m48s
    capacity-res-deploy-6bd9b54ffc-2f8kx   1/1     Terminating   0          2m48s
    ...
    helloweb-85df88c986-lllbd              0/1     Pending       0          1s
    helloweb-85df88c986-gh8q8              0/1     Pending       0          1s
    helloweb-85df88c986-74jrl              0/1     Pending       0          1s
    helloweb-85df88c986-zmk4f              0/1     Pending       0          1s
    helloweb-85df88c986-bw7x4              0/1     Pending       0          1s
    helloweb-85df88c986-gh8q8              0/1     ContainerCreating   0          1s
    helloweb-85df88c986-zmk4f              0/1     ContainerCreating   0          1s
    helloweb-85df88c986-bw7x4              0/1     ContainerCreating   0          1s
    helloweb-85df88c986-lllbd              0/1     ContainerCreating   0          1s
    helloweb-85df88c986-74jrl              0/1     ContainerCreating   0          1s
    helloweb-85df88c986-zmk4f              1/1     Running             0          4s
    helloweb-85df88c986-lllbd              1/1     Running             0          4s
    helloweb-85df88c986-74jrl              1/1     Running             0          5s
    helloweb-85df88c986-gh8q8              1/1     Running             0          5s
    helloweb-85df88c986-bw7x4              1/1     Running             0          5s
    

    Esta saída mostra que a nova implantação levou cinco segundos para mudar de "Pendente" para "Em execução".

Considerações sobre o provisionamento de capacidade

Provisionamento consistente de capacidade

  • Avalie quantas réplicas de pods de marcador são necessárias e o tamanho das solicitações em cada réplica. As réplicas de baixa prioridade precisam solicitar pelo menos a mesma capacidade da maior carga de trabalho de produção. Assim, essas cargas de trabalho podem caber na capacidade reservada pela carga de trabalho de baixa prioridade.
  • Se você opera um grande número de cargas de trabalho de produção em escala, considere definir as solicitações de recursos dos pods de marcador como valores que provisionam capacidade suficiente para executar várias cargas de trabalho de produção, em vez de apenas uma.

Provisionamento de capacidade de uso único

  • Defina a duração dos jobs do marcador como o tempo restante durante o qual você precisa de mais capacidade. Por exemplo, se você quiser a capacidade adicional para um dia de lançamento de jogo de 24 horas, defina a duração como 86.400 segundos. Isso garante que a capacidade provisionada não dure mais tempo do que o necessário.
  • Defina uma janela de manutenção para o mesmo período em que você está reservando a capacidade. Isso evita que jobs de baixa prioridade sejam removidos durante o upgrade do nó. Definir uma janela de manutenção também é uma prática recomendável quando você estiver antecipando a alta demanda da sua carga de trabalho.
  • Se você opera um grande número de cargas de trabalho de produção em escala, considere definir as solicitações de recursos dos jobs do marcador como valores que provisionam capacidade suficiente para executar várias cargas de trabalho de produção, em vez de apenas uma.

A capacidade é provisionada apenas para um único evento de escalonamento. Se você escalonar verticalmente e usar a capacidade e depois reduzir, essa capacidade não estará mais disponível para outro evento de escalonamento vertical. Se você antecipar vários eventos de aumento e redução, use o método de reserva consistente de capacidade e ajuste o tamanho da reserva conforme necessário. Por exemplo, aumentar as solicitações do pod antes de um evento e diminuir ou zerar depois.

Escolher uma prioridade

Defina a prioridade nas suas PriorityClasses como menos de 0.

É possível definir várias PriorityClasses no cluster para usar com cargas de trabalho com requisitos diferentes. Por exemplo, você pode criar uma PriorityClass com prioridade -10 para provisionamento de capacidade de uso único e uma PriorityClass com prioridade -9 para provisionamento consistente de capacidade. Em seguida, você pode provisionar capacidade consistente usando a PriorityClass com prioridade -9 e, quando quiser mais capacidade para um evento especial, poderá implantar novos jobs que usam a PriorityClass com prioridade -10. Primeiro, o GKE remove as cargas de trabalho de menor prioridade.

Também é possível usar outras PriorityClasses para executar cargas de trabalho que não são de produção de baixa prioridade que executam tarefas reais, como cargas de trabalho em lote tolerantes a falhas, com uma prioridade menor que as cargas de trabalho de produção, mas maior que os pods de marcador. Por exemplo, -5.

Escolher o tamanho da capacidade

Defina as contagens de réplicas e as solicitações de recursos da carga de trabalho de marcadores como maior ou igual à capacidade necessária para as cargas de trabalho de produção ao escalonar verticalmente.

A capacidade total provisionada é baseada no número de pods de marcador que você implanta e nas solicitações de recursos de cada réplica. Se o escalonamento vertical exigir mais capacidade do que o GKE provisionou para os pods de marcador, algumas de suas cargas de trabalho de produção permanecerão em Pending até que o GKE possa provisionar mais capacidade.

A seguir