Configurar buffers de capacidade

Os buffers de capacidade melhoram a capacidade de resposta e a confiabilidade de cargas de trabalho críticas, gerenciando de maneira proativa a capacidade de cluster extra usando uma definição de recurso personalizado do CapacityBuffer do Kubernetes. O uso de um buffer de capacidade permite definir explicitamente uma quantidade específica de capacidade de nó não utilizada no cluster. Essa capacidade reservada ajuda a garantir que o GKE provisione nós com antecedência.

Quando uma carga de trabalho de alta prioridade precisa escalonar verticalmente rapidamente, a nova carga de trabalho pode usar a capacidade vazia imediatamente sem esperar pelo provisionamento de nós. Isso minimiza a latência e evita a contenção de recursos durante picos repentinos na demanda.

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

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 gcloud CLI anteriormente, instale a versão mais recente executando o comando gcloud components update. Talvez as versões anteriores da gcloud CLI 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 ou mais recente.
  • (Opcional, mas recomendado) Ative o provisionamento automático de nós no cluster.
  • Para usar buffers de espera, é necessário criar um cluster com a seguinte versão do GKE:

    gcloud container clusters create CLUSTER_NAME \
        --region=COMPUTE_REGION \
        --cluster-version=1.35.2-gke.1842002 \
        --release-channel=None
    

    Substitua:

    • CLUSTER_NAME: o nome do novo cluster;
    • COMPUTE_REGION: a região do Compute Engine para o novo cluster, como us-central1.

Criar objetos do Kubernetes necessários

Para configurar um CapacityBuffer, é necessário um namespace que contenha todos os objetos necessários (o CapacityBuffer em si e outros recursos, 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 namespace atual, incluindo o namespace default.

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

  • 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 que você referencia no objeto CapacityBuffer. Este guia usa um objeto de implantação como um 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. 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"
    

    Esse manifesto cria um PodTemplate que define os requisitos de recursos para uma única unidade de capacidade de buffer (1 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 considera nós com menos de 1 CPU e 1Gi de recursos disponíveis como parte do buffer, se o cluster for escalonado.

  3. 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
    

    Esse 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.

  4. Aplique os manifestos ao cluster:

    kubectl apply -f namespace.yaml -f buffer-pod-template.yaml -f sample-workload-deployment.yaml
    
  5. 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á assim:

    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 cargas de trabalho.

Configurar um buffer de réplicas fixas

A configuração de 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 baseado em porcentagem

A configuração de um buffer baseado em porcentagem dimensiona dinamicamente o buffer com base em uma porcentagem de uma carga de trabalho escalonável atual. Os buffers baseados em porcentagem são compatíveis com qualquer objeto que defina um 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.

Para criar um buffer baseado 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 é 20% das 10 réplicas definidas na implantação.

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

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

    O controlador CapacityBuffer reage e escalona automaticamente o buffer para 4 réplicas.

Configurar um buffer de limites de recursos

É possível usar o campo limits para definir um número máximo de recursos que o buffer precisa consumir, calculado 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 de PodTemplate da etapa anterior, defina cada unidade como 1 CPU e 1Gi de memória, o que resultará em 5 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 precisa mostrar um valor derivado dos limites definidos. Se você estiver usando o exemplo de PodTemplate da seção anterior, verá 5 unidades de buffer, porque esse é o número máximo de unidades que se encaixam nos limites definidos.

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 essas 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 é 1d.

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ó de espera é retomado, é possível pré-carregar imagens de contêiner usando um DaemonSet. O DaemonSet é executado durante o período de inicialização antes que o nó seja suspenso.

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.

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 clusters reduza a escala vertical dos 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 um status de 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 clusters poderá falhar ao escalonar o buffer se não tiver as permissões necessárias.

Para resolver esse problema, conceda manualmente as permissões necessárias por criar um ClusterRole e 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