Réduire le coût GPU Kubernetes avec Spot et un secours à la demande
Configurer DOKS Spot GPU, l’autoscaling, les affinités et les PDB, puis tester un pool à la demande et mesurer le coût par tâche terminée.
Exécuter des Jobs GPU interruptibles avec un secours
DigitalOcean a annoncé les GPU Spot pour DOKS le 9 septembre 2026. Ce guide les utilise pour des Jobs Kubernetes redémarrables, avec un pool GPU à la demande lorsque Spot ne peut plus les accueillir. L’objectif est de réduire le coût par tâche terminée tout en permettant au travail de continuer sans Spot.
Les pools GPU Spot sont en préversion publique. La récupération concerne un pool entier. DigitalOcean vise un préavis de deux heures par courriel, sans garantie, et une urgence peut le réduire ou le supprimer. DOKS bloque les nouvelles affectations, draine les nœuds et publie des événements Kubernetes. Le préavis aide à limiter le travail perdu, mais ne doit pas être votre seul mécanisme de reprise.
Transparence : cet article contient des liens affiliés DigitalOcean. Un achat peut me rapporter une commission sans frais supplémentaires pour vous. Sources vérifiées le 13 septembre 2026. Les exemples reposent sur la documentation ; je n’ai pas créé de pools GPU payants ni observé de récupération réelle pour cet article.
Vérifier la charge et la capacité du compte
Cette approche convient à l’inférence par lots, aux expériences indépendantes ou à un entraînement qui sauvegarde déjà des points de reprise. Si un redémarrage efface des heures de progression, adaptez d’abord l’application. Gardez la capacité minimale d’un service sensible à la latence sur des nœuds à la demande.
Il faut un cluster DOKS de test existant, un pool CPU, kubectl et doctl authentifié. Réservez les CPU aux services système ; DigitalOcean recommande au moins deux nœuds CPU pour leur disponibilité. Dans le panneau de contrôle, vérifiez l’équipe, le quota GPU, la région et le prix des deux pools. Une inscription ne réserve aucun GPU.
Le catalogue Spot comprend MI350X, MI355X et B300. Cet exemple utilise un NVIDIA B300 Spot à un GPU. Choisissez un modèle NVIDIA à la demande compatible dans la même région. Un H100 possède moins de mémoire GPU qu’un B300 : un modèle peut donc fonctionner sur B300 et échouer sur H100. Testez le modèle réel, son conteneur et sa mémoire sur les deux.
Vérifiez que le contexte kubeconfig ci-dessous désigne le cluster de test. Sinon, téléchargez sa configuration en suivant la procédure de connexion DOKS avant de continuer.
kubectl config current-contextCréer les pools GPU Spot et à la demande
Remplacez YOUR_CLUSTER_ID par l’identifiant du cluster de test. Vérifiez que gpu-b300x1-288gb-spot est proposé avec doctl kubernetes options sizes et dans le panneau de contrôle. Remplacez YOUR_ON_DEMAND_NVIDIA_SIZE par un modèle NVIDIA à la demande disponible et testé. Arrêtez si un pool ne peut pas être créé.
Ces commandes créent des ressources facturées. Chaque pool commence avec un nœud et peut atteindre deux nœuds. Ce plafond sert à l’exemple. Dimensionnez le secours pour le travail qui doit continuer si tout le pool Spot disparaît.
Les deux pools reçoivent notre label et notre taint workload=gpu-batch. Configurez-les sur le pool pour que les nouveaux nœuds les héritent. DOKS ajoute aussi un taint lié au fabricant du GPU. Le Job tolère les deux restrictions. Aucun pool CPU ne reçoit notre label.
Choisissez le plafond Spot dès la création. Vous ne pourrez ensuite ni augmenter son maximum d’autoscaling ni accroître manuellement sa taille fixe. L’autoscaling peut remonter dans la plage initiale si la capacité existe. Une capacité libérée peut manquer plus tard.
Gardez un nœud à la demande prêt pour ce premier test. Un minimum nul réduit le coût d’inactivité mais ajoute un délai de création et un risque de capacité. La documentation avertit que la création GPU peut parfois prendre des heures. Un pool vide ne garantit pas une reprise immédiate.
Avant de continuer : Modifie le cluster cible. Les ressources GPU peuvent être facturées.
doctl kubernetes cluster node-pool create YOUR_CLUSTER_ID --name gpu-spot --size gpu-b300x1-288gb-spot --count 1 --auto-scale --min-nodes 1 --max-nodes 2 --label workload=gpu-batch --taint workload=gpu-batch:NoScheduleAvant de continuer : Modifie le cluster cible. Les ressources GPU peuvent être facturées.
doctl kubernetes cluster node-pool create YOUR_CLUSTER_ID --name gpu-fallback --size YOUR_ON_DEMAND_NVIDIA_SIZE --count 1 --auto-scale --min-nodes 1 --max-nodes 2 --label workload=gpu-batch --taint workload=gpu-batch:NoScheduleDéfinir le pool à privilégier pour l’autoscaling
L’affinité des pods note les nœuds existants. L’autoscaler choisit le pool à agrandir pour les pods impossibles à placer. Configurez les deux décisions. Une affinité préférée ne définit pas l’ordre des pools, et un GPU occupé ne crée pas à lui seul des pods supplémentaires.
Activez le sélecteur priority ci-dessous. Exécutez ensuite doctl kubernetes cluster node-pool list YOUR_CLUSTER_ID et relevez les identifiants des pools. Ouvrez le ConfigMap existant avec kubectl edit configmap cluster-autoscaler-priority-expander -n kube-system. Remplacez uniquement le texte de data.priorities par le modèle fourni avec les vrais identifiants. Conservez le nom du ConfigMap et ses labels gérés.
La priorité supérieure essaie Spot en premier lors d’un agrandissement. Le secours dépend toujours des contraintes de placement et de la capacité. Un nœud à la demande déjà libre peut recevoir immédiatement un pod. Ni l’affinité préférée ni le sélecteur ne déplacent les pods actifs vers Spot à son retour. Mesurez ce comportement.
Avant de continuer : Modifie le cluster cible. Les ressources GPU peuvent être facturées.
doctl kubernetes cluster update YOUR_CLUSTER_ID --expanders priority100:
- "^YOUR_SPOT_POOL_ID$"
50:
- "^YOUR_FALLBACK_POOL_ID$"
1:
- ".*"Exécuter un petit Job GPU autorisant le secours
Enregistrez le YAML sous gpu-spot-check.yaml. Il exécute nvidia-smi une fois pour vérifier qu’un conteneur voit un GPU. Il ne mesure pas les calculs, ne charge aucun modèle et n’implémente pas de reprise. Vérifiez votre politique de registre et fixez une empreinte d’image validée pour les essais répétés.
Le sélecteur exige notre label sur l’un des deux pools GPU. L’affinité préfère Spot sans l’imposer. N’ajoutez pas de sélecteur obligatoire capacity-type=spot, qui exclurait le secours. Une tolérance autorise le passage d’un taint ; elle ne sélectionne pas un nœud.
Appliquez le fichier et lisez les journaux. Exécutez kubectl get pods -n default -l app=gpu-spot-check -o wide puis kubectl get nodes -L doks.digitalocean.com/capacity-type,workload pour identifier le nœud. Les journaux doivent afficher les informations GPU et le Job doit être Complete. Vérifiez avec kubectl get job gpu-spot-check -n default.
Le Job autorise trois nouvelles tentatives et impose quinze minutes au total. Une création de GPU plus longue peut le faire échouer. Cherchez la cause avant d’allonger ce délai. Pour un vrai worker, utilisez des identifiants de tâche stables, des écritures idempotentes et un accusé de traitement seulement après stockage durable. Kubernetes peut démarrer une tâche plusieurs fois.
apiVersion: batch/v1
kind: Job
metadata:
name: gpu-spot-check
namespace: default
spec:
backoffLimit: 3
activeDeadlineSeconds: 900
ttlSecondsAfterFinished: 3600
template:
metadata:
labels:
app: gpu-spot-check
spec:
restartPolicy: Never
terminationGracePeriodSeconds: 30
nodeSelector:
workload: gpu-batch
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
- key: workload
operator: Equal
value: gpu-batch
effect: NoSchedule
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: doks.digitalocean.com/capacity-type
operator: In
values: [spot]
containers:
- name: gpu-check
image: nvidia/cuda:12.8.1-base-ubuntu24.04
command: ["nvidia-smi"]
resources:
requests:
cpu: "1"
memory: 1Gi
limits:
memory: 2Gi
nvidia.com/gpu: 1Avant de continuer : Modifie le cluster cible. Les ressources GPU peuvent être facturées.
kubectl apply -f gpu-spot-check.yamlkubectl logs -n default job/gpu-spot-checkUtiliser les PDB et sauvegarder la progression
Un PodDisruptionBudget limite les évictions volontaires. Pour un Deployment d’inférence distinct ayant au moins deux réplicas sains, cet exemple facultatif autorise un réplica indisponible. Son sélecteur doit correspondre aux labels des pods du Deployment. Il ne cible volontairement pas notre Job ponctuel.
Un PDB ne peut ni empêcher une perte involontaire de nœud ni conserver la capacité récupérée. Interdire toute éviction peut bloquer le drainage sans sauver le nœud. Prévoyez de la capacité libre, des sondes de disponibilité et plusieurs nœuds. Des réplicas répartis dans un même pool Spot restent exposés à sa récupération entière.
Pour les longs Jobs, sauvegardez périodiquement les points de reprise hors des nœuds Spot, sur un stockage durable. Incluez le modèle, l’optimiseur et la position dans les données. Testez la restauration sur le GPU de secours. Gérez SIGTERM pour arrêter les nouvelles tâches et tenter une dernière sauvegarde, tout en conservant les sauvegardes périodiques. terminationGracePeriodSeconds règle l’arrêt du pod et ne garantit aucun préavis du fournisseur.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: gpu-inference
namespace: default
spec:
maxUnavailable: 1
selector:
matchLabels:
app: gpu-inferenceTester le secours avant de lui faire confiance
Exécutez le diagnostic avec les deux pools disponibles et notez son nœud. Pour tester l’éligibilité du secours, créez gpu-fallback-check.yaml, changez metadata.name en gpu-fallback-check et ajoutez doks.digitalocean.com/node-pool-id avec l’identifiant du pool à la demande dans spec.template.spec.nodeSelector. Conservez le sélecteur workload. Appliquez le fichier et confirmez le placement sur un nœud à la demande.
Cela vérifie l’image, les tolérances et la capacité du secours. Cela ne teste ni la récupération Spot ni une erreur de capacité de l’autoscaler. Dans un cluster jetable, testez séparément une éviction et la reprise du vrai worker. Mesurez le délai de remplacement, le retour au travail utile et les doublons. Ne supprimez pas de force un nœud de production pour ce tutoriel.
Pour un pod Pending, consultez kubectl describe pod POD_NAME -n default. Cherchez un taint non toléré, un sélecteur excluant le secours, un manque de nvidia.com/gpu, une limite de quota ou de capacité. Consultez cluster-autoscaler-status dans kube-system et les événements ci-dessous. Relevez les vrais noms des événements de récupération avant de créer des alertes.
Après les tests, supprimez seulement les deux Jobs de diagnostic créés. Examinez les pools GPU dans le panneau de contrôle et retirez ceux du tutoriel après avoir confirmé qu’aucune autre charge ne les utilise. La fin ou le nettoyage automatique des Jobs ne supprime pas les frais des nœuds dont le minimum reste à un.
kubectl get events -A --sort-by=.metadata.creationTimestampComparer le coût du travail terminé
Utilisez les tarifs affichés dans votre compte. Le tarif Spot reste fixe pendant la vie du pool, y compris pour les nœuds ajoutés automatiquement. L’offre au moment de la création peut changer. Relevez les heures de nœuds des deux pools, les CPU, le stockage et les frais réseau éventuels.
Divisez le coût total de l’expérience par le nombre de tâches réussies. Incluez les échecs et le temps de restauration. Comparez avec les mêmes données et critères de réussite sur des ressources à la demande. Une heure moins chère peut produire une tâche plus coûteuse si les redémarrages perdent trop de travail.
Si la reprise fonctionne et que le coût mesuré convient, utilisez l’action DigitalOcean ci-dessous pour créer un compte ou continuer avec votre équipe. Vérifiez la disponibilité GPU et le budget complet du secours avant toute création. Le lien affilié ne configure pas Kubernetes et ne garantit pas l’application de crédits promotionnels aux GPU.
Vérifier le résultat
- Résultat attendu
- Le Job de diagnostic termine sur le pool de secours.
- Arrêter si
- Examiner événements Pending, sélecteurs, taints, quota et capacité.
- Étape suivante
- Tester la reprise réelle et mesurer le coût du travail terminé.