Configurar buffers de capacidade

Os buffers de capacidade melhoram a capacidade de resposta e a confiabilidade das cargas de trabalho críticas gerenciando de forma proativa a capacidade extra do cluster e os estados suspensos da capacidade pré-provisionada e pré-configurada usando uma definição de recurso personalizada (CRD) CapacityBuffer do Kubernetes. Com os buffers de capacidade, é possível definir explicitamente uma quantidade específica de capacidade de nó não utilizada no cluster. Essa capacidade reservada ajuda a reduzir o tempo de programação do pod.

Quando uma carga de trabalho de alta prioridade precisa ser escalonar verticalmente rapidamente, a nova carga de trabalho pode usar a capacidade vazia imediatamente sem esperar pelo provisionamento de nós. Essa abordagem minimiza a latência e evita a disputa de recursos durante picos repentinos de demanda.

Esta página oferece métodos para configurar buffers de capacidade: um buffer fixo de réplicas, um buffer de limites de recursos e um buffer baseado em porcentagem.

Antes de começar

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

  • Ative 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 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.
  • Crie ou tenha acesso a um cluster do GKE na versão 1.35.2-gke.1842000 para buffers ativos e na versão 1.36.0-gke.2253000 ou mais recente para buffers em espera.
  • Ative o provisionamento automático de nós nos clusters padrão. Nos clusters do Autopilot, o provisionamento automático de nós já está ativado. O provisionamento automático de nós é opcional, mas recomendado para buffers ativos e obrigatório para buffers em espera.

Criar objetos do Kubernetes de pré-requisito

Para configurar um CapacityBuffer, você precisa de um namespace que contenha todos os objetos necessários (o próprio CapacityBuffer e recursos adicionais, como um PodTemplate ou uma carga de trabalho). O PodTemplate e o CapacityBuffer precisam estar no mesmo namespace. É possível criar um namespace ou usar um já existente, incluindo o namespace default.

Dependendo do tipo de CapacityBuffer que você está configurando, também é necessário um dos seguintes itens:

  • PodTemplate: define os requisitos de recursos para uma única unidade de capacidade de buffer. A configuração especificada no objeto CapacityBuffer faz referência ao modelo de pod.
  • Carga de trabalho: uma carga de trabalho atual referenciada no objeto CapacityBuffer. Este guia usa um objeto de implantação como exemplo de carga de trabalho, mas os buffers de capacidade são compatíveis com qualquer um dos seguintes tipos de recursos:

    • Implantação
    • ReplicaSet
    • StatefulSet
    • ReplicationController
    • Job
    • CustomResourceDefinitions (CRDs) que implementam o sub-recurso scale.

Esta seção fornece exemplos desses objetos. Se você já tiver uma carga de trabalho que quer configurar com um buffer de capacidade, acesse Aplicar um buffer de capacidade.

Para criar um exemplo de carga de trabalho do Kubernetes, siga estas etapas:

  1. Salve o seguinte manifesto como namespace.yaml:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: capacity-buffer-example
      labels:
        name: capacity-buffer-example
    

    Esse manifesto cria um namespace chamado capacity-buffer-example.

  2. Opcional: para usar buffers de capacidade com uma ComputeClass personalizada, salve o manifesto a seguir como custom-compute-class.yaml:

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: ccc-example
      namespace: capacity-buffer-example
    spec:
      # Buffers are also created according to these priorities
      priorities:
      - machineFamily: n4
      - machineFamily: n4d
      - machineFamily: c4
      - machineFamily: c4d
      nodePoolAutoCreation:
        enabled: true
    

    Esse manifesto cria um ComputeClass personalizado que define e controla as prioridades de computação para os nós provisionados pelo GKE. Para saber mais, consulte ComputeClasses personalizadas.

  3. Salve o seguinte manifesto como buffer-pod-template.yaml:

    apiVersion: v1
    kind: PodTemplate
    metadata:
      name: buffer-unit-template
      namespace: capacity-buffer-example # the namespace must be the same namespace as the CapacityBuffer
    template:
      spec:
        terminationGracePeriodSeconds: 0
        containers:
        - name: buffer-container
          image: registry.k8s.io/pause:3.9
          resources:
            requests:
              cpu: "1"
              memory: "1Gi"
            limits:
              cpu: "1"
              memory: "1Gi"
        # Optional: Using buffers with a custom ComputeClass /
        # controls the properties of the provisioned nodes.
        nodeSelector:
          cloud.google.com/compute-class: ccc-example
    

    Esse manifesto cria um PodTemplate que define os requisitos de recursos para uma única unidade de capacidade de buffer (1 de CPU e 1Gi de memória). Essa configuração especifica o tamanho das unidades de capacidade que o GKE provisiona para o buffer. Por exemplo, com esse PodTemplate, o GKE não vai considerar nós com menos de 1 CPU e 1 Gi de recursos disponíveis como parte do buffer, se o cluster for escalonado verticalmente.

  4. Salve o seguinte manifesto como sample-workload-deployment.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: critical-workload-ref
      namespace: capacity-buffer-example # the namespace must be the same namespace as the CapacityBuffer
    spec:
      replicas: 10
      selector:
        matchLabels:
          app: critical-workload
      template:
        metadata:
          labels:
            app: critical-workload
        spec:
          containers:
          - name: busybox
            image: busybox
            command: ["sleep", "3600"]
            resources:
              requests:
                cpu: 100m
          # Optional: Using buffers with a custom ComputeClass /
          # controls the properties of the provisioned nodes.
          nodeSelector:
            cloud.google.com/compute-class: ccc-example
    

    Este manifesto cria um exemplo de implantação com 10 réplicas, que é o objeto de referência para o exemplo de buffer baseado em porcentagem na próxima seção.

  5. Aplique os manifestos ao cluster:

    kubectl apply -f namespace.yaml -f custom-compute-class.yaml -f buffer-pod-template.yaml -f sample-workload-deployment.yaml
    
  6. Verifique se o GKE criou os objetos:

    kubectl get podtemplate -n capacity-buffer-example
    kubectl get deployment critical-workload-ref -n capacity-buffer-example
    

    O resultado será o seguinte:

    NAME                   AGE
    buffer-unit-template   1m
    
    NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
    critical-workload-ref   10/10   10           10          1m
    

Aplicar um buffer de capacidade

Esta seção fornece exemplos dos diferentes tipos de buffers de capacidade que podem ser aplicados às suas cargas de trabalho.

Configurar um buffer de réplicas fixas

Configurar um CapacityBuffer com réplicas fixas especifica o número exato de unidades de buffer que você quer com base em um PodTemplate.

Para criar um buffer com réplicas fixas, siga estas etapas:

  1. Salve o seguinte manifesto como cb-fixed-replicas.yaml:

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityBuffer
    metadata:
      name: fixed-replica-buffer
      namespace: NAMESPACE
    spec:
      podTemplateRef:
        name: POD_TEMPLATE
      replicas: 3
      provisioningStrategy: "STRATEGY"
    

    Substitua:

    • NAMESPACE: o nome do namespace, por exemplo, capacity-buffer-example.
    • POD_TEMPLATE: o PodTemplate que define os requisitos de recursos, por exemplo, buffer-unit-template.
    • STRATEGY: a estratégia de provisionamento, "buffer.x-k8s.io/active-capacity" (padrão) ou "buffer.gke.io/standby-capacity".

    Esse manifesto cria um recurso CapacityBuffer que faz referência a um PodTemplate para solicitar um número específico de unidades de buffer.

  2. Aplique o manifesto:

    kubectl apply -f cb-fixed-replicas.yaml
    
  3. Confirme se o GKE aplicou o buffer de capacidade:

    kubectl get capacitybuffer fixed-replica-buffer -n NAMESPACE
    

    O campo replicas no status precisa mostrar 3, que reflete o número de réplicas definidas no manifesto. O campo STATUS precisa mostrar ReadyForProvisioning.

Configurar um buffer de limites de recursos

Use o campo limits para definir uma quantidade máxima de recursos que o buffer pode consumir, calculada com base no tamanho do PodTemplate.

Para criar um buffer de limites de recursos, siga estas etapas:

  1. Salve o seguinte manifesto como cb-resource-limits.yaml:

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityBuffer
    metadata:
      name: resource-limit-buffer
      namespace: NAMESPACE
    spec:
      podTemplateRef:
        name: POD_TEMPLATE
      limits:
        cpu: "5"
        memory: "5Gi"
      provisioningStrategy: "STRATEGY"
    

    Substitua:

    • NAMESPACE: o nome do namespace, por exemplo, capacity-buffer-example.
    • POD_TEMPLATE: o PodTemplate que define os requisitos de recursos, por exemplo, buffer-unit-template.
    • STRATEGY: a estratégia de provisionamento, "buffer.x-k8s.io/active-capacity" (padrão) ou "buffer.gke.io/standby-capacity".

    Esse manifesto cria um recurso CapacityBuffer com um limite total de 5 CPUs e 5 GiB de memória. Se você estiver usando o exemplo PodTemplate da etapa anterior, defina cada unidade como 1 CPU e 1Gi de memória, o que resultará em cinco unidades de buffer.

  2. Aplique o manifesto:

    kubectl apply -f cb-resource-limits.yaml
    
  3. Confirme se o GKE aplicou o buffer de capacidade:

    kubectl get capacitybuffer resource-limit-buffer -n NAMESPACE
    

    Verifique o status do CapacityBuffer. O campo replicas mostra um valor derivado dos limites definidos. Se você estiver usando o exemplo PodTemplate da seção anterior, verá 5 unidades de buffer porque esse é o número máximo de unidades que cabem nos limites definidos.

Configurar um buffer baseado em porcentagem

Configurar um buffer baseado em porcentagem dimensiona dinamicamente o buffer com base em uma porcentagem de uma carga de trabalho escalonável. Os buffers de capacidade baseados em porcentagem são compatíveis apenas com objetos escalonáveis do Kubernetes que implementam o sub-recurso de escalonamento, como implantações, StatefulSets, ReplicaSets ou Jobs. Não é possível definir um buffer baseado em porcentagem para modelos de pod porque eles não têm um campo replicas.

Em geral, recomendamos começar com réplicas fixas ou estratégias de limite de recursos, em vez de buffers baseados em porcentagem. Buffers baseados em porcentagem são menos responsivos a aumentos repentinos se a carga de trabalho for escalonada para números baixos ou zero, porque a margem de segurança é escalonada proporcionalmente aos pods ativos. Elas são úteis principalmente para implantações grandes que nunca são reduzidas a contagens de réplicas muito baixas.

Para criar um buffer com base em porcentagem, siga estas etapas:

  1. Salve o seguinte manifesto como cb-percentage-based.yaml:

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityBuffer
    metadata:
      name: percentage-buffer
      namespace: NAMESPACE
    spec:
      scalableRef:
        apiGroup: apps
        kind: Deployment
        name: SCALABLE_RESOURCE_NAME
      percentage: 20
      provisioningStrategy: "STRATEGY"
    

    Substitua:

    • NAMESPACE: o nome do namespace.
    • SCALABLE_RESOURCE_NAME: o nome do recurso escalonável, por exemplo, critical-workload-ref.
    • STRATEGY: a estratégia de provisionamento, "buffer.x-k8s.io/active-capacity" (padrão) ou "buffer.gke.io/standby-capacity".

    Esse manifesto cria um recurso CapacityBuffer que solicita um tamanho de buffer equivalente a 20% das réplicas do recurso referenciado. Se você estiver usando o exemplo de implantação da seção anterior, o valor da réplica será definido como 10.

  2. Aplique o manifesto:

    kubectl apply -f cb-percentage-based.yaml
    
  3. Confirme se o GKE aplicou o buffer de capacidade:

    kubectl get capacitybuffer percentage-buffer -n NAMESPACE
    

    Verifique o status do CapacityBuffer. O campo replicas precisa mostrar um valor do cálculo de porcentagem. Se você estiver usando o exemplo de implantação da seção anterior, verá 2 unidades de buffer, que correspondem a 20% das 10 réplicas definidas na implantação.

  4. Teste o escalonamento dinâmico escalonando manualmente a implantação até 20 réplicas:

    kubectl scale deployment critical-workload-ref -n NAMESPACE --replicas=20
    

    O controlador CapacityBuffer reage e dimensiona automaticamente o buffer para quatro réplicas.

Personalizar o comportamento do buffer de espera

É possível usar anotações para personalizar como os buffers de espera são iniciados e atualizados. Adicione estas anotações ao campo metadata.annotations do recurso CapacityBuffer:

  • buffer.gke.io/standby-capacity-init-time: o período em que um nó permanece ativo após a criação antes de ser suspenso. O formato é uma string de duração (por exemplo, 5m ou 1h). O padrão é 5m.
  • buffer.gke.io/standby-capacity-refresh-frequency: a frequência com que os nós suspensos são atualizados. O padrão é 24h.

O exemplo a seguir mostra um manifesto com esses campos opcionais para personalizar o comportamento dos buffers de espera:

apiVersion: autoscaling.x-k8s.io/v1beta1
kind: CapacityBuffer
metadata:
  name: customized-standby-buffer
  namespace: my-namespace
  annotations:
    buffer.gke.io/standby-capacity-init-time: "15m"
    buffer.gke.io/standby-capacity-refresh-frequency: "12h"
spec:
  podTemplateRef:
    name: buffer-unit-template
  replicas: 3
  provisioningStrategy: "buffer.gke.io/standby-capacity"

Pré-carregar imagens em buffers de espera

Para acelerar os tempos de inicialização da carga de trabalho quando um nó em espera é retomado, é possível pré-carregar imagens de contêiner usando um DaemonSet. O DaemonSet é executado durante o período de inicialização antes da suspensão do nó.

Para pré-carregar imagens usando o DaemonSet, siga estas etapas:

  1. Salve o seguinte manifesto como image-puller-daemonset.yaml:

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: image-prefetch-daemonset
      namespace: NAMESPACE
    spec:
      selector:
        matchLabels:
          name: image-prefetch
      template:
        metadata:
          labels:
            name: image-prefetch
        spec:
          tolerations:
          - key: "buffer.gke.io/standby-node-suspended"
            operator: "Exists"
          initContainers:
          - name: image-puller
            image: IMAGE_NAME
            command: ["sh", "-c", "true"]
          containers:
          - name: pause
            image: registry.k8s.io/pause:3.9
    

    Substitua:

    • NAMESPACE: o namespace do DaemonSet, por exemplo, capacity-buffer-example.
    • IMAGE_NAME: o nome da imagem a ser pré-carregada, por exemplo, your-app-image:latest.
  2. Aplique o manifesto do DaemonSet ao cluster:

    kubectl apply -f image-puller-daemonset.yaml
    
  3. Verifique se o DaemonSet foi criado:

    kubectl get daemonset image-prefetch-daemonset -n NAMESPACE
    
  4. Verifique se o buffer de capacidade foi criado e está pronto para provisionamento:

    kubectl get capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
    

    Verifique o status. O campo STATUS precisa mostrar ReadyForProvisioning.

Monitorar o status e a performance do buffer de capacidade

É possível monitorar o status e a integridade dos buffers de capacidade usando comandos kubectl e métricas do Cloud Monitoring.

Verificar o status do recurso CapacityBuffer

Para verificar a integridade dos buffers de capacidade e se eles estão prontos para receber cargas de trabalho, siga estas etapas:

  1. Confira o status de todos os buffers de capacidade no cluster:

    kubectl get capacitybuffer -A
    
  2. Inspecione o status detalhado, as condições e os registros de eventos de um buffer específico:

    kubectl describe capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
    

Identificar nós de buffer em espera suspensos

As VMs de buffer em espera são pré-provisionadas, mas mantidas em estado suspenso para ajudar a reduzir custos. É possível reconhecer esses nós suspensos porque eles têm uma condição personalizada. Para auditar instâncias de nós suspensos, execute o seguinte comando:

kubectl get nodes -o custom-columns='NAME:.metadata.name,SUSPENDED:.status.conditions[?(@.type=="Suspended")].status'

O status True indica que uma VM em espera está suspensa. Um status False ou <none> indica um nó ativo e em execução.

Monitore o desempenho com o Cloud Monitoring

Para monitorar o desempenho dos buffers de capacidade, acompanhe os seguintes recursos no Cloud Monitoring:

  • Latência de reação (cluster_autoscaler/reaction_time_milliseconds): acompanha a duração para que o escalonador automático de cluster tome uma decisão de escalonamento com base na demanda pendente do CapacityBuffer.
  • Registros do escalonador automático de cluster: pesquise entradas de registro como "Capacity pod processor injecting ..." para observar eventos ativos de substituição de pods de buffer.

Remover buffers de capacidade

Se você não precisar mais de um buffer de capacidade para suas cargas de trabalho, exclua o objeto "CapacityBuffer". Isso remove os pods de marcador de posição e permite que o escalonador automático de cluster reduza verticalmente os nós.

kubectl delete capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE

Substitua CAPACITY_BUFFER_NAME pelo nome do CapacityBuffer que você quer excluir.

Solução de problemas

A seção a seguir contém informações sobre como resolver problemas comuns com buffers de capacidade.

Buffer de capacidade não está pronto devido ao modelo de faturamento

Se você criar um CapacityBuffer para uma carga de trabalho que usa o modelo de faturamento baseado em pod (pagamento por pod), o buffer de capacidade não estará pronto para provisionamento.

Para identificar esse problema, verifique o status do CapacityBuffer:

kubectl describe capacitybuffer BUFFER_NAME -n NAMESPACE

Procure uma condição do tipo ReadyForProvisioning com o status False.

Para resolver esse problema, verifique se o CapacityBuffer faz referência a uma carga de trabalho ou PodTemplate compatível com o faturamento baseado em nós.

Erros de permissão para recursos escalonáveis personalizados

Se você configurar um CapacityBuffer para trabalhar com objetos escalonáveis personalizados (usando o campo scalableRef), o escalonador automático de cluster poderá não escalonar o buffer se não tiver as permissões necessárias.

Para resolver esse problema, conceda manualmente as permissões necessárias criando um ClusterRole e um ClusterRoleBinding, como no exemplo a seguir:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: custom-scale-getter
rules:
- apiGroups: ["api.example.com"]
  resources: ["customreplicatedresources/scale"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ca-custom-scale-getter
subjects:
- kind: User
  name: "system:cluster-autoscaler"
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: custom-scale-getter

Para mais informações sobre como configurar o RBAC, consulte a documentação do RBAC do Kubernetes.

A seguir