Configurer des marges de capacité

Les tampons de capacité améliorent la réactivité et la fiabilité des charges de travail critiques en gérant de manière proactive la capacité de cluster de réserve et les états suspendus de la capacité préprovisionnée et préconfigurée à l'aide d'une définition de ressource personnalisée (CRD) Kubernetes CapacityBuffer. Les tampons de capacité vous permettent de définir explicitement une quantité spécifique de capacité de nœud inutilisée dans votre cluster. Cette capacité réservée permet de réduire le temps de planification des pods.

Lorsqu'une charge de travail de haute priorité doit être mise à l'échelle rapidement, la nouvelle charge de travail peut utiliser immédiatement la capacité vide sans attendre le provisionnement des nœuds. Cette approche minimise la latence et évite la contention des ressources lors de pics de demande soudains.

Cette page présente des méthodes de configuration des tampons de capacité : un tampon de réplicas fixes, un tampon de limites de ressources et un tampon basé sur un pourcentage.

Avant de commencer

Avant de commencer, effectuez les tâches suivantes :

  • Activez l'API Google Kubernetes Engine.
  • Activer l'API Google Kubernetes Engine
  • Si vous souhaitez utiliser la Google Cloud CLI pour cette tâche, installez et initialisez la gcloud CLI. Si vous avez déjà installé la gcloud CLI, obtenez la dernière version en exécutant la commande gcloud components update. Il est possible que les versions antérieures de la gcloud CLI ne permettent pas d'exécuter les commandes de ce document.
  • Créez un cluster GKE ou accédez-y, en version 1.35.2-gke.1842000 pour les tampons actifs et en version 1.36.0-gke.2253000 ou ultérieure pour les tampons en veille.
  • Activez le provisionnement automatique des nœuds sur vos clusters standards. Dans les clusters Autopilot, le provisionnement automatique des nœuds est déjà activé. Le provisionnement automatique des nœuds est facultatif, mais recommandé pour les tampons actifs et obligatoire pour les tampons en veille.

Créer des objets Kubernetes prérequis

Pour configurer un CapacityBuffer, vous avez besoin d'un espace de noms contenant tous les objets requis (le CapacityBuffer lui-même et des ressources supplémentaires telles qu'un PodTemplate ou une charge de travail). PodTemplate et CapacityBuffer doivent se trouver dans le même espace de noms. Vous pouvez créer un espace de noms ou en utiliser un existant, y compris l'espace de noms default.

Selon le type de CapacityBuffer que vous configurez, vous avez également besoin de l'un des éléments suivants :

  • PodTemplate : définit les exigences en termes de ressources pour une seule unité de capacité de tampon. La configuration spécifiée dans l'objet CapacityBuffer fait référence au modèle de pod.
  • Charge de travail : charge de travail existante que vous référencez dans l'objet CapacityBuffer. Ce guide utilise un objet Deployment comme exemple de charge de travail, mais les tampons de capacité sont compatibles avec les types de ressources suivants :

    • Déploiement
    • ReplicaSet
    • StatefulSet
    • ReplicationController
    • Job
    • CustomResourceDefinitions (CRD) qui implémentent la sous-ressource scale.

Cette section fournit des exemples de ces objets. Si vous disposez déjà d'une charge de travail que vous souhaitez configurer avec une marge de capacité, passez à Appliquer une marge de capacité.

Pour créer un exemple de charge de travail Kubernetes, procédez comme suit :

  1. Enregistrez le manifeste suivant sous le nom namespace.yaml :

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

    Ce fichier manifeste crée un espace de noms appelé capacity-buffer-example.

  2. Facultatif : Pour utiliser des tampons de capacité avec une ComputeClass personnalisée, enregistrez le fichier manifeste suivant sous le nom 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
    

    Ce fichier manifeste crée un ComputeClass personnalisé qui définit et contrôle les priorités de calcul pour les nœuds provisionnés par GKE. Pour en savoir plus, consultez Classes de calcul personnalisées.

  3. Enregistrez le manifeste suivant sous le nom 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
    

    Ce fichier manifeste crée un PodTemplate qui définit les exigences en termes de ressources pour une seule unité de capacité de tampon (1 CPU et 1Gi mémoire). Cette configuration spécifie la taille des unités de capacité que GKE provisionne pour le tampon. Par exemple, avec ce PodTemplate, GKE ne considérera pas les nœuds disposant de moins d'un processeur et d'un Gio de ressources disponibles comme faisant partie du tampon, si le cluster est mis à l'échelle.

  4. Enregistrez le manifeste suivant sous le nom 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
    

    Ce fichier manifeste crée un exemple de déploiement avec 10 répliques, qui est l'objet de référence pour l'exemple de tampon basé sur un pourcentage dans la section suivante.

  5. Appliquez les fichiers manifestes à votre cluster :

    kubectl apply -f namespace.yaml -f custom-compute-class.yaml -f buffer-pod-template.yaml -f sample-workload-deployment.yaml
    
  6. Vérifiez que GKE a créé les objets :

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

    Le résultat ressemble à ce qui suit :

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

Appliquer une marge de capacité

Cette section fournit des exemples des différents types de marges de capacité que vous pouvez appliquer à vos charges de travail.

Configurer un tampon d'instances répliquées fixes

La configuration d'un CapacityBuffer avec des instances répliquées fixes spécifie le nombre exact d'unités de tampon souhaitées en fonction d'un PodTemplate.

Pour créer un tampon avec des réplicas fixes, procédez comme suit :

  1. Enregistrez le manifeste suivant sous le nom 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"
    

    Remplacez les éléments suivants :

    • NAMESPACE : nom de votre espace de noms (par exemple, capacity-buffer-example).
    • POD_TEMPLATE : PodTemplate qui définit vos besoins en ressources, par exemple buffer-unit-template.
    • STRATEGY : stratégie de provisionnement, "buffer.x-k8s.io/active-capacity" (par défaut) ou "buffer.gke.io/standby-capacity".

    Ce fichier manifeste crée une ressource CapacityBuffer qui fait référence à un PodTemplate pour demander un nombre spécifique d'unités de tampon.

  2. Appliquez le fichier manifeste :

    kubectl apply -f cb-fixed-replicas.yaml
    
  3. Vérifiez que GKE a appliqué la marge de capacité :

    kubectl get capacitybuffer fixed-replica-buffer -n NAMESPACE
    

    Le champ replicas de l'état doit afficher 3, ce qui reflète le nombre de répliques que vous avez défini dans le fichier manifeste. Le champ STATUS doit afficher ReadyForProvisioning.

Configurer un tampon de limites de ressources

Vous pouvez utiliser le champ limits pour définir une quantité maximale de ressources que le tampon doit consommer, calculée en fonction de la taille de votre PodTemplate.

Pour créer une marge pour les limites de ressources, procédez comme suit :

  1. Enregistrez le manifeste suivant sous le nom 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"
    

    Remplacez les éléments suivants :

    • NAMESPACE : nom de votre espace de noms (par exemple, capacity-buffer-example).
    • POD_TEMPLATE : PodTemplate qui définit vos besoins en ressources, par exemple buffer-unit-template.
    • STRATEGY : stratégie de provisionnement, "buffer.x-k8s.io/active-capacity" (par défaut) ou "buffer.gke.io/standby-capacity".

    Ce fichier manifeste crée une ressource CapacityBuffer avec une limite totale de cinq processeurs et cinq Gio de mémoire. Si vous utilisez l'exemple PodTemplate de l'étape précédente, vous définissez chaque unité sur 1 CPU et 1Gi mémoire, ce qui devrait donner 5 unités de tampon.

  2. Appliquez le fichier manifeste :

    kubectl apply -f cb-resource-limits.yaml
    
  3. Vérifiez que GKE a appliqué la marge de capacité :

    kubectl get capacitybuffer resource-limit-buffer -n NAMESPACE
    

    Vérifiez l'état de CapacityBuffer. Le champ replicas doit afficher une valeur dérivée des limites que vous avez définies. Si vous utilisez l'exemple PodTemplate de la section précédente, vous devriez voir 5 unités de tampon, car il s'agit du nombre maximal d'unités qui tiennent dans les limites définies.

Configurer une marge basée sur un pourcentage

La configuration d'un tampon basé sur un pourcentage dimensionne dynamiquement le tampon en fonction d'un pourcentage d'une charge de travail évolutive existante. Les tampons de capacité basés sur un pourcentage ne sont compatibles qu'avec les objets évolutifs Kubernetes qui implémentent la sous-ressource scale, tels que les déploiements, les StatefulSets, les ReplicaSets ou les Jobs. Vous ne pouvez pas définir de tampon basé sur un pourcentage pour les modèles de pods, car ils ne comportent pas de champ replicas.

Nous vous recommandons généralement de commencer par des stratégies de réplicas fixes ou de limites de ressources, plutôt que par des tampons basés sur des pourcentages. Les tampons basés sur des pourcentages sont moins réactifs aux augmentations soudaines de l'échelle si la charge de travail est mise à l'échelle à des nombres faibles ou à zéro, car la marge de sécurité est mise à l'échelle proportionnellement aux pods actifs. Elles sont utiles principalement pour les déploiements à grande échelle qui ne sont jamais réduits à un très petit nombre de réplicas.

Pour créer une zone tampon basée sur un pourcentage, procédez comme suit :

  1. Enregistrez le manifeste suivant sous le nom 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"
    

    Remplacez les éléments suivants :

    • NAMESPACE : nom de votre espace de noms
    • SCALABLE_RESOURCE_NAME : nom de votre ressource évolutive, par exemple critical-workload-ref.
    • STRATEGY : stratégie de provisionnement, "buffer.x-k8s.io/active-capacity" (par défaut) ou "buffer.gke.io/standby-capacity".

    Ce fichier manifeste crée une ressource CapacityBuffer qui demande une taille de mémoire tampon équivalente à 20% des instances répliquées de la ressource référencée. Si vous utilisez l'exemple de déploiement de la section précédente, la valeur du réplica est définie sur 10.

  2. Appliquez le fichier manifeste :

    kubectl apply -f cb-percentage-based.yaml
    
  3. Vérifiez que GKE a appliqué la marge de capacité :

    kubectl get capacitybuffer percentage-buffer -n NAMESPACE
    

    Vérifiez l'état de CapacityBuffer. Le champ replicas doit afficher une valeur issue du calcul du pourcentage. Si vous utilisez l'exemple de déploiement de la section précédente, vous devriez voir 2 unités de tampon, ce qui représente 20% des 10 répliques définies dans le déploiement.

  4. Testez le scaling dynamique en augmentant manuellement le nombre de répliques du déploiement jusqu'à 20 :

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

    Le contrôleur CapacityBuffer réagit et met automatiquement à l'échelle le tampon sur quatre réplicas.

Personnaliser le comportement du tampon de veille

Vous pouvez utiliser des annotations pour personnaliser le démarrage et l'actualisation des tampons de veille. Ajoutez ces annotations au champ metadata.annotations de votre ressource CapacityBuffer :

  • buffer.gke.io/standby-capacity-init-time : durée pendant laquelle un nœud reste actif après sa création avant d'être suspendu. Le format est une chaîne de durée (par exemple, 5m ou 1h). La valeur par défaut est 5m.
  • buffer.gke.io/standby-capacity-refresh-frequency : fréquence d'actualisation des nœuds suspendus. La valeur par défaut est 1d.

L'exemple suivant montre un fichier manifeste avec ces champs facultatifs pour personnaliser le comportement des tampons de secours :

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écharger des images sur des tampons de veille

Pour accélérer les temps de démarrage des charges de travail lorsqu'un nœud de secours reprend son activité, vous pouvez précharger des images de conteneurs à l'aide d'un DaemonSet. Le DaemonSet s'exécute pendant la période de démarrage avant la suspension du nœud.

Pour précharger des images à l'aide de DaemonSet, procédez comme suit :

  1. Enregistrez le manifeste suivant sous le nom 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
    

    Remplacez les éléments suivants :

    • NAMESPACE : espace de noms du DaemonSet, par exemple capacity-buffer-example.
    • IMAGE_NAME : nom de l'image à précharger, par exemple your-app-image:latest.
  2. Appliquez le fichier manifeste DaemonSet à votre cluster :

    kubectl apply -f image-puller-daemonset.yaml
    
  3. Vérifiez que le DaemonSet a été créé :

    kubectl get daemonset image-prefetch-daemonset -n NAMESPACE
    
  4. Vérifiez que votre tampon de capacité a été créé et est prêt pour le provisionnement :

    kubectl get capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
    

    Vérifiez l'état. Le champ STATUS doit afficher ReadyForProvisioning.

Surveiller l'état et les performances de la marge de capacité

Vous pouvez surveiller l'état et l'intégrité de vos tampons de capacité à l'aide des commandes kubectl et des métriques Cloud Monitoring.

Vérifier l'état de la ressource CapacityBuffer

Pour vérifier l'état de vos tampons de capacité et vous assurer qu'ils sont prêts à recevoir des charges de travail, procédez comme suit :

  1. Obtenez l'état de toutes les mémoires tampons de capacité du cluster :

    kubectl get capacitybuffer -A
    
  2. Inspectez l'état détaillé, les conditions et les journaux d'événements d'un tampon spécifique :

    kubectl describe capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
    

Identifier les nœuds de mémoire tampon de secours suspendus

Les VM tampon de secours sont préprovisionnées, mais conservées à l'état suspendu pour réduire les coûts. Vous pouvez identifier ces nœuds suspendus, car ils présentent une condition personnalisée. Pour auditer les instances de nœuds suspendues, exécutez la commande suivante :

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

L'état True indique qu'une VM de secours est suspendue. L'état False ou <none> indique qu'un nœud est actif et en cours d'exécution.

Surveillez les performances avec Cloud Monitoring

Pour surveiller les performances des tampons de capacité, surveillez les ressources suivantes dans Cloud Monitoring :

  • Latence de réaction (cluster_autoscaler/reaction_time_milliseconds) : suit la durée nécessaire à l'autoscaler de cluster pour prendre une décision de scaling en fonction de la demande en attente de votre CapacityBuffer.
  • Journaux de l'autoscaler de cluster : recherchez des entrées de journal telles que "Capacity pod processor injecting ..." pour observer les événements de remplacement de pods de tampon actifs.

Supprimer les marges de capacité

Si vous n'avez plus besoin de tampon de capacité pour vos charges de travail, supprimez l'objet CapacityBuffer. Cela supprime les pods de substitution et permet à l'autoscaler de cluster de réduire la taille des nœuds.

kubectl delete capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE

Remplacez CAPACITY_BUFFER_NAME par le nom du CapacityBuffer que vous souhaitez supprimer.

Dépannage

La section suivante explique comment résoudre les problèmes courants liés aux marges de capacité.

La marge de capacité n'est pas prête en raison du modèle de facturation

Si vous créez un CapacityBuffer pour une charge de travail qui utilise le modèle de facturation basé sur les pods (paiement par pod), le tampon de capacité ne sera pas prêt pour le provisionnement.

Pour identifier ce problème, vérifiez l'état de CapacityBuffer :

kubectl describe capacitybuffer BUFFER_NAME -n NAMESPACE

Recherchez une condition de type ReadyForProvisioning dont l'état est False.

Pour résoudre ce problème, assurez-vous que votre CapacityBuffer fait référence à une charge de travail ou à un PodTemplate compatible avec la facturation basée sur les nœuds.

Erreurs d'autorisation pour les ressources évolutives personnalisées

Si vous configurez un CapacityBuffer pour qu'il fonctionne avec des objets évolutifs personnalisés (à l'aide du champ scalableRef), l'autoscaler de cluster peut ne pas parvenir à mettre à l'échelle le tampon s'il ne dispose pas des autorisations nécessaires.

Pour résoudre ce problème, accordez manuellement les autorisations requises en créant un ClusterRole et un ClusterRoleBinding, comme dans l'exemple suivant :

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

Pour en savoir plus sur la configuration de RBAC, consultez la documentation Kubernetes RBAC.

Étapes suivantes