Configura búferes de capacidad

Los búferes de capacidad mejoran la capacidad de respuesta y la confiabilidad de las cargas de trabajo críticas, ya que administran de forma proactiva la capacidad de reserva del clúster con una definición de recurso personalizado CapacityBuffer de Kubernetes. Usar un búfer de capacidad te permite definir de forma explícita una cantidad específica de capacidad de nodo sin usar dentro de tu clúster. Esta capacidad reservada ayuda a garantizar que GKE aprovisione nodos con anticipación.

Cuando una carga de trabajo de alta prioridad necesita escalar verticalmente rápidamente, la nueva carga de trabajo puede usar la capacidad vacía de inmediato sin esperar el aprovisionamiento de nodos. Esto minimiza la latencia y evita la contención de recursos durante los aumentos repentinos de demanda.

En esta página, se proporcionan tres métodos para configurar búferes de capacidad: un búfer de réplicas fijo, un búfer basado en porcentajes y un búfer de límites de recursos.

Antes de comenzar

Antes de comenzar, asegúrate de haber realizado las siguientes tareas:

  • Habilita la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Si deseas usar Google Cloud CLI para esta tarea, instala y, luego, inicializa gcloud CLI. Si ya instalaste gcloud CLI, ejecuta el comando gcloud components update para obtener la versión más reciente. Es posible que las versiones anteriores de gcloud CLI no admitan la ejecución de los comandos que se describen en este documento.
  • Crea un clúster de GKE en la versión 1.35.2-gke.1842000 o posterior, o bien ten acceso a uno.
  • (Opcional, pero recomendado) Habilita el aprovisionamiento automático de nodos en tu clúster.
  • Para usar los búferes de reserva, debes crear un clúster con la siguiente versión de GKE:

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

    Reemplaza lo siguiente:

    • CLUSTER_NAME: Es el nombre del clúster nuevo.
    • COMPUTE_REGION: Es la región de Compute Engine para tu clúster nuevo, como us-central1.

Crea objetos de Kubernetes como requisito previo

Para configurar un CapacityBuffer, necesitas un espacio de nombres que contenga todos los objetos requeridos (el CapacityBuffer en sí y recursos adicionales, como un PodTemplate o una carga de trabajo). PodTemplate y CapacityBuffer deben estar en el mismo espacio de nombres. Puedes crear un espacio de nombres o usar uno existente, incluido el espacio de nombres default.

Según el tipo de CapacityBuffer que configures, también necesitarás uno de los siguientes elementos:

  • PodTemplate: Define los requisitos de recursos para una sola unidad de capacidad de búfer. La configuración especificada en el objeto CapacityBuffer hace referencia a la plantilla de Pod.
  • Carga de trabajo: Es una carga de trabajo existente a la que haces referencia en el objeto CapacityBuffer. En esta guía, se usa un objeto Deployment como ejemplo de carga de trabajo, pero los búferes de capacidad admiten cualquiera de los siguientes tipos de recursos:

    • Implementación
    • ReplicaSet
    • StatefulSet
    • ReplicationController
    • Trabajo
    • CustomResourceDefinitions (CRD) que implementan el subrecurso scale

En esta sección, se proporcionan ejemplos de estos objetos. Si ya tienes una carga de trabajo que deseas configurar con un búfer de capacidad, continúa con Cómo aplicar un búfer de capacidad.

Para crear una carga de trabajo de Kubernetes de ejemplo, completa los siguientes pasos:

  1. Guarda el siguiente manifiesto como namespace.yaml:

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

    Este manifiesto crea un espacio de nombres llamado capacity-buffer-example.

  2. Guarda el siguiente manifiesto 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"
    

    Este manifiesto crea un PodTemplate que define los requisitos de recursos para una sola unidad de capacidad de búfer (1 CPU y 1Gi de memoria). Esta configuración especifica el tamaño de las unidades de capacidad que GKE aprovisiona para el búfer. Por ejemplo, con este PodTemplate, GKE no considerará los nodos con menos de 1 CPU y 1 Gi de recursos disponibles como parte del búfer si el clúster se escala verticalmente.

  3. Guarda el siguiente manifiesto 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
    

    En este manifiesto, se crea un Deployment de muestra con 10 réplicas, que es el objeto de referencia para el ejemplo de búfer basado en porcentajes de la siguiente sección.

  4. Aplica los manifiestos a tu clúster.

    kubectl apply -f namespace.yaml -f buffer-pod-template.yaml -f sample-workload-deployment.yaml
    
  5. Verifica que GKE haya creado los objetos:

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

    El resultado es similar a lo siguiente:

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

Aplica un búfer de capacidad

En esta sección, se proporcionan ejemplos de los diferentes tipos de búferes de capacidad que puedes aplicar a tus cargas de trabajo.

Configura un búfer de réplicas fijo

Configurar un CapacityBuffer con réplicas fijas especifica la cantidad exacta de unidades de búfer que deseas según un PodTemplate.

Para crear un búfer con réplicas fijas, completa los siguientes pasos:

  1. Guarda el siguiente manifiesto 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"
    

    Reemplaza lo siguiente:

    • NAMESPACE: Es el nombre de tu espacio de nombres, por ejemplo, capacity-buffer-example.
    • POD_TEMPLATE: Es el PodTemplate que define los requisitos de recursos, por ejemplo, buffer-unit-template.
    • STRATEGY: Es la estrategia de aprovisionamiento, que puede ser "buffer.x-k8s.io/active-capacity" (predeterminada) o "buffer.gke.io/standby-capacity".

    Este manifiesto crea un recurso CapacityBuffer que hace referencia a un PodTemplate para solicitar una cantidad específica de unidades de búfer.

  2. Aplica el manifiesto

    kubectl apply -f cb-fixed-replicas.yaml
    
  3. Confirma que GKE haya aplicado el búfer de capacidad:

    kubectl get capacitybuffer fixed-replica-buffer -n NAMESPACE
    

    El campo replicas en el estado debe mostrar 3, lo que refleja la cantidad de réplicas que definiste en el manifiesto. El campo STATUS debe mostrar ReadyForProvisioning.

Configura un búfer basado en un porcentaje

Configurar un búfer basado en un porcentaje dimensiona el búfer de forma dinámica según un porcentaje de una carga de trabajo escalable existente. Los búferes basados en porcentajes se admiten para cualquier objeto que defina un subrecurso de escala, como Deployments, StatefulSets, ReplicaSets o Jobs. No puedes definir un búfer basado en porcentajes para las plantillas de Pod porque no tienen un campo replicas.

Para crear un búfer basado en un porcentaje, completa los siguientes pasos:

  1. Guarda el siguiente manifiesto 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"
    

    Reemplaza lo siguiente:

    • NAMESPACE: Es el nombre de tu espacio de nombres.
    • SCALABLE_RESOURCE_NAME: Es el nombre de tu recurso adaptable, por ejemplo, critical-workload-ref.
    • STRATEGY: Es la estrategia de aprovisionamiento, que puede ser "buffer.x-k8s.io/active-capacity" (predeterminada) o "buffer.gke.io/standby-capacity".

    Este manifiesto crea un recurso CapacityBuffer que solicita un tamaño de búfer equivalente al 20% de las réplicas del recurso al que se hace referencia. Si usas el ejemplo de Deployment de la sección anterior, el valor de la réplica se establece en 10.

  2. Aplica el manifiesto

    kubectl apply -f cb-percentage-based.yaml
    
  3. Confirma que GKE haya aplicado el búfer de capacidad:

    kubectl get capacitybuffer percentage-buffer -n NAMESPACE
    

    Verifica el estado de CapacityBuffer. El campo replicas debe mostrar un valor del cálculo de porcentaje. Si usas el ejemplo de Deployment de la sección anterior, deberías ver 2 unidades de búfer, lo que equivale al 20% de las 10 réplicas definidas en el Deployment.

  4. Prueba el escalamiento dinámico aumentando manualmente la escala de la Deployment a 20 réplicas:

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

    El controlador CapacityBuffer reacciona y ajusta automáticamente el búfer a 4 réplicas.

Configura un búfer de límites de recursos

Puedes usar el campo limits para definir una cantidad máxima de recursos que el búfer debe consumir, calculada en función del tamaño de PodTemplate.

Para crear un búfer de límites de recursos, completa los siguientes pasos:

  1. Guarda el siguiente manifiesto 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"
    

    Reemplaza lo siguiente:

    • NAMESPACE: Es el nombre de tu espacio de nombres, por ejemplo, capacity-buffer-example.
    • POD_TEMPLATE: Es el PodTemplate que define los requisitos de recursos, por ejemplo, buffer-unit-template.
    • STRATEGY: Es la estrategia de aprovisionamiento, que puede ser "buffer.x-k8s.io/active-capacity" (predeterminada) o "buffer.gke.io/standby-capacity".

    Este manifiesto crea un recurso CapacityBuffer con un límite total de 5 CPU y 5 GiB de memoria. Si usas el ejemplo de PodTemplate del paso anterior, define cada unidad como 1 CPU y 1Gi de memoria, lo que debería generar 5 unidades de búfer.

  2. Aplica el manifiesto

    kubectl apply -f cb-resource-limits.yaml
    
  3. Confirma que GKE haya aplicado el búfer de capacidad:

    kubectl get capacitybuffer resource-limit-buffer -n NAMESPACE
    

    Verifica el estado de CapacityBuffer. El campo replicas debe mostrar un valor derivado de los límites que definiste. Si usas el ejemplo de PodTemplate de la sección anterior, deberías ver 5 unidades de búfer, ya que esta es la cantidad máxima de unidades que caben dentro de los límites definidos.

Personaliza el comportamiento del búfer en espera

Puedes usar anotaciones para personalizar la forma en que se inician y actualizan los búferes de reserva. Agrega estas anotaciones al campo metadata.annotations de tu recurso CapacityBuffer:

  • buffer.gke.io/standby-capacity-init-time: Es la cantidad de tiempo que un nodo permanece activo después de su creación antes de que se suspenda. El formato es una cadena de duración (por ejemplo, 5m o 1h). El valor predeterminado es 5m.
  • buffer.gke.io/standby-capacity-refresh-frequency: Indica con qué frecuencia se actualizan los nodos suspendidos. El valor predeterminado es 1d.

En el siguiente ejemplo, se muestra un manifiesto con estos campos opcionales para personalizar el comportamiento de los búferes en 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"

Precarga imágenes en búferes de espera

Para acelerar los tiempos de inicio de la carga de trabajo cuando se reanuda un nodo en espera, puedes precargar imágenes de contenedor con un DaemonSet. El DaemonSet se ejecuta durante el período de inicio antes de que se suspenda el nodo.

Para cargar previamente imágenes con DaemonSet, completa los siguientes pasos:

  1. Guarda el siguiente manifiesto 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
    

    Reemplaza lo siguiente:

    • NAMESPACE: Es el espacio de nombres del DaemonSet, por ejemplo, capacity-buffer-example.
    • IMAGE_NAME: Es el nombre de la imagen que se cargará previamente, por ejemplo, your-app-image:latest.
  2. Aplica el manifiesto de DaemonSet a tu clúster:

    kubectl apply -f image-puller-daemonset.yaml
    
  3. Verifica que se haya creado el DaemonSet:

    kubectl get daemonset image-prefetch-daemonset -n NAMESPACE
    
  4. Verifica que se haya creado tu búfer de capacidad y que esté listo para el aprovisionamiento:

    kubectl get capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
    

    Verifica el estado. El campo STATUS debe mostrar ReadyForProvisioning.

Cómo quitar los búferes de capacidad

Si ya no necesitas un búfer de capacidad para tus cargas de trabajo, borra el objeto CapacityBuffer. Esto quita los Pods de marcador de posición y permite que el escalador automático del clúster reduzca la escala verticalmente de los nodos.

kubectl delete capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE

Reemplaza CAPACITY_BUFFER_NAME por el nombre del CapacityBuffer que deseas borrar.

Soluciona problemas

En la siguiente sección, se proporciona información para resolver problemas comunes con los búferes de capacidad.

El búfer de capacidad no está listo debido al modelo de facturación

Si creas un CapacityBuffer para una carga de trabajo que usa el modelo de facturación basado en Pods (pago por Pod), el búfer de capacidad no estará listo para el aprovisionamiento.

Para identificar este problema, verifica el estado de CapacityBuffer:

kubectl describe capacitybuffer BUFFER_NAME -n NAMESPACE

Busca una condición del tipo ReadyForProvisioning con el estado False.

Para resolver este problema, asegúrate de que tu CapacityBuffer haga referencia a una carga de trabajo o a un PodTemplate que sea compatible con la facturación basada en nodos.

Errores de permisos para recursos escalables personalizados

Si configuras un CapacityBuffer para que funcione con objetos escalables personalizados (con el campo scalableRef), es posible que el escalador automático del clúster no pueda escalar el búfer si no tiene los permisos necesarios.

Para resolver este problema, otorga manualmente los permisos necesarios creando un ClusterRole y un ClusterRoleBinding, como en el siguiente ejemplo:

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 obtener más información sobre cómo configurar RBAC, consulta la documentación de RBAC de Kubernetes.

¿Qué sigue?