Utiliser des VM préemptives pour exécuter des charges de travail tolérantes aux pannes


Cette page explique comment utiliser des VM préemptives dans Google Kubernetes Engine (GKE).

Présentation

Les VM préemptives sont des instances de VM Compute Engine dont le prix est inférieur à celui des VM standards et qui n'offrent aucune garantie de disponibilité. Les VM préemptives présentent des fonctionnalités semblables aux Spot VMs, mais ne durent que jusqu'à 24 heures après leur création.

Dans certains cas, une VM préemptive peut durer plus de 24 heures. Cela peut se produire lorsque la nouvelle instance Compute Engine est générée trop rapidement et que Kubernetes ne détecte pas la création d'une VM Compute Engine différente. L'instance Compute Engine sous-jacente a une durée maximale de 24 heures et suit le comportement attendu de la VM préemptive.

Comparaison avec les Spot VMs

Les VM préemptives présentent de nombreuses similitudes avec les Spot VMs, y compris les suivantes :

Contrairement aux Spot VMs qui n'ont pas de délai d'expiration maximal, les VM préemptives ne durent que jusqu'à 24 heures après leur création.

Vous pouvez activer des VM préemptives sur les nouveaux clusters et pools de nœuds, utiliser nodeSelector ou l'affinité de nœuds pour contrôler la planification, et utiliser des rejets et des tolérances pour éviter les problèmes liés aux charges de travail du système lorsque les nœuds sont préemptés.

Résiliation et arrêt progressif des VM préemptives

Lorsque Compute Engine doit récupérer les ressources utilisées par les VM préemptives, un avis de préemption est envoyé à GKE. Les VM préemptives s'arrêtent 30 secondes après la réception d'une notification d'arrêt.

Sur les clusters exécutant GKE version 1.20 ou ultérieure, la fonctionnalité d'arrêt de nœuds kubelet est activée par défaut. Le kubelet détecte la notification d'arrêt et met fin aux pods en cours d'exécution sur le nœud de façon progressive. Si les pods font partie d'un déploiement, le contrôleur crée et planifie de nouveaux pods pour remplacer les pods arrêtés.

Dans la mesure du possible, le kubelet accorde le délai de grâce suivant en fonction de la version de GKE du pool de nœuds :

  • Versions ultérieures à 1.22.8-gke.200 : 15 secondes pour les pods non système, après quoi les pods système (avec les classes de priorité system-cluster-critical ou system-node-critical) disposent de 15 secondes pour s'arrêter normalement.
  • 1.22.8-gke.200 et versions antérieures : 25 secondes pour les pods non système, après quoi les pods système (avec les classes de priorité system-cluster-critical ou system-node-critical) disposent de cinq secondes pour s'arrêter normalement.

Lors de l'arrêt progressif d'un nœud, le kubelet met à jour l'état des pods, en attribuant la phase Failed et un motif Terminated aux pods arrêtés.

Lorsque le nombre de pods arrêtés atteint un seuil de 1 000 pour les clusters de moins de 100 nœuds ou de 5 000 pour les clusters de 100 nœuds ou plus, la récupération de mémoire nettoie les pods.

Vous pouvez également supprimer manuellement des pods arrêtés à l'aide des commandes suivantes :

  kubectl get pods --all-namespaces | grep -i NodeShutdown | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n
  kubectl get pods --all-namespaces | grep -i Terminated | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n

Modifications du comportement de Kubernetes

L'utilisation de VM préemptives sur GKE modifie certaines garanties et contraintes fournies par Kubernetes, telles que les suivantes :

  • GKE arrête les VM préemptives sans délai de grâce pour les pods, 30 secondes après la réception d'une notification de préemption de Compute Engine.

  • La récupération des VM préemptives est involontaire et n'est pas couverte par les garanties de PodDisruptionBudgets. Vous risquez de rencontrer une indisponibilité supérieure à la valeur PodDisruptionBudget configurée.

Limites

Créer un cluster ou un pool de nœuds doté de VM préemptives

Vous pouvez utiliser la CLI Google Cloud pour créer un cluster ou un pool de nœuds doté de machines virtuelles préemptives.

Pour créer un cluster avec des VM préemptives, exécutez la commande suivante :

gcloud container clusters create CLUSTER_NAME \
    --preemptible

Remplacez CLUSTER_NAME par le nom de votre nouveau cluster.

Pour créer un pool de nœuds avec des VM préemptives, exécutez la commande suivante :

gcloud container node-pools create POOL_NAME \
    --cluster=CLUSTER_NAME \
    --preemptible

Remplacez POOL_NAME par le nom de votre nouveau pool de nœuds.

Utiliser nodeSelector pour planifier des pods sur des VM préemptives

GKE ajoute les libellés cloud.google.com/gke-preemptible=true et cloud.google.com/gke-provisioning=preemptible (pour les nœuds exécutant la version 1.25.5-gke.2500 de GKE ou une version ultérieure) aux nœuds qui utilisent des VM préemptives. Vous pouvez utiliser un nodeSelector dans vos déploiements pour indiquer à GKE de programmer les pods sur des VM préemptives.

Par exemple, le déploiement suivant filtre les VM préemptives à l'aide du libellé cloud.google.com/gke-preemptible :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
      - name: hello-app
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
        resources:
          requests:
            cpu: 200m
      nodeSelector:
        cloud.google.com/gke-preemptible: "true"

Utiliser des rejets de nœuds pour les VM préemptives

Vous pouvez rejeter les nœuds qui utilisent des VM préemptives afin que GKE ne puisse placer que les pods avec la tolérance correspondante sur ces nœuds.

Pour ajouter un rejet de nœud à un pool de nœuds utilisant des VM préemptives, utilisez l'option --node-taints lors de la création du pool de nœuds, comme pour la commande suivante :

gcloud container node-pools create POOL2_NAME \
    --cluster=CLUSTER_NAME \
    --node-taints=cloud.google.com/gke-preemptible="true":NoSchedule

Désormais, seuls les pods qui tolèrent le rejet de nœud spécifié pourront être programmés sur ce nœud.

Pour ajouter la tolérance appropriée à vos pods, modifiez vos déploiements et ajoutez les éléments suivants à la spécification de pod :

tolerations:
- key: cloud.google.com/gke-preemptible
  operator: Equal
  value: "true"
  effect: NoSchedule

Rejets de nœuds pour les VM préemptives de GPU

Les VM préemptives sont compatibles avec l'utilisation des GPU. Vous devez créer au moins un autre pool de nœuds dans votre cluster qui n'utilise pas de VM préemptives avant d'ajouter un pool de nœuds GPU utilisant des VM préemptives. Le fait de disposer d'un pool de nœuds standards garantit que GKE peut placer en toute sécurité des composants système tels que DNS.

Si vous créez un cluster avec des pools de nœuds GPU utilisant des VM préemptives ou si vous ajoutez un pool de nœuds GPU qui utilise des VM préemptives à un cluster qui n'a pas encore de pool de nœuds standards, GKE n'ajoute pas automatiquement le rejet nvidia.com/gpu=present:NoSchedule aux nœuds. GKE peut planifier des pods système sur les VM préemptives, ce qui peut entraîner des perturbations. Ce comportement augmente également la consommation de ressources, car les nœuds GPU coûtent plus cher que les nœuds non GPU.

Étapes suivantes