Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
S’applique à : ✔️ AKS Automatic ✔️ AKS Standard
MLOps est un ensemble de pratiques pour le déploiement, la surveillance et la gestion des modèles Machine Learning dans des environnements de production.
Principales pratiques mlOps décrites dans cet article :
- Infrastructure en tant que Code (IaC)
- Mise en conteneur
- Gestion des modèles et contrôle de version
- Automatisation
- Scalabilité et gestion des ressources
- Fiabilité du travail par lots de longue durée
- Sécurité et conformité
Cet article décrit les meilleures pratiques et les considérations à garder à l’esprit quand vous utilisez des MLOps dans AKS. Pour plus d’informations sur les MLOps, consultez Opérations d’apprentissage automatique (MLOps) pour des flux de travail IA et d’apprentissage automatique.
Choisir votre mode AKS pour MLOps
AKS prend en charge deux modes de cluster : AKS Automatic et AKS Standard. Choisissez AKS Automatic lorsque vous souhaitez une base prête pour la production avec moins de gestion opérationnelle de la plateforme au quotidien. Choisissez AKS Standard quand vous avez besoin d’un contrôle plus approfondi sur l’infrastructure de cluster et la configuration de la plateforme.
Les pratiques MLOps de cet article s’appliquent aux deux modes. Toutefois, la responsabilité de l’implémentation diffère par mode : AKS Automatic fournit des valeurs par défaut plus préconfigurées, tandis que AKS Standard nécessite généralement une configuration de plateforme et une propriété de cycle de vie plus explicites.
| Domaine | AKS Automatic | AKS Standard |
|---|---|---|
| Configuration du cluster de référence | Groupes de nœuds préconfigurés, mise en réseau et surveillance intégrés d’emblée | Nécessite une configuration manuelle des pools de nœuds, CNI et pile d’observabilité |
| Opérations du pool de nœuds système | Approvisionnement et mise à l’échelle automatiques des nœuds gérés par le service | L’opérateur doit configurer le dimensionnement du pool de nœuds, les règles de mise à l’échelle et les fenêtres de maintenance |
| Contrôles de base de référence de sécurité | Stratégies réseau, normes de sécurité des pods et identité de charge de travail activées par défaut | Les opérateurs doivent activer et configurer explicitement les stratégies réseau, la sécurité des pods et les paramètres d’identité |
| Base de référence de mise en réseau | Superposition de Azure CNI préconfigurée avec des modèles d’entrée par défaut | Flexibilité totale pour choisir le plug-in CNI, configurer des contrôleurs d’entrée personnalisés et définir la topologie réseau |
| Opérations et mises à niveau | Mises à niveau automatiques de l’image de nœud et de la version de Kubernetes | Les opérateurs planifient et gèrent la stratégie de minutage et de déploiement de mise à niveau |
| Priorités de mise en œuvre du MLOps | Valider, régir et régler les valeurs par défaut | Concevoir et configurer des contrôles de plateforme |
| Capacité du GPU et planification | La capacité GPU éligible peut être provisionnée automatiquement à partir des demandes de ressources de charge de travail et des contraintes de planification, sous réserve de la disponibilité de la référence SKU régionale et du quota d’abonnement | Les opérateurs créent et gèrent des pools de nœuds GPU, des étiquettes, des teintes, des limites de mise à l’échelle automatique, des pilotes et la configuration du plug-in d’appareil |
| Entraînement distribué | L’ordonnancement Kubernetes par défaut et le provisionnement automatique des nœuds fournissent un point de départ ; les opérateurs d’entraînement, les ordonnanceurs de groupes et l’ajustement de la topologie restent des choix propres à chaque charge de travail | Les opérateurs installent explicitement des opérateurs d’entraînement et des planificateurs, et conçoivent des pools de nœuds GPU, la mise en réseau, la mise à l’échelle et le placement pour les tâches distribuées |
Infrastructure en tant que code (IaC)
Points clés : Définissez et versionz des modèles IaC pour chaque étape de votre pipeline IA pour garantir la cohérence, l’efficacité des coûts et les déploiements plus rapides.
IaC permet l’approvisionnement et la gestion d’infrastructure cohérents et reproductibles pour une gamme de types d’applications. Avec différents déploiements d’applications, votre implémentation IaC peut changer dans le pipeline IA, car la puissance de calcul et les ressources nécessaires à l’inférence, au service, à l’entraînement et aux modèles de réglage précis peuvent varier. La définition et le contrôle de version des modèles IaC pour vos équipes de développement IA peuvent vous aider à garantir la cohérence et l’efficacité des types de travaux tout en clarifiant la configuration matérielle requise et en accélérant le processus de déploiement.
Dans AKS Automatic, IaC peut se concentrer davantage sur les définitions de charge de travail, les garde-fous de stratégie et la cohérence de l’environnement sur les valeurs par défaut de la plateforme. Dans AKS Standard, IaC inclut généralement des paramètres de plateforme de cluster plus explicites tels que la mise en réseau, la mise à l’échelle et les choix de configuration opérationnelle.
Mise en conteneur
À retenir : regroupez les poids du modèle, les métadonnées et les configurations dans des images de conteneur afin d'assurer la portabilité, de simplifier la gestion des versions et de réduire les coûts de stockage.
La gestion des pondérations, des métadonnées et des configurations des modèles dans les images conteneur permet d’optimiser la portabilité, de simplifier le contrôle de version et de réduire les coûts de stockage au fil du temps. Avec la conteneurisation, vous pouvez :
- Utilisez des images conteneur existantes, en particulier pour les modèles de langage volumineux (LLMs) allant de millions à milliards de paramètres de taille et de modèles de diffusion stables, stockés dans des registres de conteneurs sécurisés.
- Évitez un point de défaillance unique dans votre pipeline à l’aide de plusieurs conteneurs légers qui contiennent les dépendances uniques pour chaque tâche au lieu de conserver une seule image volumineuse.
- Stockez des jeux de données de texte et d’images volumineux en dehors de votre image conteneur de base et référencez-les si nécessaire au moment de l’exécution. Commencez à utiliser l’opérateur Kubernetes AI Toolchain (KAITO) pour déployer un LLM sur AKS.
Les contrôles de chaîne d’approvisionnement des conteneurs restent essentiels dans les deux modes. Même avec les paramètres par défaut de la plateforme préconfigurés dans AKS Automatic, la provenance des images, l’analyse de sécurité et le durcissement à l’exécution restent des responsabilités essentielles du MLOps.
Modèle Dockerfile pour les charges de travail ML :
Utilisez une balise d’image de base explicite compatible CUDA pour les charges de travail d’entraînement GPU (par exemple) pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtimeau lieu d’une référence d’image de base non marquée. Fixez l’image sur son digest en production afin de garantir des builds reproductibles et un comportement CUDA/cuDNN prévisible. Conservez des variantes d’images CPU et GPU distinctes afin que le placement par le planificateur et les dépendances d’exécution restent explicites.
Gestion des modèles et contrôle de version
Prise en compte essentielle : version de vos modèles systématiquement pour maintenir la cohérence entre les environnements et permettre une itération plus rapide avec des méthodes de réglage précis efficaces des paramètres.
La gestion des modèles et le contrôle de version sont essentiels au suivi des modifications apportées à vos modèles au fil du temps. En versionnant vos modèles, vous pouvez :
- Maintenir une cohérence entre vos conteneurs de modèles pour faciliter leur déploiement dans des environnements distincts.
- Utiliser des méthodes d’ajustement fin économe en paramètres (PEFT) pour itérer plus rapidement sur un sous-ensemble des poids du modèle et conserver les nouvelles versions dans des conteneurs légers.
Dans AKS Automatic, les bases de référence de plateforme préconfigurées peuvent simplifier la parité de l’environnement. Dans AKS Standard, les équipes doivent souvent appliquer la parité plus explicitement via la configuration de la plateforme et du déploiement.
Automatisation
Points clés : Automatiser l’ingestion des données, la surveillance des performances des modèles et les pipelines de réentraînement pour réduire les erreurs manuelles et garantir la cohérence au cours du cycle de vie ml.
L’automatisation permet de réduire les erreurs manuelles, d’augmenter l’efficacité et de garantir la cohérence dans le cycle de vie ml. En automatisant les tâches, vous pouvez :
- Intégrez des outils d’alerte pour déclencher un flux d’ingestion de vecteurs à mesure que de nouvelles données arrivent dans votre application.
- Définir des seuils de performance du modèle pour suivre les dégradations et déclencher des pipelines de réentraînement.
Dans les deux modes AKS, prévoyez une automatisation pour la validation des stratégies, la détection des écarts de configuration et la gouvernance des mises en production, en plus des déclencheurs de qualité des modèles.
Scalabilité et gestion des ressources
Prise en compte essentielle : optimisez l’utilisation des ressources par le biais de l’informatique distribuée, de la mise à l’échelle automatique et de la planification de la reprise d’activité après sinistre pour gérer les demandes de pipeline IA variables de manière rentable.
La scalabilité et la gestion des ressources sont des éléments critiques pour garantir la capacité de votre pipeline IA à gérer les demandes de votre application. En optimisant l’utilisation des ressources, vous pouvez :
- Intégrez des outils qui utilisent efficacement vos ressources processeur, GPU et mémoire allouées par le biais de l’informatique distribuée et de plusieurs niveaux de parallélisme, tels que les données, le modèle et le parallélisme de pipeline.
- Activer la mise à l’échelle automatique de vos ressources de calcul pour prendre en charge les volumes élevés de requêtes adressées aux modèles aux heures de pointe, et effectuer un scale-down durant les heures creuses.
- Planifiez la reprise d’activité après sinistre en suivant les meilleures pratiques en matière de résilience et de fiabilité AKS.
AKS Automatic peut réduire la surcharge de configuration pour les modèles courants de mise à l’échelle et d’opérations, tandis que AKS Standard fournit un contrôle plus approfondi pour les architectures de mise à l’échelle personnalisées.
Exécuter des tâches par lots de longue durée
À retenir : exécutez une tâche de durée limitée comme un Job Kubernetes, enregistrez la progression en dehors du pod, gérez les signaux d’arrêt et supposez que la tâche peut démarrer plus d’une fois.
Les mises à niveau des nœuds, les redémarrages, les événements de scale-down, la pression des ressources, la préemption et les défaillances d’infrastructure peuvent interrompre les tâches par lots de longue durée. Un Kubernetes Job remplace un pod ayant échoué ou supprimé, mais le remplacement démarre sur un autre nœud sans les fichiers locaux ou la mémoire du processus du pod précédent. Concevez l’application pour qu’elle puisse reprendre à partir d’un état persistant et réexécuter les opérations en toute sécurité.
Utilisez ces pratiques pour les tâches de traitement par lots classiques, gourmandes en processeur, en mémoire ou en E/S. Le guide sur l’ordonnancement groupé et la file d’attente des charges de travail s’applique lorsqu’une charge de travail distribuée nécessite que plusieurs processus de travail démarrent simultanément ou lorsque des équipes ont besoin de quotas partagés. Normalement, une tâche par lots unique ou parallèle indépendant n’a pas besoin de planification groupée.
Configurer le point de contrôle, les nouvelles tentatives et l’arrêt
L’exemple suivant traite une séquence d’éléments de travail et enregistre l’élément suivant sur un volume persistant Azure Files. Il restaure le point de contrôle après le remplacement d’un pod et enregistre la progression lorsque le processus reçoit SIGTERM:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: batch-checkpoints
spec:
accessModes:
- ReadWriteMany
storageClassName: azurefile-csi
resources:
requests:
storage: 10Gi
---
apiVersion: batch/v1
kind: Job
metadata:
name: checkpointed-batch
spec:
backoffLimit: 6
activeDeadlineSeconds: 86400
ttlSecondsAfterFinished: 86400
podFailurePolicy:
rules:
- action: Ignore
onPodConditions:
- type: DisruptionTarget
template:
metadata:
labels:
app: checkpointed-batch
spec:
restartPolicy: Never
terminationGracePeriodSeconds: 120
containers:
- name: worker
image: ubuntu:24.04
command:
- /bin/bash
- -c
- |
set -euo pipefail
CHECKPOINT=/checkpoints/next-item
NEXT_ITEM=1
if [[ -f "${CHECKPOINT}" ]]; then
NEXT_ITEM="$(cat "${CHECKPOINT}")"
echo "Resuming at item ${NEXT_ITEM}."
fi
save_checkpoint() {
printf '%s\n' "${NEXT_ITEM}" > "${CHECKPOINT}.tmp"
mv "${CHECKPOINT}.tmp" "${CHECKPOINT}"
echo "Saved checkpoint for item ${NEXT_ITEM}."
}
terminate() {
echo "Received a termination signal."
save_checkpoint
exit 143
}
trap terminate TERM INT
while (( NEXT_ITEM <= 1000 )); do
echo "Processing item ${NEXT_ITEM}."
sleep 10
NEXT_ITEM=$((NEXT_ITEM + 1))
save_checkpoint
done
echo "Batch completed."
resources:
requests:
cpu: "1"
memory: 1Gi
limits:
cpu: "1"
memory: 1Gi
volumeMounts:
- name: checkpoints
mountPath: /checkpoints
volumes:
- name: checkpoints
persistentVolumeClaim:
claimName: batch-checkpoints
Remplacez l’exemple de boucle par votre application batch et sélectionnez le stockage qui répond à ses exigences de débit et de récupération. Utilisez une identité de charge de travail au lieu d’informations d’identification intégrées lorsque l’application enregistre directement ses points de contrôle dans Stockage Blob Azure ou un autre service Azure.
Appliquez délibérément ces contrôles de fiabilité :
-
Points de contrôle et idempotence : enregistrez la progression selon un intervalle conforme à votre objectif de point de reprise. Stockez les points de contrôle et la sortie validée sur le stockage persistant, et non sur le système de fichiers conteneur,
emptyDirou sur le stockage local de nœud. Utilisez des écritures atomiques, des clés d’idempotence, une écriture transactionnelle ou une déduplication, car il peut arriver que le même programme Tâche démarre plus d’une fois. -
Comportement de redémarrage : un Job permet
restartPolicy: NeverouOnFailure. AvecNever, un conteneur en échec produit un pod en échec, et le contrôleur Job crée un pod de remplacement. AvecOnFailure, le kubelet peut redémarrer le conteneur dans le même pod. UtilisezNeverlorsque des pods et des journaux d’activité distincts ont échoué facilitent le diagnostic et facilitent la reprise de l’un ou l’autre chemin d’accès. -
Limites de nouvelle tentative : définissez
backoffLimiten fonction du nombre d’échecs temporaires que la charge de travail peut tolérer. UtilisezpodFailurePolicypour échouer immédiatement en cas de codes de sortie connus pour lesquels aucune nouvelle tentative ne doit être effectuée ou, comme dans l’exemple, pour empêcher que des interruptions volontaires ne consomment le budget de réessais. Une perturbation peut toujours arrêter le pod ; la stratégie modifie uniquement la façon dont la Tâche prend cet échec en compte. -
Échéances : définissez
activeDeadlineSecondsle moment où le travail doit s’arrêter après un runtime total maximal. Le délai inclut les nouvelles tentatives et prévaut surbackoffLimit. Ne définissez pas d’échéance plus courte que le runtime attendu, ainsi que le temps de nouvelle tentative et de récupération. Un travail ayant échoué n’est pas redémarré automatiquement en tant que nouveau travail. -
Arrêt approprié : gérez
SIGTERMl’application et définissezterminationGracePeriodSecondssuffisamment longtemps pour arrêter d’accepter une nouvelle tâche, terminer ou abandonner l’unité actuelle en toute sécurité, vider la sortie et enregistrer un point de contrôle. Kubernetes envoieSIGKILLsi le processus dépasse la période de grâce, de sorte que les points de contrôle périodiques restent nécessaires. -
Nettoyage : définissez
ttlSecondsAfterFinishedou configurez les limites d’historique des CronJobs pour éviter l’accumulation des tâches et des pods terminés. Conservez les enregistrements des tâches suffisamment longtemps pour permettre la collecte des journaux et l’analyse des incidents.
Planifier les évictions et la maintenance des nœuds
Ne considérez pas le blocage de l’éviction comme la principale stratégie de reprise pour une tâche de longue durée. Pour une tâche par lots redémarrable, ne créez normalement pas de PodDisruptionBudget (PDB) ; le contrôleur de tâches crée un pod de remplacement après une perturbation volontaire. Un PDB protège uniquement contre les évictions volontaires et n’offre aucune protection contre la défaillance d’un nœud, les évictions dues à une pression sur les ressources ou la préemption. Un PDB qui n’autorise aucune perturbation peut également bloquer la vidange des nœuds et retarder les mises à niveau d’AKS.
Utilisez une base de données PDB uniquement lorsqu’une charge de tâche par lots parallèle doit conserver un nombre minimal de workers en cours d’exécution simultanée et que vous avez testé son comportement de vidage. De même, utilisez cluster-autoscaler.kubernetes.io/safe-to-evict: "false" uniquement pour des travaux exceptionnels et non démarrageables. L’annotation peut empêcher le scale-down et augmenter les coûts, mais elle ne protège pas contre les défaillances de nœud ou chaque événement de maintenance.
AKS met à niveau le cordon et vide les anciens nœuds avant de les remplacer. Configurez des fenêtres de maintenance planifiée afin d’aligner les opérations de maintenance prises en charge par AKS sur des périodes de moindre impact, mais veillez à ce que la charge de travail puisse être redémarrée, car le calendrier de la maintenance n’élimine pas les interruptions non planifiées. Pour AKS Standard, exécutez des traitements par lots sur un pool de nœuds utilisateur dédié lorsqu’ils nécessitent des tailles de machine virtuelle distinctes, des limites de mise à l’échelle, des taints ou un calendrier de mise à niveau séparés. Évitez les pools de nœuds Spot pour le travail qui ne peuvent pas récupérer à partir de la préemption. Avant la maintenance des nœuds, vérifiez que les points de contrôle récents sont utilisables et qu’un autre pool de nœuds éligible dispose d’un quota et d’une capacité suffisants pour exécuter des pods de remplacement.
Surveiller la progression et la récupération des travaux
Utilisez conjointement l’état, les événements et les journaux Kubernetes lorsque vous analysez une tâche de longue durée :
kubectl get job checkpointed-batch --watch
kubectl describe job checkpointed-batch
kubectl get pods -l batch.kubernetes.io/job-name=checkpointed-batch
kubectl logs job/checkpointed-batch
Activez Azure Monitor service géré pour Prometheus et Container Insights afin de conserver les journaux et de mettre en corrélation l’état de la tâche avec les redémarrages de pod, les évictions, le temps d’attente, l’intégrité des nœuds et l’utilisation des ressources. Instrumentez l’application avec des signaux de progression métier tels que les éléments terminés, les éléments ayant échoué, l’heure du dernier point de contrôle réussi, le taux de traitement, le nombre de nouvelles tentatives et l’heure d’achèvement estimée. Alerte sur une tâche ayant échoué, une tâche qui dépasse sa durée attendue, aucun point de contrôle dans l’objectif de point de récupération, remplacements répétés de pods, pods en attente soutenus et débit de traitement bloqué.
Sécurité et conformité
Point clé : Implémenter l’analyse CVE, les pistes d’audit et les contrôles de conformité pour protéger vos données et répondre aux exigences réglementaires telles que SOC 2, HIPAA et RGPD.
La sécurité et la conformité sont des éléments critiques pour protéger vos données, et garantir la conformité de votre pipeline IA aux exigences réglementaires. En implémentant les meilleures pratiques de sécurité et de conformité, vous pouvez :
- Intégrez l’analyse des vulnérabilités et des expositions courantes (CVE) pour détecter les vulnérabilités courantes sur les images conteneur de modèle open source.
- Utilisez Microsoft Defender pour les conteneurs pour les images conteneur de modèles stockées dans votre instance d’Azure Container Registry.
- Conserver et gérer une piste d’audit des données ingérées, des changements apportés aux modèles et des métriques pour rester en conformité avec vos directives organisationnelles.
- Prenez en charge les frameworks de conformité tels que SOC 2 (via la journalisation d'audit et les contrôles d'accès de Azure), HIPAA (via le chiffrement au repos et en transit, isolation du réseau) et RGPD (via les options de résidence des données et les stratégies de gestion des accès).
Dans AKS Automatic, les valeurs par défaut de sécurité préconfigurées améliorent la posture de référence, mais les contrôles de sécurité au niveau du modèle, au niveau des données et au niveau du pipeline restent requis.
Planifier des charges de travail GPU
À retenir : exposez les GPU via le plug-in de périphérique NVIDIA, demandez explicitement des GPU et isolez les nœuds GPU coûteux à l’aide d’étiquettes, de teintes et de tolérances.
Kubernetes planifie des GPU en tant que ressources étendues. Une fois que le plugin de périphérique NVIDIA a enregistré les GPU sur un nœud, un pod demande un GPU en définissant nvidia.com/gpu dans resources.requests et resources.limits. Le pod suivant demande un GPU et cible un pool de nœuds étiqueté :accelerator=nvidia
apiVersion: v1
kind: Pod
metadata:
name: gpu-training-pod
labels:
app: gpu-training
spec:
restartPolicy: Never
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: trainer
image: nvcr.io/nvidia/cuda:12.4.1-runtime-ubuntu22.04
command:
- /bin/bash
- -c
- |
set -e
nvidia-smi
echo "GPU is available to the training container."
resources:
requests:
cpu: "1"
memory: 2Gi
nvidia.com/gpu: 1
limits:
cpu: "1"
memory: 2Gi
nvidia.com/gpu: 1
Les ressources étendues ne sont pas surcommises. Kubernetes traite une limite GPU comme une requête GPU quand seule la limite est spécifiée, mais la définition des deux champs rend l’intention de charge de travail explicite et aide la validation de stratégie.
Créer un pool de nœuds GPU AKS
Pour AKS Standard, créez un pool de nœuds utilisateur dédié avec une taille de machine virtuelle GPU NVIDIA prise en charge. L’exemple suivant d’Azure CLI crée un pool de nœuds Standard_NC4as_T4_v3 automatiquement mis à l’échelle, applique l’étiquette utilisée par le pod précédent et teinte les nœuds pour repousser les charges de travail qui ne tolèrent pas explicitement les nœuds GPU :
RESOURCE_GROUP=myResourceGroup
AKS_CLUSTER=myAKSCluster
az aks nodepool add \
--resource-group "$RESOURCE_GROUP" \
--cluster-name "$AKS_CLUSTER" \
--name gpunp \
--mode User \
--node-vm-size Standard_NC4as_T4_v3 \
--node-count 0 \
--enable-cluster-autoscaler \
--min-count 0 \
--max-count 4 \
--labels accelerator=nvidia workload=training \
--node-taints sku=gpu:NoSchedule
Avant de créer le pool de nœuds, vérifiez que la référence SKU de machine virtuelle est disponible dans la région du cluster et que l’abonnement dispose d’un quota régional et familial de machines virtuelles suffisant. Sélectionnez une taille de série NC basée sur la mémoire GPU, le nombre de GPU, le ratio PROCESSEUR/GPU, le stockage local, la mise en réseau et les fonctionnalités CUDA requises par l’infrastructure de formation. Par exemple, les tailles NCas T4 v3 conviennent à de nombreuses charges de travail d’entraînement mono-GPU et de plus petite taille, tandis que les tailles NC A100 v4 prennent en charge des modèles plus volumineux et des configurations à plusieurs instances de GPU.
AKS Automatic peut provisionner une capacité de GPU éligible en réponse aux pods en attente. La charge de travail doit toujours demander nvidia.com/gpu, et tous les sélecteurs de nœuds, affinités, tolérances, contraintes de topologie, quotas d’abonnement ainsi que la disponibilité des références SKU régionales doivent pouvoir être satisfaits. Utilisez AKS Standard lorsque vous avez besoin d’une référence SKU de machine virtuelle fixe, d’un cycle de vie de pool de nœuds personnalisé ou d’un contrôle détaillé sur la mise à l’échelle et la topologie du pool GPU.
Vérifier ou installer le plugin de périphérique NVIDIA
Les configurations AKS avec GPU peuvent inclure des pilotes GPU gérés et l’intégration du plug-in de périphérique. Vérifiez la configuration effective avant d’installer un autre plug-in :
kubectl get nodes -L accelerator,kubernetes.azure.com/agentpool
kubectl get daemonsets --all-namespaces | grep -i nvidia
kubectl describe node | grep -A5 -E "Capacity:|Allocatable:|nvidia.com/gpu"
N’exécutez pas plusieurs daemonSets de plug-in d’appareil NVIDIA sur les mêmes nœuds. Si votre configuration AKS ne gère pas le plug-in, le DaemonSet autonome suivant inscrit les GPU NVIDIA auprès du kubelet. Installez une version de plug-in d’appareil prise en charge par votre pilote NVIDIA et les versions de Kubernetes :
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nvidia-device-plugin
namespace: kube-system
labels:
app.kubernetes.io/name: nvidia-device-plugin
spec:
selector:
matchLabels:
app.kubernetes.io/name: nvidia-device-plugin
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/name: nvidia-device-plugin
spec:
priorityClassName: system-node-critical
nodeSelector:
accelerator: nvidia
tolerations:
- operator: Exists
containers:
- name: nvidia-device-plugin
image: nvcr.io/nvidia/k8s-device-plugin:v0.17.1
args:
- --fail-on-init-error=false
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
volumeMounts:
- name: device-plugin
mountPath: /var/lib/kubelet/device-plugins
volumes:
- name: device-plugin
hostPath:
path: /var/lib/kubelet/device-plugins
type: Directory
Vérifiez que nvidia.com/gpu apparaît dans les ressources pouvant être allouées de chaque nœud GPU avant d’envoyer des tâches d’entraînement.
Partitionner des GPU A100 et H100 avec MIG
NVIDIA Multi-Instance GPU (MIG) peut partitionner un GPU A100 ou H100 pris en charge en instances GPU isolées. MIG est utile pour le réglage des hyperparamètres et les travaux d’optimisation plus petits qui ne nécessitent pas un GPU physique entier. Utilisez des GPU complets pour les charges de travail qui nécessitent toutes les mémoires GPU, la bande passante d’interconnexion maximale ou un profil qui n’est pas pris en charge par le GPU installé.
Utilisez l’opérateur GPU NVIDIA et le gestionnaire MIG lorsque vous avez besoin d’une gestion déclarative du cycle de vie MIG. L’opérateur doit posséder le plug-in d’appareil et la configuration MIG pour les nœuds affectés ; ne la combinez pas avec un deuxième plug-in d’appareil autonome. Les noms de profil exacts et le nombre d’instances dépendent du modèle GPU et de la capacité de mémoire. La configuration suivante crée sept 1g.10gb instances sur les configurations 80 Go A100 ou H100 prises en charge :
apiVersion: v1
kind: Namespace
metadata:
name: gpu-operator
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mig-parted-config
namespace: gpu-operator
data:
config.yaml: |
version: v1
mig-configs:
all-disabled:
- devices: all
mig-enabled: false
hptuning-1g10gb:
- devices: all
mig-enabled: true
mig-devices:
"1g.10gb": 7
---
apiVersion: v1
kind: Namespace
metadata:
name: ml-training
---
apiVersion: batch/v1
kind: Job
metadata:
name: mig-hyperparameter-trial
namespace: ml-training
labels:
workload: hyperparameter-tuning
spec:
backoffLimit: 2
template:
metadata:
labels:
workload: hyperparameter-tuning
spec:
restartPolicy: Never
nodeSelector:
accelerator: nvidia
nvidia.com/mig.config: hptuning-1g10gb
nvidia.com/mig.config.state: success
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: trial
image: nvcr.io/nvidia/cuda:12.4.1-runtime-ubuntu22.04
command:
- /bin/bash
- -c
- |
set -e
nvidia-smi
echo "Starting one hyperparameter trial on a MIG instance."
sleep 30
resources:
requests:
cpu: "2"
memory: 8Gi
nvidia.com/mig-1g.10gb: 1
limits:
cpu: "2"
memory: 8Gi
nvidia.com/mig-1g.10gb: 1
Configurez le Gestionnaire MIG de l’opérateur GPU pour utiliser ConfigMap mig-parted-config , utilisez la mixed stratégie MIG lorsque les charges de travail demandent des profils MIG nommés, puis étiquetez les nœuds cibles :
kubectl label nodes \
-l accelerator=nvidia \
nvidia.com/mig.config=hptuning-1g10gb \
--overwrite
La modification d’une configuration MIG perturbe les charges de travail utilisant déjà le GPU. Restreignez et videz le nœud cible, appliquez la configuration pendant une fenêtre de maintenance, puis vérifiez que le profil demandé existe dans les ressources allouables du nœud avant de soumettre des tâches.
Isoler les charges de travail de GPU avec des teintes et des tolérances
Une teinte NoSchedule éloigne les pods d’application ordinaires des nœuds GPU coûteux. L’exemple de création du groupe de nœuds utilise sku=gpu:NoSchedule. Le Job complet suivant comprend la tolération correspondante et un sélecteur de nœud :
apiVersion: batch/v1
kind: Job
metadata:
name: isolated-gpu-training
spec:
backoffLimit: 3
template:
metadata:
labels:
app: isolated-gpu-training
spec:
restartPolicy: Never
nodeSelector:
accelerator: nvidia
workload: training
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: trainer
image: nvcr.io/nvidia/cuda:12.4.1-runtime-ubuntu22.04
command:
- /bin/bash
- -c
- |
set -e
nvidia-smi
sleep 60
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Une tolérance autorise la planification, mais ne force pas le pod vers un nœud GPU. Associez des tolérances à une demande de ressources GPU et à un sélecteur de nœud ou à une affinité de nœud. Assurez-vous que les DaemonSets de plateforme requis, tels que ceux du réseau, de la surveillance, du stockage et du plug-in de périphérique, tolèrent la teinte du GPU.
Exécuter des charges de travail d’entraînement distribuées
À retenir : utilisez un opérateur d’entraînement pour gérer les identités des nœuds de calcul et le cycle de vie des travaux, valider la communication réseau entre plusieurs nœuds et utiliser une admission groupée lorsque tous les nœuds de calcul doivent démarrer ensemble.
L’entraînement distribué utilise plusieurs processus pour diviser les données, l’état du modèle ou les phases de pipeline. Sur Kubernetes, un opérateur peut créer des pods de travail, injecter la configuration rendez-vous, suivre l’état du réplica, redémarrer les nœuds de calcul ayant échoué et nettoyer le travail. Installez et gérez les versions des opérateurs d’entraînement via l’IaC de votre plateforme et son processus de mise en production, plutôt que de permettre à des équipes individuelles d’installer des CRD non gouvernées à l’échelle du cluster.
Créer une image d’entraînement CUDA portable
Le fichier Dockerfile suivant développe le modèle Dockerfile identifié dans la section Conteneurisation. L’image contient le runtime CUDA et les bibliothèques PyTorch, tandis que le pilote NVIDIA compatible reste sur le nœud GPU AKS :
FROM pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime
WORKDIR /workspace
COPY requirements.txt .
RUN python -m pip install --no-cache-dir -r requirements.txt
COPY train.py .
ENTRYPOINT ["python", "/workspace/train.py"]
Fixez l’image de base à l’aide d’un digest immuable en production. Conservez les jeux de données et modifiez fréquemment les points de contrôle en dehors de l’image, puis analysez l’image obtenue avant de l’envoyer à Azure Container Registry.
Exécuter un PyTorchJob
L’opérateur d’entraînement Kubeflow fournit le CRD PyTorchJob. Installez une version d’opérateur de formation compatible avec votre version kubernetes avant d’appliquer ce manifeste. L’exemple suivant à deux réplicas effectue une opération d’all-reduce NCCL entre un nœud et un nœud de calcul :
apiVersion: v1
kind: Namespace
metadata:
name: ml-training
labels:
purpose: ml-training
---
apiVersion: kubeflow.org/v1
kind: PyTorchJob
metadata:
name: pytorch-nccl-example
namespace: ml-training
spec:
runPolicy:
cleanPodPolicy: None
pytorchReplicaSpecs:
Master:
replicas: 1
restartPolicy: OnFailure
template:
metadata:
labels:
training-job: pytorch-nccl-example
spec:
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: pytorch
image: pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime
command:
- python
- -c
- |
import os
import torch
import torch.distributed as dist
torch.cuda.set_device(0)
dist.init_process_group(backend="nccl")
value = torch.tensor(
[float(dist.get_rank() + 1)],
device="cuda"
)
dist.all_reduce(value)
print(
f"rank={dist.get_rank()} "
f"world_size={dist.get_world_size()} "
f"all_reduce_sum={value.item()}"
)
dist.destroy_process_group()
env:
- name: NCCL_DEBUG
value: INFO
- name: NCCL_SOCKET_IFNAME
value: eth0
- name: NCCL_IB_DISABLE
value: "1"
- name: TORCH_NCCL_ASYNC_ERROR_HANDLING
value: "1"
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Worker:
replicas: 1
restartPolicy: OnFailure
template:
metadata:
labels:
training-job: pytorch-nccl-example
spec:
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: pytorch
image: pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime
command:
- python
- -c
- |
import os
import torch
import torch.distributed as dist
torch.cuda.set_device(0)
dist.init_process_group(backend="nccl")
value = torch.tensor(
[float(dist.get_rank() + 1)],
device="cuda"
)
dist.all_reduce(value)
print(
f"rank={dist.get_rank()} "
f"world_size={dist.get_world_size()} "
f"all_reduce_sum={value.item()}"
)
dist.destroy_process_group()
env:
- name: NCCL_DEBUG
value: INFO
- name: NCCL_SOCKET_IFNAME
value: eth0
- name: NCCL_IB_DISABLE
value: "1"
- name: TORCH_NCCL_ASYNC_ERROR_HANDLING
value: "1"
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Pour l’entraînement en production, remplacez le test intégré par votre image d’entraînement versionnée et votre script d’entraînement versionné. Aligner le nombre de réplicas sur le nombre de GPU et de processus requis par l’infrastructure d’entraînement.
Exécuter une tâche TFJob
L’opérateur d’entraînement fournit également le CRD TFJob. L’exemple suivant exécute un entraînement synchrone de TensorFlow sur deux nœuds de calcul GPU en utilisant MultiWorkerMirroredStrategy :
apiVersion: v1
kind: Namespace
metadata:
name: ml-training
labels:
purpose: ml-training
---
apiVersion: kubeflow.org/v1
kind: TFJob
metadata:
name: tensorflow-multiworker-example
namespace: ml-training
spec:
runPolicy:
cleanPodPolicy: None
tfReplicaSpecs:
Worker:
replicas: 2
restartPolicy: OnFailure
template:
metadata:
labels:
training-job: tensorflow-multiworker-example
spec:
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: tensorflow
image: tensorflow/tensorflow:2.16.1-gpu
command:
- python
- -c
- |
import tensorflow as tf
strategy = tf.distribute.MultiWorkerMirroredStrategy()
print("workers:", strategy.num_replicas_in_sync)
with strategy.scope():
model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(32,)),
tf.keras.layers.Dense(64, activation="relu"),
tf.keras.layers.Dense(1)
])
model.compile(
optimizer="adam",
loss="mean_squared_error"
)
features = tf.random.normal([4096, 32])
labels = tf.random.normal([4096, 1])
dataset = (
tf.data.Dataset.from_tensor_slices((features, labels))
.shuffle(4096)
.repeat()
.batch(64)
)
model.fit(dataset, epochs=2, steps_per_epoch=32)
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Pour l’entraînement du serveur de paramètres, définissez Chief, Workeret PS les types de réplicas en fonction de la stratégie de distribution TensorFlow. Mesurez les goulots d’étranglement du réseau et du serveur de paramètres qui en résultent avant d’augmenter le nombre de réplicas.
Ajuster un modèle avec KAITO
KAITO fournit une abstraction d’espace de travail axée sur AKS pour le déploiement de modèles et le réglage précis. Activez le module complémentaire KAITO ou installez une version KAITO compatible avant d’appliquer un Workspace. Vérifiez que la présélection sélectionnée, la référence SKU de machine virtuelle et la méthode de réglage précis sont prises en charge par la version KAITO installée.
L’espace de travail suivant requiert une machine virtuelle avec GPU A100 et lance un ajustement fin QLoRA pour un préréglage Phi-3 pris en charge à l’aide d’un jeu de données accessible au public :
apiVersion: kaito.sh/v1alpha1
kind: Workspace
metadata:
name: workspace-tuning-phi-3-mini
resource:
instanceType: Standard_NC24ads_A100_v4
labelSelector:
matchLabels:
apps: phi-3-mini-tuning
tuning:
preset:
name: phi-3-mini-4k-instruct
method: qlora
input:
urls:
- https://huggingface.co/datasets/yahma/alpaca-cleaned/resolve/main/alpaca_data_cleaned.json
KAITO peut coordonner la configuration prédéfinie du modèle et l’infrastructure GPU nécessaire par l’espace de travail. Pour la production, stockez le jeu de données d’entraînement dans un compte de stockage approuvé Azure, utilisez l’identité d’accès privé et de charge de travail, où elles sont prises en charge, et conservez le modèle obtenu dans un registre de modèles régi ou Azure Container Registry. Traitez le manifeste de l’espace de travail, la version du jeu de données d’entrée, la version prédéfinie, la configuration de l’adaptateur et le digest de l’image de sortie comme un enregistrement d’entraînement avec version.
Configurer la communication NCCL avec AKS CNI
NVIDIA Collective Communications Library (NCCL) gère des opérations collectives comme all-reduce. Pour une base de référence TCP portable sur AKS CNI, utilisez l’interface réseau du pod, normalement eth0, et commencez par NCCL_IB_DISABLE=1. Sur les tailles de machines virtuelles prenant en charge RDMA, utilisez la configuration RDMA NVIDIA et Azure documentée et validez-la avant de définir NCCL_IB_DISABLE=0.
Utilisez ces variables d’environnement de référence :
-
NCCL_SOCKET_IFNAME=eth0sélectionne l’interface réseau du pod. -
NCCL_DEBUG=INFOfournit des diagnostics pendant la validation. Réduisez le niveau de journalisation après le paramétrage. -
NCCL_IB_DISABLE=1sélectionne les sockets TCP quand RDMA n’est pas configuré. -
TORCH_NCCL_ASYNC_ERROR_HANDLING=1permet à PyTorch de s’arrêter au lieu de rester bloqué indéfiniment après des échecs de communication asynchrone.
Si la stratégie réseau est activée, autorisez tout le trafic de rendez-vous et NCCL requis entre les réplicas. NCCL peut négocier des ports dynamiques, de sorte qu’une stratégie de port fixe étroite peut entraîner le blocage des travaux d’entraînement. La stratégie suivante permet une communication pod-à-pod illimitée uniquement entre les réplicas du travail PyTorch et autorise la résolution DNS :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-pytorch-nccl
namespace: ml-training
spec:
podSelector:
matchLabels:
training-job: pytorch-nccl-example
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
training-job: pytorch-nccl-example
egress:
- to:
- podSelector:
matchLabels:
training-job: pytorch-nccl-example
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Évaluez les performances de NCCL indépendamment de l’entraînement du modèle avant d’opérer un scale-out. Comparez la bande passante de l’opération all-reduce, la latence, l’utilisation du GPU et le débit d’entraînement pour chaque nœud de calcul. Un plus grand nombre de nœuds de calcul peut réduire les performances lorsque la communication ou le chargement des données devient le goulot d’étranglement.
Utiliser la planification groupée et les files d’attente de charges de travail
À retenir : traiter les nœuds de calcul distribués comme un groupe et appliquer des quotas de GPU par locataire afin que les tâches partiellement planifiées ne réservent pas de GPU en attendant les nœuds restants.
Le planificateur Kubernetes par défaut place les pods individuellement. Pour un travail distribué qui ne peut pas progresser tant que chaque nœud de calcul n’est pas en cours d’exécution, le placement partiel peut gaspiller la capacité GPU. Kueue fournit le contrôle d’admission et la gestion des quotas avant que les pods ne commencent à s’exécuter. Volcano fournit un planificateur et un modèle de planification tout-ou-rien basé sur PodGroup.
AKS Automatic fournit le planificateur Kubernetes par défaut et l’approvisionnement automatique de nœuds comme point de départ. Envoyez des travaux ordinaires ou des travaux de formation gérés par l’opérateur avec des demandes de ressources précises et laissez la plateforme provisionner la capacité éligible. Ce comportement ne garantit pas d’admission atomique pour chaque nœud de calcul. Installez Kueue ou Volcano lorsqu’une charge de travail nécessite une planification groupée, une mise en file d’attente, des quotas d’équipe, un partage équitable ou un comportement de préemption personnalisé.
Allouer un quota de GPU multi-locataire avec Kueue
Installez une version Kueue compatible avec la version kubernetes et activez les intégrations pour les types de charge de travail que vous utilisez. Le manifeste suivant crée :
- Un GPU
ResourceFlavorassocié aux nœuds étiquetésaccelerator=nvidia. - Quatre GPU
ClusterQueuepour l’équipe A. - Un
ClusterQueueà deux GPU pour l’équipe B. - Un
LocalQueuelimité à l’espace de noms pour chaque équipe. - Un travail à deux nœuds de calcul que Kueue n’admet que lorsque les ressources qu’il demande sont disponibles.
apiVersion: v1
kind: Namespace
metadata:
name: team-a
---
apiVersion: v1
kind: Namespace
metadata:
name: team-b
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
name: nvidia-gpu
spec:
nodeLabels:
accelerator: nvidia
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: team-a-gpu
spec:
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: team-a
queueingStrategy: BestEffortFIFO
resourceGroups:
- flavors:
- name: nvidia-gpu
resources:
- name: cpu
nominalQuota: "64"
- name: memory
nominalQuota: 256Gi
- name: nvidia.com/gpu
nominalQuota: "4"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: team-b-gpu
spec:
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: team-b
queueingStrategy: BestEffortFIFO
resourceGroups:
- flavors:
- name: nvidia-gpu
resources:
- name: cpu
nominalQuota: "32"
- name: memory
nominalQuota: 128Gi
- name: nvidia.com/gpu
nominalQuota: "2"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
name: gpu-queue
namespace: team-a
spec:
clusterQueue: team-a-gpu
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
name: gpu-queue
namespace: team-b
spec:
clusterQueue: team-b-gpu
---
apiVersion: batch/v1
kind: Job
metadata:
name: team-a-two-gpu-training
namespace: team-a
labels:
kueue.x-k8s.io/queue-name: gpu-queue
spec:
suspend: true
completions: 2
parallelism: 2
backoffLimit: 2
template:
metadata:
labels:
app: team-a-two-gpu-training
spec:
restartPolicy: Never
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: worker
image: nvcr.io/nvidia/cuda:12.4.1-runtime-ubuntu22.04
command:
- /bin/bash
- -c
- |
set -e
nvidia-smi
echo "Kueue admitted this worker."
sleep 120
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Un ClusterQueue quota est un quota de planification, et non un quota d’abonnement Azure. Vérifiez que le cluster AKS peut provisionner la capacité de machine virtuelle sous-jacente et que Azure quota GPU est suffisant pour la charge de travail agrégée admise. Utilisez des cohortes et les fonctionnalités de partage équitable de Kueue lorsque les équipes peuvent se prêter du quota inutilisé entre elles.
Utiliser Volcano comme alternative
Volcano est une autre solution si vous avez besoin d’un planificateur de traitements par lots dédié avec la planification groupée, des files d’attente et des stratégies de cycle de vie des tâches. Installez une version de Volcano compatible avec le cluster avant d’appliquer ses CRD. La tâche Volcano suivante nécessite que les deux nœuds de calcul GPU soient disponibles avant que la tâche ne s’exécute :
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: volcano-gpu-training
namespace: default
spec:
minAvailable: 2
schedulerName: volcano
policies:
- event: PodEvicted
action: RestartJob
- event: PodFailed
action: RestartJob
tasks:
- replicas: 2
name: worker
template:
metadata:
labels:
app: volcano-gpu-training
spec:
restartPolicy: OnFailure
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: worker
image: nvcr.io/nvidia/cuda:12.4.1-runtime-ubuntu22.04
command:
- /bin/bash
- -c
- |
set -e
nvidia-smi
echo "All Volcano workers were admitted."
sleep 120
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Standardisez un seul système principal de gestion des files d’attente et d’ordonnancement par groupes, sauf si vous disposez d’une architecture d’interopérabilité éprouvée. La présence de plusieurs contrôleurs d’admission ou ordonnanceurs peut sinon rendre difficile à appréhender le comportement des mises en attente et des préemptions.
Configurer les priorités de formation et d’inférence
L’inférence sensible à la latence nécessite généralement une priorité plus élevée que l’entraînement par lots interromptable. Les ressources PriorityClass suivantes permettent aux pods d’inférence de préempter des pods moins prioritaires tout en empêchant les pods d’entraînement par lots de préempter d’autres charges de travail :
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: training-batch
value: 10000
globalDefault: false
preemptionPolicy: Never
description: Batch training can wait and can be preempted by higher-priority workloads.
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: inference-critical
value: 100000
globalDefault: false
preemptionPolicy: PreemptLowerPriority
description: Latency-sensitive production inference can preempt lower-priority workloads.
Attribuez la classe via spec.priorityClassName dans le modèle de pod. La priorité des pods Kubernetes et la priorité des charges de travail Kueue affectent différentes étapes : Kueue contrôle l’admission dans la file d’attente, tandis que la priorité dans Kubernetes influence la planification et la préemption des pods après l’admission. Coordonnez les deux stratégies afin qu’elles expriment la même priorité métier.
La préemption met fin aux pods de priorité inférieure. Les charges de travail d’entraînement qui peuvent être interrompues doivent enregistrer des points de contrôle sur un stockage persistant, tolérer l’exécution de tâches en double et redémarrer sans dépendre de fichiers locaux au niveau du nœud.
Configurer la mémoire partagée et la gestion des ressources
Clé à prendre : remplacez la petite valeur par défaut /dev/shmdu runtime de conteneur, définissez les demandes de ressources à partir de l’utilisation observée et configurez la mise à l’échelle des nœuds autour des exigences complètes de charge de travail GPU.
Augmentez /dev/shm pour les chargeurs de données ML
Les chargeurs de données PyTorch, les pipelines d’entrée de TensorFlow, NCCL et le module multiprocessing de Python peuvent utiliser la mémoire partagée POSIX. La valeur par défaut du conteneur pour /dev/shm est souvent trop faible pour un entraînement multi-processus, ce qui peut entraîner des plantages des processus de travail, des erreurs de bus ou un blocage apparent de l’entraînement.
Montez un emptyDir en mémoire sur /dev/shm et définissez un sizeLimit explicite :
apiVersion: batch/v1
kind: Job
metadata:
name: shared-memory-training
spec:
backoffLimit: 2
template:
metadata:
labels:
app: shared-memory-training
spec:
restartPolicy: Never
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: trainer
image: pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime
command:
- /bin/bash
- -c
- |
set -e
df -h /dev/shm
python -c '
import multiprocessing as mp
import torch
def worker(index):
value = torch.ones(1024, 1024)
print(f"worker={index}, sum={value.sum().item()}")
if __name__ == "__main__":
processes = [mp.Process(target=worker, args=(i,)) for i in range(4)]
for process in processes:
process.start()
for process in processes:
process.join()
if process.exitcode != 0:
raise SystemExit(process.exitcode)
'
volumeMounts:
- name: shared-memory
mountPath: /dev/shm
resources:
requests:
cpu: "8"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "8"
memory: 16Gi
nvidia.com/gpu: 1
volumes:
- name: shared-memory
emptyDir:
medium: Memory
sizeLimit: 8Gi
L’utilisation de emptyDir basée sur la mémoire est prise en compte dans la consommation de mémoire du pod. Incluez l’utilisation maximale attendue de la mémoire partagée lors de la définition de la limite de mémoire du conteneur. Si /dev/shm dépasse le budget mémoire effectif, le pod peut être expulsé ou arrêté pour avoir dépassé sa limite de mémoire.
Dimensionner le processeur et la mémoire en fonction de l’utilisation observée
Commencez par un benchmark fondé sur un modèle représentatif, la taille de lot, la longueur de séquence, le niveau de parallélisme du chargeur de données, l’augmentation des données et la gestion des points de contrôle. Utilisez ensuite les données de surveillance pour ajuster :
- Définissez des demandes de CPU suffisamment élevées pour alimenter correctement les pipelines d’entrée du GPU. Les périodes d’inactivité gpu persistantes peuvent indiquer une insuffisance de processeur ou de stockage.
- Définissez les demandes de mémoire près de l’utilisation stable du groupe de travail, ainsi qu’une marge de sécurité. Inclure
/dev/shm, le comportement du cache de pages, la surcharge de l’allocateur du framework et les pics de sérialisation des points de contrôle. - Définissez les limites de mémoire au-dessus du pic observé. Analysez
OOMKilledles événements plutôt que d’augmenter à plusieurs reprises les limites sans en identifier la cause. - Évaluez le bridage du processeur avant d’utiliser des limites strictes du processeur. Des limites de CPU trop faibles peuvent réduire l’utilisation du GPU, même lorsque l’utilisation moyenne du CPU semble acceptable.
- Définissez les demandes et les limites égales pour les travaux d’entraînement prévisibles et à valeur élevée lorsque la qualité de service garantie est plus importante que l’empaquetage des nœuds.
- Profilez toutes les modifications significatives de la taille du modèle, de la précision, de la taille du lot, du nombre de workers et du pipeline de données.
Utilisez des percentiles sur des cycles d’entraînement complets plutôt qu’une moyenne calculée sur une courte période. Les phases de démarrage, de validation, de création de point de contrôle et de redistribution des données présentent souvent des pics d’utilisation des ressources distincts.
Configurer la mise à l’échelle automatique du cluster pour un pool de nœuds GPU
Pour AKS Standard, activez l’autoscaler de cluster sur le pool de nœuds utilisateur GPU et définissez la capacité minimale et maximale :
RESOURCE_GROUP=myResourceGroup
AKS_CLUSTER=myAKSCluster
GPU_NODE_POOL=gpunp
az aks nodepool update \
--resource-group "$RESOURCE_GROUP" \
--cluster-name "$AKS_CLUSTER" \
--name "$GPU_NODE_POOL" \
--enable-cluster-autoscaler \
--min-count 0 \
--max-count 8
Vous pouvez paramétrer les paramètres de profil de mise à l’échelle automatique de cluster pris en charge au niveau de l’étendue du cluster. Testez les modifications de profil par rapport aux charges de travail d’entraînement et de service :
az aks update \
--resource-group "$RESOURCE_GROUP" \
--name "$AKS_CLUSTER" \
--cluster-autoscaler-profile \
scan-interval=20s \
scale-down-unneeded-time=10m \
scale-down-delay-after-add=15m \
max-graceful-termination-sec=120
Un pod GPU en attente déclenche une mise à l’échelle uniquement lorsque l’ensemble complet de ses contraintes de planification correspond au modèle d’un pool de nœuds. Vérifiez la demande de ressource GPU, la capacité de machine virtuelle, les étiquettes, les teintes, les tolérances, l'affinité, les contraintes de topologie, la topologie de volume persistant, le nombre maximal de nœuds et Azure quota lorsque le scale-up n'a pas lieu.
La mise à l’échelle à zéro convient aux pools d’entraînement pouvant être interrompus, mais elle ajoute l’approvisionnement de machines virtuelles, l’extraction d’images, le montage de jeu de données et la latence d’initialisation du modèle. Conservez un minimum différent de zéro lorsque la latence de démarrage a un effet matériel sur les objectifs de service. Les budgets de perturbation des pods, les pods ne pouvant pas être supprimés, le stockage local et les longues périodes de grâce d’arrêt peuvent retarder le scale-down.
AKS Automatic gère l’approvisionnement et la mise à l’échelle des nœuds dans le cadre de la base de référence du service. Concentrez-vous sur les requêtes de pod précises et les contraintes prises en charge au lieu de configurer un autoscaler de pool de nœuds GPU manuel.
Stocker des jeux de données et des points de contrôle
Point essentiel : choisissez le stockage en fonction du mode d’accès, du débit, du partage et des exigences de reprise, et conservez les points de contrôle en dehors du nœud afin que l’entraînement puisse reprendre après une éviction ou une préemption.
Conservez des jeux de données volumineux, des artefacts de modèle et des points de contrôle hors des images conteneur. Choisissez une interface de stockage basée sur la charge de travail :
- Utilisez Stockage Blob Azure pour les jeux de données d’objets volumineux, les artefacts de modèle et les référentiels de données à haute capacité.
- Utilisez Azure Files lorsque plusieurs nœuds Worker nécessitent un système de fichiers de style POSIX partagé.
- Utilisez Azure Disk pour les charges de travail de point de contrôle ou de cache en lecture-écriture sur un seul nœud nécessitant des performances élevées, lorsque
ReadWriteOncesuffit. - Utilisez le stockage éphémère local de nœud uniquement pour les caches reconstruits et les fichiers temporaires.
Accéder à de grands ensembles de données avec le pilote CSI Azure Blob
Activez le pilote CSI Blob Azure dans AKS Standard s'il n'est pas déjà activé :
RESOURCE_GROUP=myResourceGroup
AKS_CLUSTER=myAKSCluster
az aks update \
--resource-group "$RESOURCE_GROUP" \
--name "$AKS_CLUSTER" \
--enable-blob-driver
L’exemple suivant crée dynamiquement un conteneur Blob Azure Premium accessible via NFS et le monte dans un pod d’entraînement. Pour un jeu de données régi existant, utilisez un volume défini statiquement ou une configuration BlobFuse avec les contrôles de mise en réseau privés et d’identité appropriés au lieu de créer un conteneur dynamique vide :
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ml-azureblob-nfs
provisioner: blob.csi.azure.com
parameters:
protocol: nfs
skuName: Premium_LRS
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: Immediate
mountOptions:
- -o attr_timeout=120
- -o entry_timeout=120
- -o negative_timeout=120
- -o actimeo=120
- -o noresvport
- -o nconnect=4
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: blob-training-dataset
namespace: default
spec:
accessModes:
- ReadWriteMany
storageClassName: ml-azureblob-nfs
resources:
requests:
storage: 1Ti
---
apiVersion: batch/v1
kind: Job
metadata:
name: inspect-blob-dataset
namespace: default
spec:
backoffLimit: 2
template:
metadata:
labels:
app: inspect-blob-dataset
spec:
restartPolicy: Never
containers:
- name: dataset-reader
image: ubuntu:24.04
command:
- /bin/bash
- -c
- |
set -e
echo "Mounted dataset path:"
df -h /mnt/dataset
find /mnt/dataset -maxdepth 2 -type f | head -100
volumeMounts:
- name: dataset
mountPath: /mnt/dataset
volumes:
- name: dataset
persistentVolumeClaim:
claimName: blob-training-dataset
Évaluez les performances du protocole et des options de montage en fonction de tailles de fragments et de schémas d’accès représentatifs. De nombreux nœuds de calcul lisant un grand nombre de petits fichiers peuvent produire des résultats différents de ceux obtenus par la lecture séquentielle en flux de grands fragments. Envisagez de prétraiter les jeux de données sous forme de fragments de taille appropriée et d’utiliser l’espace de cache local au niveau du nœud lorsque plusieurs époques nécessiteraient sinon de retélécharger les mêmes objets.
Partager des données d’apprentissage avec Azure Files
Azure Files prend en charge ReadWriteMany, ce qui permet à des processus distribués sur différents nœuds de monter le même partage. Le Azure Files Premium est approprié lorsque la charge de travail nécessite des performances prévisibles du système de fichiers et que la région sélectionnée prend en charge l’option de redondance requise.
Le manifeste suivant crée un partage Azure Files Premium et le monte dans deux pods worker parallèles :
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ml-azurefile-premium
provisioner: file.csi.azure.com
parameters:
skuName: Premium_LRS
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: Immediate
mountOptions:
- dir_mode=0770
- file_mode=0660
- uid=1000
- gid=1000
- mfsymlinks
- cache=strict
- actimeo=30
- nosharesock
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-training-data
namespace: default
spec:
accessModes:
- ReadWriteMany
storageClassName: ml-azurefile-premium
resources:
requests:
storage: 100Gi
---
apiVersion: batch/v1
kind: Job
metadata:
name: shared-data-workers
namespace: default
spec:
completions: 2
parallelism: 2
completionMode: Indexed
backoffLimitPerIndex: 2
template:
metadata:
labels:
app: shared-data-workers
spec:
restartPolicy: Never
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: worker
image: ubuntu:24.04
command:
- /bin/bash
- -c
- |
set -e
WORKER_INDEX="${JOB_COMPLETION_INDEX:-0}"
echo "worker=${WORKER_INDEX}" \
> "/mnt/shared/worker-${WORKER_INDEX}.txt"
ls -la /mnt/shared
volumeMounts:
- name: shared-data
mountPath: /mnt/shared
volumes:
- name: shared-data
persistentVolumeClaim:
claimName: shared-training-data
Évitez de devoir énumérer à plusieurs reprises un répertoire contenant des millions de fichiers. Utilisez un manifeste ou une affectation de fragment déterministe pour que chaque nœud de calcul sache quels objets lire.
Point de contrôle vers le stockage persistant
Un point de contrôle doit inclure suffisamment d’informations d’état pour reprendre l’exécution correctement, comme le poids des modèles, l’état de l’optimiseur, l’état du planificateur, l’état du facteur d’échelle, le numéro d’époque ou d’étape, l’état du générateur de nombres aléatoires et la position du chargeur de données, si cette information est prise en charge. Écrivez régulièrement des points de contrôle avant l’arrêt approprié.
Le travail suivant écrit de façon atomique des points de contrôle PyTorch sur Azure Files, restaure le point de contrôle le plus récent après un redémarrage du conteneur ou le remplacement d’un pod, et gère SIGTERM afin que la préemption puisse préserver les progrès récents :
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ml-checkpoints-azurefile
provisioner: file.csi.azure.com
parameters:
skuName: Premium_LRS
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: Immediate
mountOptions:
- dir_mode=0770
- file_mode=0660
- uid=1000
- gid=1000
- mfsymlinks
- cache=strict
- actimeo=30
- nosharesock
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: model-checkpoints
namespace: default
spec:
accessModes:
- ReadWriteMany
storageClassName: ml-checkpoints-azurefile
resources:
requests:
storage: 100Gi
---
apiVersion: batch/v1
kind: Job
metadata:
name: checkpointed-pytorch-training
namespace: default
spec:
backoffLimit: 6
template:
metadata:
labels:
app: checkpointed-pytorch-training
spec:
restartPolicy: OnFailure
terminationGracePeriodSeconds: 120
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: trainer
image: pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime
command:
- python
- -c
- |
import os
import signal
import sys
import time
import torch
checkpoint_path = "/checkpoints/latest.pt"
temporary_path = "/checkpoints/latest.pt.tmp"
state = {"epoch": 0, "value": torch.tensor([0.0])}
if os.path.exists(checkpoint_path):
state = torch.load(checkpoint_path, map_location="cpu")
print(f"Restored epoch {state['epoch']}", flush=True)
def save_checkpoint():
torch.save(state, temporary_path)
os.replace(temporary_path, checkpoint_path)
print(f"Saved epoch {state['epoch']}", flush=True)
def terminate(signum, frame):
print(f"Received signal {signum}", flush=True)
save_checkpoint()
sys.exit(143)
signal.signal(signal.SIGTERM, terminate)
signal.signal(signal.SIGINT, terminate)
for epoch in range(state["epoch"] + 1, 21):
state["epoch"] = epoch
state["value"] += 1
time.sleep(10)
if epoch % 2 == 0:
save_checkpoint()
save_checkpoint()
print("Training completed.", flush=True)
volumeMounts:
- name: checkpoints
mountPath: /checkpoints
resources:
requests:
cpu: "1"
memory: 2Gi
limits:
cpu: "1"
memory: 2Gi
volumes:
- name: checkpoints
persistentVolumeClaim:
claimName: model-checkpoints
Utilisez une Retain stratégie de récupération ou un compte de stockage géré indépendamment pour les points de contrôle de production afin que la suppression d’un PVC ne supprime pas involontairement le seul point de récupération. Pour l’entraînement parallèle distribué sur les données, on confie normalement au rang zéro l’écriture du point de contrôle global, ou bien on utilise un format de point de contrôle fragmenté pris en charge par le framework. Empêchez plusieurs rangs d’écrire simultanément le même fichier.
Testez la récupération en supprimant délibérément un pod de travail pendant une exécution dans un environnement hors production. Vérifiez que le contrôleur recrée la charge de travail, le nouveau pod monte le même volume persistant et que l’entraînement reprend à partir de l’étape attendue.
Surveiller l’utilisation du GPU et le débit d’entraînement
Prise en compte clé : surveillez ensemble le calcul GPU, la mémoire GPU, le débit du pipeline de données, la durée des étapes et l’activité de point de contrôle afin de distinguer la saturation du calcul par le processeur, le réseau ou les goulots d’étranglement du stockage.
Activez Azure Monitor service managé pour Prometheus et Container Insights afin de mettre en corrélation l’état Kubernetes, les journaux de conteneur, l’intégrité des nœuds et les métriques Prometheus. Utilisez les meilleures pratiques de surveillance pour AKS lors de la conception d’alertes, de rétention et de tableaux de bord opérationnels.
Collecter les métriques GPU NVIDIA
L’exportateur NVIDIA Data Center GPU Manager (DCGM) expose les métriques Prometheus pour les GPU NVIDIA. Si l’opérateur GPU NVIDIA déploie déjà l’exportateur DCGM, ne déployez pas d’exportateur en double. Configurez Prometheus managé de Azure Monitor pour récupérer l’exportateur existant.
Le PodMonitor suivant utilise la CRD Prometheus managée d’Azure Monitor et cible les pods de l’exportateur DCGM dans l’espace de noms gpu-operator. Ajustez le sélecteur d’étiquette pour qu’il corresponde aux étiquettes utilisées par votre exportateur installé :
apiVersion: azmonitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: nvidia-dcgm-exporter
namespace: gpu-operator
spec:
selector:
matchLabels:
app: nvidia-dcgm-exporter
podMetricsEndpoints:
- port: metrics
interval: 30s
scrapeTimeout: 10s
Vérifiez le nom du port du service ou du pod de l’exportateur avant d’appliquer le moniteur. Les métriques DCGM courantes sont les suivantes :
| Metric | Purpose |
|---|---|
DCGM_FI_DEV_GPU_UTIL |
Pourcentage de temps actif du GPU |
DCGM_FI_DEV_FB_USED |
Mémoire tampon d’images utilisée |
DCGM_FI_DEV_FB_FREE |
Mémoire tampon de trame libre |
DCGM_FI_DEV_MEM_COPY_UTIL |
Utilisation du moteur de copie de mémoire |
DCGM_FI_DEV_POWER_USAGE |
Consommation d’alimentation GPU |
DCGM_FI_DEV_GPU_TEMP |
Température du GPU |
DCGM_FI_DEV_XID_ERRORS |
Événements d’erreur NVIDIA XID |
La disponibilité des métriques dépend des versions du GPU, du pilote, de DCGM et de l’exportateur.
Exporter les métriques de débit d’entraînement
Instrumentez l’application d’apprentissage avec des métriques au niveau de la charge de travail. Les métriques utiles sont les suivantes :
-
ml_training_samples_totalpour les échantillons cumulés ou les jetons traités. -
ml_training_steps_totalpour les étapes de l’optimiseur terminées. -
ml_training_step_duration_secondspour la latence par étape. -
ml_training_checkpoint_duration_secondspour la latence du point de contrôle. -
ml_training_data_wait_secondspour le temps d’attente des données d’entrée. - Perte spécifique au modèle, taux d’apprentissage, norme de dégradé et métriques de validation.
L’exemple exécutable suivant expose les métriques d’entraînement synthétiques sur le port 8000. Remplacez la simulation par les métriques émises par la boucle d’entraînement réelle :
apiVersion: v1
kind: Namespace
metadata:
name: ml-observability
---
apiVersion: v1
kind: ConfigMap
metadata:
name: training-metrics-server
namespace: ml-observability
data:
server.py: |
import http.server
import threading
import time
state = {
"samples": 0,
"steps": 0,
"last_step_duration": 0.0,
}
def train():
while True:
started = time.time()
time.sleep(1)
state["samples"] += 256
state["steps"] += 1
state["last_step_duration"] = time.time() - started
class MetricsHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path != "/metrics":
self.send_response(404)
self.end_headers()
return
body = (
"# HELP ml_training_samples_total Samples processed.\n"
"# TYPE ml_training_samples_total counter\n"
f"ml_training_samples_total{{job_name=\"metrics-demo\"}} "
f"{state['samples']}\n"
"# HELP ml_training_steps_total Training steps completed.\n"
"# TYPE ml_training_steps_total counter\n"
f"ml_training_steps_total{{job_name=\"metrics-demo\"}} "
f"{state['steps']}\n"
"# HELP ml_training_step_duration_seconds "
"Duration of the most recent training step.\n"
"# TYPE ml_training_step_duration_seconds gauge\n"
f"ml_training_step_duration_seconds"
f"{{job_name=\"metrics-demo\"}} "
f"{state['last_step_duration']}\n"
).encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "text/plain; version=0.0.4")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, format, *args):
return
threading.Thread(target=train, daemon=True).start()
http.server.ThreadingHTTPServer(("0.0.0.0", 8000), MetricsHandler).serve_forever()
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: training-metrics-demo
namespace: ml-observability
spec:
replicas: 1
selector:
matchLabels:
app: training-metrics-demo
template:
metadata:
labels:
app: training-metrics-demo
spec:
containers:
- name: metrics
image: python:3.12-slim
command:
- python
- /app/server.py
ports:
- name: metrics
containerPort: 8000
readinessProbe:
httpGet:
path: /metrics
port: metrics
initialDelaySeconds: 2
periodSeconds: 10
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
volumeMounts:
- name: application
mountPath: /app
readOnly: true
volumes:
- name: application
configMap:
name: training-metrics-server
---
apiVersion: azmonitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: training-metrics-demo
namespace: ml-observability
spec:
selector:
matchLabels:
app: training-metrics-demo
podMetricsEndpoints:
- port: metrics
path: /metrics
interval: 30s
scrapeTimeout: 10s
Pour un travail distribué réel, incluez des étiquettes stables telles que le nom du modèle, la version du modèle, le nom du travail, l’ID d’exécution, le rôle de réplica et l’équipe. N’utilisez pas d’étiquettes non liées telles que des ID d’exemple, des ID de requête ou des chemins de jeu de données bruts, car les étiquettes de cardinalité élevée augmentent le coût de surveillance et la latence des requêtes.
Créer des tableaux de bord GPU et de débit
Utilisez des requêtes PromQL telles que les points de départ suivants et validez les étiquettes de métriques par rapport à votre exportateur :
avg by (namespace, pod, gpu) (
avg_over_time(DCGM_FI_DEV_GPU_UTIL[5m])
)
La requête suivante calcule l’utilisation de la mémoire tampon frame en pourcentage :
100 *
DCGM_FI_DEV_FB_USED
/
(DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE)
La requête suivante calcule les exemples d’entraînement traités par seconde :
sum by (job_name) (
rate(ml_training_samples_total[5m])
)
La requête suivante affiche la durée moyenne des étapes :
avg by (job_name) (
ml_training_step_duration_seconds
)
Interpréter ces signaux ensemble :
- Une faible utilisation du GPU et un temps d’attente élevé des données indiquent généralement le stockage, le réseau, le prétraitement ou la faim du processeur.
- Une utilisation élevée du GPU avec un débit attendu indique que l’accélérateur est utilisé efficacement.
- Une utilisation élevée de la mémoire GPU et des erreurs répétées de type « out of memory » indiquent que la taille du lot, la longueur de séquence, la mémoire d’activation, l’état de l’optimiseur ou la fragmentation doivent être ajustés.
- Une baisse du débit avec une utilisation stable du GPU peut indiquer des séquences plus longues, une surcharge de communication, un comportement thermique ou un changement dans le calcul du modèle.
- Une faible utilisation du GPU sur les GPU alloués indique une capacité inactive qui peut être réduite, mise en file d’attente différemment ou partitionnée avec MIG.
- La durée de point de contrôle longue peut rendre la préemption coûteuse et augmenter la quantité de travail répétée après la récupération.
Créez des alertes pour une sous-utilisation prolongée du GPU, une mémoire GPU proche de la saturation, des erreurs XID, un débit d’entraînement à l’arrêt, des nœuds de calcul en échec, des charges de travail à planification groupée en attente et des points de contrôle qui ne se sont pas terminés dans le délai prévu par l’objectif de point de récupération.
Questions fréquemment posées (FAQ)
Quelle est la différence entre AKS Automatic et AKS Standard pour MLOps ?
AKS Automatic fournit des valeurs par défaut préconfigurées pour les pools de nœuds, la mise en réseau, la sécurité et les mises à niveau, ce qui permet aux équipes MLOps de se concentrer sur les définitions et la gouvernance des charges de travail. AKS Standard nécessite une configuration manuelle de ces composants de plateforme, mais offre un contrôle plus approfondi pour les architectures personnalisées et les exigences de mise à l’échelle.
Comment puis-je versionr des modèles ML dans AKS ?
Versionnez vos modèles en empaquetant les poids des modèles, les métadonnées et les configurations dans des images de conteneur avec des balises de versionnage sémantique. Stockez ces images dans Azure Container Registry et référencez des versions spécifiques dans vos manifestes de déploiement Kubernetes pour garantir la cohérence entre les environnements.
Comment planifier des charges de travail GPU sur AKS ?
Vérifiez que le plug-in d’appareil NVIDIA est disponible afin que les nœuds GPU publient nvidia.com/gpu. Sur AKS Standard, provisionnez un pool de nœuds utilisateur GPU dédié avec une taille de machine virtuelle prise en charge, telle qu’un SKU Standard_NC, et configurez les étiquettes de nœud, une teinte NoSchedule ainsi que les limites de mise à l’échelle automatique du cluster. Dans chaque pod d’entraînement, demandez nvidia.com/gpu, sélectionnez un nœud GPU éligible et ajoutez la tolérance correspondante. AKS Automatic peut approvisionner une capacité GPU éligible à partir de demandes de pods, sous réserve de références SKU prises en charge, de disponibilité régionale, de contraintes de planification et de quota d’abonnement Azure.
Comment exécuter des tâches de formation distribuées sur AKS ?
Installez le Kubeflow Training Operator et soumettez un PyTorchJob ou TFJob pour gérer les réplicas distribués, la configuration de rendez-vous, la stratégie de redémarrage et l’état du travail. KAITO fournit une abstraction d’espace de travail axée sur AKS pour les flux de travail d’optimisation des modèles pris en charge et peut coordonner l’infrastructure GPU avec des présélections de modèle. Pour l’entraînement PyTorch à plusieurs nœuds, configurez et testez la NCCL sur le réseau de pods CNI AKS, autorisez le trafic nœud de calcul à nœud de calcul via la stratégie réseau et utilisez la configuration RDMA prise en charge lorsque la référence SKU et la charge de travail de machine virtuelle sélectionnées le nécessitent.
Comment gérer le quota GPU entre plusieurs équipes ?
Installez Kueue et définissez les ressources ClusterQueue avec le processeur, la mémoire et les quotas de nvidia.com/gpu, puis associez l’espace de noms de chaque équipe au quota qui lui est attribué à l’aide d’un LocalQueue. Utilisez des cohortes Kueue ou un partage équitable lorsque les équipes peuvent emprunter une capacité inutilisée. Volcan est une solution possible lorsque vous avez besoin d’un planificateur de traitement par lots avec admission de nœud de calcul de type tout ou rien. Coordonnez la priorité des files d’attente avec les ressources Kubernetes PriorityClass afin que les tâches d’inférence sensibles à la latence puissent préempter les tâches d’entraînement pouvant l’être et veillez à ce que ces tâches reprennent à partir de points de contrôle sur le stockage persistant.
Quelles sont les meilleures pratiques pour exécuter des travaux de traitement par lots de longue durée sur AKS ?
Utilisez un Kubernetes Job pour un travail fini et un CronJob travail planifié. Conserver les points de contrôle et la sortie validée en dehors du pod, rendre le traitement idempotent, gérer SIGTERMet définir des demandes de ressources explicites, des limites de nouvelle tentative, des délais et des stratégies de nettoyage. Supposons que la maintenance ou l’échec du nœud peut remplacer le pod et tester que le remplacement restaure correctement son point de contrôle. Surveillez l’état de la tâche, les événements du pod, les journaux, l’âge du point de contrôle, le débit et le comportement des nouvelles tentatives. Les jobs redémarrables ordinaires ne nécessitent ni ordonnancement en groupe ni PDB. Utilisez ces contrôles uniquement lorsque les travailleurs parallèles doivent démarrer ensemble ou maintenir une concurrence minimale testée.
Contenu connexe
Découvrez les meilleures pratiques dans d’autres domaines du déploiement d’applications et des opérations sur AKS :
- Comparaison des fonctionnalités AKS Automatic et AKS Standard
- Meilleures pratiques relatives à la résilience et la fiabilité des applications
- Meilleures pratiques relatives à la gestion des ressources
- Meilleures pratiques relatives à la sécurité des pods
- Appliquer les meilleures pratiques avec les mesures de sécurité de déploiement