Recherche de site Web

Comment faire évoluer les charges de travail GPU AMD sur DOKS en utilisant KEDA


Introduction

À mesure que les applications cloud-native gagnent en échelle et en sophistication, la capacité à allouer dynamiquement les ressources informatiques devient critique—en particulier pour les charges de travail nécessitant des GPU. Kubernetes offre une mise à l'échelle automatique intégrée, mais elle s'avère souvent insuffisante lorsque vous devez évoluer en fonction de métriques externes ou personnalisées. C'est là que KEDA (Kubernetes Event-Driven Autoscaling) excelle. KEDA permet à vos charges de travail Kubernetes de s'adapter en fonction des métriques en temps réel provenant de sources comme Prometheus.

Dans ce tutoriel, nous allons expliquer comment mettre à l'échelle automatiquement une charge de travail basée sur un GPU AMD exécutée sur Linux-Console.net Kubernetes (DOKS) en utilisant Prometheus et KEDA. Cette configuration vous permet de réagir aux métriques en temps réel et d'optimiser l'utilisation du GPU de manière efficace et rentable.

Points clés

  • Autoscaling GPU basé sur les événements : Apprenez à utiliser KEDA pour l'autoscaling des charges de travail GPU AMD sur Linux-Console.net Kubernetes (DOKS) en fonction des métriques en temps réel de Prometheus, permettant un scaling réactif et économique au-delà de l'autoscaling standard basé sur le CPU.
  • Séparation des charges de travail : Découvrez les meilleures pratiques pour isoler les charges de travail GPU et non-GPU en utilisant plusieurs groupes de nœuds, optimiser l'allocation des ressources et réduire les coûts opérationnels.
  • Prise en charge native des GPU AMD : Profitez de la prise en charge intégrée des GPU AMD MI300X par DOKS, avec le plugin de périphérique AMD GPU et l'exportateur de métriques activés par défaut pour une intégration et une observabilité transparentes.
  • Métriques personnalisées pour la mise à l'échelle : Découvrez comment configurer Prometheus pour collecter des métriques GPU personnalisées et les utiliser comme déclencheurs pour la mise à l'échelle, vous permettant d'ajuster l'allocation des ressources à la demande réelle de travail (par exemple, l'inférence en apprentissage automatique, le traitement vidéo, l'analyse en temps réel).
  • Guide pratique étape par étape : Suivez un guide pratique couvrant la configuration du cluster, la configuration du pool de nœuds, l'activation des métriques GPU, le déploiement d'une charge de travail exemple et la mise en œuvre de l'autoscaling basé sur KEDA.
  • Test et validation : Apprenez à simuler la charge du GPU, à observer l'autoscaling en action et à vérifier que les nouveaux nœuds GPU sont provisionnés et que les charges de travail sont replanifiées automatiquement à mesure que la demande augmente.
  • Modèles prêts pour la production : Découvrez comment créer des applications robustes, évolutives et rentables avec GPU sur Kubernetes en utilisant des outils open-source et les meilleures pratiques cloud-native.

À la fin de ce tutoriel, vous serez capable de déployer et de mettre à l'échelle automatiquement des charges de travail GPU sur DOKS en toute confiance, en utilisant la mise à l'échelle pilotée par les événements pour optimiser les performances et les coûts des applications exigeantes en IA/ML et en calcul intensif.

Prérequis

  • Un compte Linux-Console.net avec accès au cluster DOKS.
  • Un jeton API DO avec des autorisations d'écriture
  • Connaissances de base de Kubernetes et Helm

Étape 1 - Créez un cluster DOKS avec prise en charge des GPU AMD

Vous pouvez créer un nouveau cluster DOKS en cliquant sur le bouton Créer en haut à droite de votre tableau de bord Linux-Console.net, ou en naviguant vers Ressources dans votre projet et en sélectionnant :

  1. Kubernetes → Créer un cluster Kubernetes.

    • Choisir la version de Kubernetes et la région

      • Version de Kubernetes : Sélectionnez la dernière version stable pour garantir la sécurité et l'égalité des fonctionnalités.
      • Région : Choisissez une région qui prend en charge les Droplets GPU—TOR1, NYC2 ou ATL1 sont recommandées si vous prévoyez de déployer des AMD MI300X ou d'autres charges de travail GPU.
  2. Ensuite, spécifiez le VPC et les réseaux de services
  3. Une fois que vous avez nommé votre cluster et choisi une région, l'étape suivante consiste à configurer un pool de nœuds—c'est là que vos applications s'exécuteront.

Remarque : Nous recommandons de créer deux pools de nœuds

Pool de nœuds n°1 : Pour les charges de travail GPU

  • Type de GPU : Sous Choisir la capacité du cluster, allez à l'onglet GPU.
  • Type de machine : Sélectionnez un Droplet GPU, tel que AMD MI300X.
  • Nœuds Min/Max : Définissez un minimum de 0 (pour économiser des coûts lorsqu'ils sont inactifs) et un maximum plus élevé en fonction des besoins de charge de travail.

Piscine de nœuds #2 : Pour les charges de travail générales/périphériques

  • Type de Gouttelette : Choisissez Standard, CPU Dédié, ou Optimisé pour la Mémoire, selon les besoins de votre application.
  • Objectif : Ce pool est idéal pour exécuter Prometheus, des tableaux de bord (par exemple, Grafana), KEDA, des API web ainsi que des composants kube-system.
  • Mise à l'échelle automatique : Vous pouvez également activer la mise à l'échelle automatique en option.

Pourquoi deux pools de nœuds ?

Isoler les charges de travail GPU et non-GPU permet un meilleur contrôle de la mise à l'échelle, réduit le gaspillage de ressources et évite les conflits de planification. Les services périphériques n'ont pas besoin de nœuds GPU coûteux.

Remarque : Pour les GPU AMD, le plugin de périphérique GPU AMD est activé par défaut.

Étape 2 - Configurer les pools de nœuds

  • Vérifiez vos sélections.
  • Cliquez sur Créer un cluster Kubernetes.

Remarque : pour les GPU AMD, le plugin de périphérique GPU AMD est activé par défaut. Activez ensuite l'Exportateur de métriques du périphérique GPU AMD, vous pourrez alors utiliser l'API

  -H "Content-Type: application/json" \
  -H "Authorization: Bearer  <your-api-token>" \
  -d '{"name": "<your_cluster_name.", "amd_gpu_device_metrics_exporter_plugin": {"enabled": true}}' \
  "https://api.linux-console.net/v2/kubernetes/clusters/<your-cluster-uuid>"

Étape 3 - Installer le kube-prometheus-stack via Helm

  1. Prometheus surveillera et collectera les métriques personnalisées nécessaires à KEDA.
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install prometheus prometheus-community/kube-prometheus-stack -n kube-system

Étape 3 : Installer KEDA avec Helm KEDA évaluera les métriques de Prometheus et ajustera l'échelle de vos charges de travail en conséquence.

helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda

Étape 4 - Déployer une charge de travail GPU avec des métriques personnalisées

Nous allons déployer une application Go exemple qui expose une métrique de jauge Prometheus. Cette charge de travail demande un GPU et sera mise à l'échelle en fonction de la valeur de la métrique.

Créez un fichier nommé resources.yaml et collez les manifestes suivants :

apiVersion: v1
kind: ConfigMap
metadata:
 name: go-program
data:
 main.go: |
   package main

   import (
       "log"
       "net/http"
       "strconv"
       "github.com/prometheus/client_golang/prometheus"
       "github.com/prometheus/client_golang/prometheus/promhttp"
   )
  
   var customGauge = prometheus.NewGauge(prometheus.GaugeOpts{
       Name: "my_custom_gauge",
       Help: "This is a custom gauge metric",
   })

   func init() {
       prometheus.MustRegister(customGauge)
   }
  
   func handler(w http.ResponseWriter, r *http.Request) {
       value := r.URL.Query().Get("value")
       floatVal, err := strconv.ParseFloat(value, 64)
       if err != nil {
           http.Error(w, "Bad Request: invalid input", http.StatusBadRequest)
           return
      }
       customGauge.Set(floatVal)
       w.Write([]byte("Hello, from the handler!"))
   }

   func main() {
       http.HandleFunc("/", handler)
       http.Handle("/metrics", promhttp.Handler())
       log.Fatal(http.ListenAndServe(":8080", nil))
   }
---
apiVersion: apps/v1
kind: Deployment
metadata:
 name: go-from-configmap
spec:
 replicas: 1
 selector:
   matchLabels:
     app: go-from-configmap
 template:
   metadata:
     labels:
       app: go-from-configmap
   spec:
     nodeSelector:
       doks.linux-console.net/gpu-brand: amd
     tolerations:
       - key: CriticalAddonsOnly
         operator: Exists
       - key: amd.com/gpu
         operator: Exists
     containers:
       - name: go-runner
         image: golang:1.24
         command: ["/bin/sh", "-c"]
         resources:
           requests:
             amd.com/gpu: "1"
           limits:
             amd.com/gpu: "1"
         ports:
           - containerPort: 8080
         args:
           - |
             set -e                                   
             cp /config/*.go /app/
             cd /app
             [ -f go.mod ] || go mod init temp
             go mod tidy                             
             go run .                                 
         volumeMounts:
           - name: go-code
             mountPath: /config
           - name: app-dir
             mountPath: /app
     volumes:
       - name: go-code
         configMap:
           name: go-program
       - name: app-dir
         emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
 name: go-from-configmap
 labels:
   app: go-from-configmap
spec:
 selector:
   app: go-from-configmap
 ports:
   - name: metrics
     port: 8080
     targetPort: 8080
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
 name: go-from-configmap
 labels:
   release: prometheus
spec:
 selector:
   matchLabels:
     app: go-from-configmap
 endpoints:
   - port: metrics
     path: /metrics
     interval: 30s
 namespaceSelector:
   matchNames:
     - kube-system
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
 name: go-from-configmap
spec:
 scaleTargetRef:
   name: go-from-configmap
 pollingInterval: 30
 cooldownPeriod: 30
 minReplicaCount: 1
 maxReplicaCount: 8
 triggers:
   - type: prometheus
     metadata:
       serverAddress: http://prometheus-operated.kube-system.svc.cluster.local:9090
       metricName: my_custom_gauge
       threshold: '80'
       query: sum(my_custom_gauge{}) / sum(kube_deployment_status_replicas{deployment="go-from-configmap"})

Appliquer les ressources :

kubectl apply -f resources.yaml -n <your-namespace>

Étape 5 - Ce que vous venez de déployer

ConfigMap

Nous avons créé un ConfigMap qui stocke un simple serveur HTTP Go sous forme de chaîne. Cette application

  • Serveur HTTP sur le port 8080.
  • Définit une métrique de type gauge Prometheus : my_custom_gauge. Cette métrique représente une valeur de charge simulée et sera le principal moteur de notre logique d'autoscaling.
  • Expose un point de terminaison /metrics compatible avec le scraping Prometheus
  • Offre un point de terminaison racine / où un utilisateur peut mettre à jour une métrique de jauge en appelant /?value=123

Remarque : Cette configuration est uniquement à des fins de démonstration et n'est pas destinée à un usage en production.

Déploiement

Nous définissons un Deployment qui utilise l'image officielle golang:1.24. Au démarrage, il :

  • Monte le ConfigMap et compile dynamiquement le code serveur Go
  • Exécute le programme qui expose les points de terminaison HTTP
  • Demande 1 GPU AMD via les demandes et limites de ressources (amd.com/gpu: 1)

Service

  • La ressource Service permet à Prometheus d'accéder à notre point de terminaison /metrics.
  • Il cible les pods étiquetés app: go-from-configmap
  • Expose le port 8080.

ServiceMonitor

Pour rendre Prometheus conscient de notre point de terminaison de scraping, nous définissons un ServiceMonitor. Cette ressource :

  • Demande à Prometheus de récupérer le service correspondant à l’étiquette app: go-from-configmap
  • Configure le chemin de collecte comme /metrics
  • Définit l'intervalle de récupération sur 30s

Prometheus collectera désormais en continu les dernières valeurs de my_custom_gauge.

ObjetÉchelonné (KEDA)

Le ScaledObject de KEDA relie tout ensemble. Il configure KEDA pour :

  • Utilisez Prometheus comme source de métriques
  • Dit à Keda de surveiller la métrique my_custom_gauge stockée dans Prometheus
  • Et utilisez la requête suivante pour les événements d'auto-scalabilité

En bref, Keda va :

  • Interroger Prometheus toutes les 30 secondes
  • Échelle entre 1 et 8 répliques du déploiement go-from-configmap.
  • Refroidir (réduire) après 30 secondes si la charge diminue.

Étape 6 - Tester l'autoscaling du GPU

Obtenez le nom du pod et exécutez-vous dedans :

kubectl get pods -l app=go-from-configmap 
kubectl exec -it <go-pod-name> -- bash

Réglez le compteur sur une valeur élevée (par exemple 160) :

curl http://127.0.0.1:8080/?value=160
exit

Surveillez la mise à l'échelle des pods :

kubectl get pods -w -l app=go-from-configmap

KEDA évaluera la requête :

160 (valeur du calibre)/1 (réplique)=160, ce qui dépasse le seuil de 80
→ Une deuxième réplique est déclenchée.

À ce stade, le nouveau pod devrait être dans un état en attente puisque nous n’avons pas suffisamment de GPU en fonction des ressources GPU AMD demandées pour ce déploiement. Dans l’interface utilisateur cloud, vous devriez voir un nouvel événement d’autoscaling (un nouveau nœud en cours de lancement) sous le pool de nœuds GPU AMD. Attendez que le nouveau GPU ait terminé son processus de démarrage et vérifiez le pod. Le pod doit être passé de l’état En attente à En cours d’exécution.

La requête est évaluée en continu et la mise à l’échelle s’arrête ou continue en fonction du comportement de la métrique.

Questions fréquemment posées

1. Puis-je utiliser KEDA pour mettre à l'échelle automatiquement tout type de charge de travail GPU sur DOKS ?

Oui. KEDA est indépendant du type de charge de travail tant que vous pouvez exposer une métrique (comme l'utilisation du GPU, la longueur de la file d'attente ou des métriques d'application personnalisées) que Prometheus peut récupérer. Pour les charges de travail GPU AMD, assurez-vous que le plugin de périphérique AMD et l'exportateur de métriques sont activés (par défaut sur les pools de nœuds GPU DOKS).

2. Quelles régions de Linux-Console.net prennent en charge les nœuds GPU AMD pour DOKS ?

Au moment de la rédaction, les nœuds GPU AMD MI300X sont disponibles dans certaines régions telles que TOR1, NYC2 et ATL1. Consultez toujours la documentation de Linux-Console.net pour connaître les dernières régions et types de GPU pris en charge.

3. En quoi KEDA diffère-t-il de l’Horizontal Pod Autoscaler (HPA) intégré à Kubernetes ?

KEDA étend l'autoscaling de Kubernetes en vous permettant de dimensionner les charges de travail en fonction de métriques externes ou personnalisées (comme les requêtes Prometheus, la longueur des files d'attente ou les événements cloud), et pas seulement le CPU ou la mémoire. Cela est particulièrement utile pour les charges de travail GPU où les modèles d'utilisation peuvent ne pas corréler avec l'utilisation du CPU.

4. Que se passe-t-il s'il n'y a pas assez de GPU disponibles dans le pool de nœuds ?

Si votre logique de mise à l'échelle déclenche plus de pods qu'il n'y a de GPU disponibles, les nouveaux pods resteront dans l'état Pending jusqu'à ce que des nœuds GPU supplémentaires soient provisionnés. DOKS mettra automatiquement à l'échelle le pool de nœuds GPU (si l'auto-scalage est activé) pour répondre à la demande accrue, sous réserve des limites que vous avez configurées.

5. Puis-je utiliser cette approche pour d'autres types d'accélérateurs (par exemple, les GPU NVIDIA) ou sur d'autres plateformes Kubernetes ?

Oui. Le modèle KEDA + Prometheus est indépendant de la plateforme et du fournisseur. Vous pouvez adapter cette approche pour les GPU NVIDIA ou d'autres accélérateurs en utilisant le plugin de périphérique approprié et l'exportateur de métriques pour votre matériel et votre distribution Kubernetes.

Conclusion

Ce guide a démontré comment créer une charge de travail GPU à mise à l'échelle automatique sur DOKS en utilisant KEDA et Prometheus, le tout avec des constructions Kubernetes natives et des outils open source.

Cette architecture permet à vos charges de travail de :

  • Redimensionner automatiquement en réponse aux métriques réelles—pas seulement au CPU
  • Optimisez les coûts GPU en gérant dynamiquement les répliques
  • Adaptez-vous facilement à des cas d'utilisation tels que l'inférence en apprentissage automatique, le traitement vidéo ou l'analyse en temps réel

En combinant l'élasticité pilotée par les événements avec une observabilité personnalisée, les équipes peuvent gérer efficacement les ressources GPU et exécuter des charges de calcul haute performance avec une intervention manuelle minimale.

Lectures complémentaires et références

Gouttelettes GPU AMD : MI300X

AMD101 : Charges de travail basées sur les GPU AMD

Plateforme d'application Linux-Console.net vs DOKS vs Droplets : La comparaison ultime pour les équipes de développement

Comment installer la pile de surveillance Prometheus pour un cluster DOKS

Merci d'apprendre avec la communauté Linux-Console.net.