Escalonar cargas de trabalho do GKE para e de zero usando o HPA

Neste tutorial, mostramos como otimizar a utilização de recursos no Google Kubernetes Engine (GKE) configurando cargas de trabalho para escalonar automaticamente para zero réplicas quando estiverem inativas e escalonar novamente à medida que a demanda aumenta. Essa abordagem integra o escalonador automático horizontal de pods (HPA) com a infraestrutura de escalonamento automático gerenciado do GKE para gerenciar o escalonamento com base em métricas externas.

Configure a implantação para escalonar até zero definindo o valor do campo minReplicas como 0 e definindo uma métrica com o tipo External ou Object no manifesto do HPA. O GKE monitora essas métricas usando o recurso personalizado AutoscalingMetric, que ajuda a garantir o gerenciamento eficiente de recursos para seus aplicativos.

Com essa configuração, não é necessário usar adaptadores de métricas de terceiros, como o KEDA, para escalonar cargas de trabalho do GKE. Essa solução gerencia a ingestão de métricas e as recomendações de escalonamento diretamente no plano de controle do GKE, reduzindo a sobrecarga de gerenciamento do cluster.

Neste tutorial, você vai implantar um aplicativo de worker assíncrono de exemplo que processa mensagens de uma fila do Pub/Sub. Configure um escalonador automático horizontal de pods para monitorar a profundidade da fila (pubsub.googleapis.com:num_undelivered_messages) usando um recurso personalizado AutoscalingMetric:

  • Quando as mensagens chegam à assinatura:o GKE aumenta a escala dos pods de worker para processar a fila.
  • Quando a fila está vazia:o GKE reduz automaticamente o escalonamento da implantação do worker para zero réplicas.

Este tutorial é destinado a desenvolvedores de aplicativos, administradores e operadores de plataforma e DevOps que querem otimizar o uso de recursos no GKE escalonando cargas de trabalho para zero quando elas estão inativas.

Considerações

Antes de configurar as cargas de trabalho para escalonar até zero, revise as seguintes considerações:

  • Para escalonar cargas de trabalho de e para zero usando o HPA, o plano de controle e os nós do cluster do GKE precisam executar a versão 1.37 ou mais recente em clusters novos e atualizados. Se você usa um cluster atual, verifique a versão dele ou faça upgrade do cluster ou dos nós para a versão 1.37 ou mais recente.
  • O manifesto do HPA precisa usar a configuração apiVersion: autoscaling/v2 para oferecer suporte à configuração minReplicas: 0 e às métricas externas.
  • Antes de fazer downgrade dos pools de nós para uma versão anterior à 1.37, atualize todos os manifestos do HPA configurados para escalonar de e para zero definindo o campo minReplicas como 1 ou maior. Versões anteriores à 1.37 não são compatíveis com a configuração minReplicas: 0, o que pode fazer com que as cargas de trabalho fiquem presas em zero réplicas.
  • É preciso configurar pelo menos uma métrica External ou Object (como uma profundidade de fila) no escalonador automático horizontal de pods. O GKE não pode coletar métricas de CPU ou memória (Resource) quando uma carga de trabalho tem zero pods. Portanto, as métricas de recursos sozinhas não podem acionar o escalonamento vertical de zero.
  • O AutoscalingMetric, o HorizontalPodAutoscaler e a implantação de destino precisam estar no mesmo namespace do Kubernetes.

Antes de começar

  1. Instale a CLI do Google Cloud.

  2. Configure a CLI gcloud para usar sua identidade federada.

    Para mais informações, consulte Fazer login na CLI gcloud com sua identidade federada.

  3. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  4. Crie ou selecione um Google Cloud projeto.

    Funções necessárias para selecionar ou criar um projeto

    • Selecionar um projeto: não é necessário um papel específico do IAM para selecionar um projeto. Você pode escolher qualquer projeto em que tenha recebido um papel.
    • Criar um projeto: para criar um projeto, é necessário ter o papel de Criador de projetos (roles/resourcemanager.projectCreator), que contém a permissão resourcemanager.projects.create. Saiba como conceder papéis.
    • Crie um projeto do Google Cloud :

      gcloud projects create PROJECT_ID

      Substitua PROJECT_ID por um nome para o projeto Google Cloud que você está criando.

    • Selecione o projeto Google Cloud que você criou:

      gcloud config set project PROJECT_ID

      Substitua PROJECT_ID pelo nome do projeto do Google Cloud .

  5. Verifique se o faturamento está ativado para o projeto do Google Cloud .

  6. Ative as APIs GKE e Pub/Sub:

    Funções necessárias para ativar APIs

    Para ativar APIs, você precisa da permissão serviceusage.services.enable. Se você criou o projeto, provavelmente já tem essa permissão com o papel de Proprietário (roles/owner). Caso contrário, é possível receber essa permissão com o papel de Administrador do Service Usage (roles/serviceusage.serviceUsageAdmin). Saiba como conceder papéis.

    gcloud services enable container.googleapis.com pubsub.googleapis.com

Funções exigidas

Para conseguir as permissões necessárias a fim de concluir o tutorial, peça ao administrador para conceder a você os seguintes papéis do IAM no projeto:

Para mais informações sobre a concessão de papéis, consulte Gerenciar o acesso a projetos, pastas e organizações.

Também é possível conseguir as permissões necessárias usando papéis personalizados ou outros papéis predefinidos.

Configurar o ambiente

Para simplificar, os comandos neste tutorial criam todos os recursos (o cluster do GKE e o tópico e a assinatura do Pub/Sub) em um único projeto Google Cloud (PROJECT_ID).

Para configurar o ambiente, siga estas etapas:

  1. Defina as variáveis de ambiente:

    export PROJECT_ID=PROJECT_ID
    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format 'get(projectNumber)')
    export LOCATION=LOCATION
    

    Substitua:

    • PROJECT_ID: o Google Cloud ID do projeto.
    • LOCATION: a região ou zona em que você quer criar o cluster do GKE, como us-central1. Para clusters do Autopilot, especifique uma região.
  2. Crie um cluster do GKE executando a versão 1.37 ou mais recente com a Federação de Identidade da Carga de Trabalho para GKE ativada. Recomendamos que você use um cluster do Autopilot para ter uma experiência totalmente gerenciada do Kubernetes e maximizar a economia de custos quando as cargas de trabalho forem reduzidas a zero. Para escolher o modo de operação mais adequado para suas cargas de trabalho, consulte Escolher um modo de operação do GKE:

    Piloto automático

    Criar um cluster do Autopilot:

    gcloud container clusters create-auto scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION}
    

    A Federação de Identidade da Carga de Trabalho para GKE é ativada por padrão nos clusters do Autopilot.

    Padrão

    Crie um cluster Standard com a federação de identidade da carga de trabalho para GKE ativada:

    gcloud container clusters create scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION} \
        --workload-pool=${PROJECT_ID}.
    
  3. Configure kubectl para se comunicar com o cluster:

    gcloud container clusters get-credentials scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION}
    

Crie recursos do Pub/Sub

Este tutorial usa a profundidade da fila do Pub/Sub como um exemplo de fonte de métrica externa.

Para criar um tópico e uma assinatura do Pub/Sub, siga estas etapas:

  1. Crie um tópico do Pub/Sub:

    gcloud pubsub topics create my-worker-topic \
        --project=${PROJECT_ID}
    
  2. Crie uma assinatura anexada ao tópico:

    gcloud pubsub subscriptions create my-worker-subscription \
        --topic=my-worker-topic \
        --project=${PROJECT_ID}
    

Configurar a Federação de Identidade da Carga de Trabalho para GKE

Configure a Federação de Identidade da Carga de Trabalho para GKE para permitir que seu aplicativo de worker se autentique com Google Cloud APIs e consuma mensagens do Pub/Sub.

O GKE processa automaticamente a autenticação com o Cloud Monitoring para recursos AutoscalingMetric no mesmo projeto. Para saber mais sobre como definir métricas para escalonamento automático, consulte Buscar métricas personalizadas ou externas do Cloud Monitoring.

Para configurar a Federação de Identidade da Carga de Trabalho para GKE para a sua carga de trabalho do worker, siga estas etapas:

  1. Crie uma conta de serviço do Kubernetes para o aplicativo de worker no namespace default:

    kubectl create serviceaccount async-worker-sa \
        --namespace default
    
  2. Conceda o papel roles/pubsub.subscriber à conta de serviço do Kubernetes para que o aplicativo possa receber mensagens da sua assinatura do Pub/Sub:

    gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
        --role=roles/pubsub.subscriber \
        --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}./subject/ns/default/sa/async-worker-sa
    

Para mais informações, consulte Configurar aplicativos para usar a Federação de Identidade da Carga de Trabalho para GKE.

Crie a implantação de exemplo

Antes de criar um objeto HPA, é preciso criar a carga de trabalho que ele vai monitorar.

Para criar a implantação de exemplo, siga estas etapas:

  1. Salve o seguinte manifesto como async-worker.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: async-worker
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: async-worker
      template:
        metadata:
          labels:
            app: async-worker
        spec:
          containers:
          - name: async-worker
            image: nginx:latest
            ports:
            - containerPort: 80
            resources:
              limits:
                memory: 100Mi
              requests:
                cpu: 50m
                memory: 100Mi
    
  2. Aplique a implantação async-worker.yaml:

    kubectl apply -f async-worker.yaml
    

Configurar uma carga de trabalho para escalonar de e para zero

Nesta seção, você vai configurar a implantação do async-worker para reduzir escala vertical a zero quando a fila do Pub/Sub estiver vazia e aumentar novamente à medida que novas mensagens chegarem.

Criar o recurso AutoscalingMetric

Para definir o indicador externo monitorado pelo GKE, crie o recurso personalizado AutoscalingMetric. No exemplo de manifesto a seguir, as consultas de métrica do Cloud Monitoring mostram o número de mensagens não entregues do Pub/Sub na assinatura my-worker-subscription.

Para criar o recurso AutoscalingMetric, siga estas etapas:

  1. Salve o seguinte manifesto como o arquivo pubsub-metric.yaml:

    apiVersion: autoscaling.gke.io/v1beta1
    kind: AutoscalingMetric
    metadata:
      name: pubsub-queue-depth
      namespace: default
    spec:
      metrics:
      - promql:
          name: pubsub-undelivered
          query: >
              {
                "pubsub.googleapis.com/subscription/num_undelivered_messages",
                subscription_id="my-worker-subscription"
              }
    
  2. Aplique o manifesto pubsub-metric.yaml:

    kubectl apply -f pubsub-metric.yaml
    
  3. Verifique o status da métrica e recupere o identificador dela:

    kubectl describe autoscalingmetric pubsub-queue-depth
    

    Na seção Status da saída, verifique se não há erros listados e anote o valor Hpa Name no formato autoscaling.gke.io|CUSTOM_RESOURCE_NAME|METRIC_NAME. Você vai referenciar esse identificador de métrica externa ao criar o objeto HorizontalPodAutoscaler na próxima seção. Se a seção Status informar erros de configuração ou se as métricas não forem recuperadas conforme o esperado, consulte Resolver problemas com métricas buscadas para escalonamento automático.

Configurar o escalonador automático horizontal de pods

Para configurar o comportamento do escalonamento automático, crie um recurso HorizontalPodAutoscaler direcionado à implantação.

Para configurar o escalonador automático horizontal de pods, siga estas etapas:

  1. Salve o seguinte manifesto como o arquivo worker-hpa.yaml:

    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: async-worker-hpa
      namespace: default
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: async-worker
      minReplicas: 0
      maxReplicas: 20
      metrics:
      - type: External
        external:
          metric:
            name: autoscaling.gke.io|pubsub-queue-depth|pubsub-undelivered
          target:
            type: AverageValue
            averageValue: "10"
    

    Esse manifesto configura os seguintes campos principais:

    • minReplicas: 0: permite a redução da escala a zero, permitindo que o controlador reduza o escalonamento do Deployment para 0 réplicas quando a demanda cai para zero.
    • type: External: configura uma fonte de métrica externa para que o HPA possa acionar o escalonamento vertical quando a carga de trabalho tiver zero pods.
    • name: autoscaling.gke.io|pubsub-queue-depth|pubsub-undelivered: mapeia o HPA diretamente para o recurso AutoscalingMetric criado na etapa anterior usando o formato de identificador autoscaling.gke.io|CUSTOM_RESOURCE_NAME|METRIC_NAME.
  2. Aplique o manifesto worker-hpa.yaml:

    kubectl apply -f worker-hpa.yaml
    

Verificar o comportamento e as condições de escalonamento para zero

Quando todas as mensagens na assinatura do Pub/Sub são processadas, o escalonador automático horizontal de pods avalia a demanda zero e reduz o escalonamento do Deployment para 0 réplicas.

Para verificar se o escalonador automático horizontal de pods acionou o estado zero, inspecione as condições de status do recurso async-worker-hpa executando o seguinte comando:

kubectl describe hpa async-worker-hpa

O resultado será o seguinte:

Name:             async-worker-hpa
Namespace:        default
Reference:        Deployment/async-worker
Metrics:          ( current / target )
  "autoscaling.gke.io|pubsub-queue-depth|pubsub-undelivered" (external metric):  0 / 10
Min replicas:     0
Max replicas:     20
Deployment pods:  0 current / 0 desired
Conditions:
  Type            Status  Reason               Message
  ----            ------  ------               -------
  AbleToScale     True    SucceededGetScale    the HPA controller was able to get the target's current scale
  ScalingActive   True    ValidMetricFound     the HPA was able to successfully calculate a replica count from external metric
  ScaledToZero    True    ScaledToZero         the HPA has scaled the target resource to 0 replicas due to zero metric demand

Entender a condição ScaledToZero

A condição ScaledToZero indica se o escalonador automático horizontal de pods dimensionou a carga de trabalho para zero réplicas:

  • ScaledToZero: True (Reason: ScaledToZero): indica que o controlador HPA escalonou sua carga de trabalho para 0 réplicas porque a demanda de métricas externas caiu para zero. O HPA permanece ativo (ScalingActive: True) e pesquisa continuamente o GKE para detectar quando a demanda de carga de trabalho aumenta.
  • ScaledToZero: False: indica que a carga de trabalho foi escalonada para uma ou mais réplicas.

Se você escalonar manualmente uma implantação para zero réplicas, por exemplo, com o comando kubectl scale --replicas=0, o HPA vai pausar o escalonamento automático (ScalingActive: False) para evitar mudanças conflitantes. Para retomar o escalonamento automático, reduza a implantação para uma ou mais réplicas (kubectl scale deployment async-worker --replicas=1).

Para cenários de solução de problemas em que as cargas de trabalho não conseguem reduzir a zero ou escalonar verticalmente de zero, consulte Resolver problemas de escalonamento de cargas de trabalho do GKE para e de zero usando o HPA. Se o escalonador automático de pod horizontal informar métricas externas ausentes ou inválidas, consulte Resolver problemas de métricas buscadas para escalonamento automático.

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados neste tutorial, siga estas etapas:

  1. Exclua o cluster do GKE:

    gcloud container clusters delete scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION}
    
  2. Exclua o tópico e a assinatura do Pub/Sub:

    gcloud pubsub subscriptions delete my-worker-subscription \
        --project=${PROJECT_ID}
    gcloud pubsub topics delete my-worker-topic \
        --project=${PROJECT_ID}
    

A seguir