Maîtriser les Requêtes et Limites de Ressources Kubernetes pour des Performances Optimales
Kubernetes offre de puissantes capacités pour automatiser le déploiement, la mise à l'échelle et la gestion des applications conteneurisées. Cependant, atteindre des performances maximales et maintenir la stabilité sur l'ensemble de votre cluster dépend de manière critique de la façon dont vous définissez les exigences de ressources pour vos charges de travail. Des paramètres de ressources incorrects sont une source principale de goulots d'étranglement de performance, de planification imprévisible et d'utilisation inefficace du cluster.
Ce guide explore en profondeur les Requêtes de Ressources et les Limites de Kubernetes. Comprendre la distinction et les appliquer correctement est fondamental pour garantir la Qualité de Service (QoS) pour vos applications, prévenir les voisins bruyants ("noisy neighbors") et optimiser vos dépenses d'infrastructure. Nous examinerons comment ces paramètres interagissent avec le planificateur Kubernetes et le système d'exploitation sous-jacent.
Comprendre les Concepts de Base : Requêtes contre Limites
Dans Kubernetes, chaque spécification de conteneur au sein d'un Pod doit définir sa consommation de ressources attendue en utilisant resources.requests et resources.limits. Ces paramètres régissent le CPU et la Mémoire, les deux ressources les plus critiques pour la santé de l'application.
1. Requêtes de Ressources (requests)
Les Requêtes représentent la quantité de ressources qu'un conteneur est garanti de recevoir lors de la planification. C'est le montant minimum de ressources que le kube-scheduler utilise lorsqu'il décide sur quel nœud placer un Pod.
- Planification : Un nœud doit disposer de suffisamment de ressources allouables disponibles qui satisfassent la somme de toutes les requêtes des Pods avant qu'un nouveau Pod puisse y être planifié.
- Garanties : Si le nœud vient à manquer de ressources plus tard, le conteneur recevra toujours au moins la quantité demandée (sauf s'il est sujet à l'éviction).
2. Limites de Ressources (limits)
Les Limites définissent la quantité maximale de ressources qu'un conteneur est autorisé à consommer. Le dépassement de ces limites entraîne des comportements spécifiques et définis pour le CPU et la Mémoire.
- Limites CPU : Si un conteneur tente d'utiliser plus de CPU que sa limite, les cgroups du noyau Linux limiteront son utilisation, l'empêchant de consommer d'autres cycles.
- Limites Mémoire : Si un conteneur dépasse sa limite de mémoire, le système d'exploitation terminera immédiatement le processus (OOMKill : Out Of Memory Kill).
Comportement CPU contre Mémoire
Il est crucial de comprendre la différence qualitative dans la manière dont Kubernetes applique les limites CPU par rapport à la Mémoire :
| Ressource | Comportement en cas de dépassement de limite | Mécanisme d'Application |
|---|---|---|
| CPU | Limité (ralenti) | cgroups (contrôle de bande passante cpu) |
| Mémoire | Terminé (OOMKill) | Tueur OOM du noyau |
Astuce : Comme la limitation du CPU est généralement moins perturbatrice qu'un OOMKill, il est souvent préférable de définir une limite CPU légèrement supérieure à votre utilisation maximale typique, tout en définissant une limite de mémoire stricte pour éviter l'instabilité du nœud.
Définir les Ressources dans les Spécifications de Pod
Les ressources sont définies dans le bloc spec.containers[*].resources. Les quantités sont spécifiées en utilisant les suffixes standards de Kubernetes (par exemple, m pour milli-CPU, Mi pour Mébioctets).
Définitions d'Unités CPU
1unité CPU équivaut à 1 cœur complet (ou vCPU sur les fournisseurs cloud).1000m(millicoeurs) équivaut à 1 unité CPU.
Définitions d'Unités Mémoire
Mi(Mébioctets) ouGi(Gibioctets) sont courants.1024Mi=1Gi.
Exemple de Configuration YAML
Considérez un conteneur qui nécessite un minimum garanti de 500m CPU et 256Mi de mémoire, mais qui ne doit jamais dépasser 1 CPU et 512Mi :
resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1"
Classes de Qualité de Service (QoS)
La relation entre les Requêtes et les Limites détermine la Classe de Qualité de Service (QoS) attribuée à un Pod. Cette classe dicte la priorité du Pod lorsque les ressources se raréfient et que le nœud doit récupérer de la mémoire (éviction).
Kubernetes définit trois classes QoS :
1. Garantie (Guaranteed)
Définition : Tous les conteneurs du Pod doivent avoir des Requêtes et des Limites identiques et non nulles pour à la fois le CPU et la Mémoire.
- Avantage : Ces Pods sont les derniers à être évincés en cas de pression sur les ressources, assurant une stabilité maximale.
- Cas d'Usage : Composants système critiques ou bases de données nécessitant un isolement de performance strict.
2. Évolutif (Burstable)
Définition : Au moins un conteneur dans le Pod a des Requêtes définies, mais soit les Requêtes et les Limites ne sont pas égales pour tous les conteneurs, soit certaines ressources ne sont pas limitées (bien que définir des limites soit fortement recommandé).
- Avantage : Permet aux conteneurs de dépasser leurs requêtes, en utilisant la capacité inutilisée du nœud, jusqu'à leurs limites définies.
- Priorité d'Éviction : Évincés avant les Pods BestEffort, mais après les Pods Guaranteed.
- Cas d'Usage : La plupart des applications stateless standard où une légère variation de latence est acceptable.
3. Meilleur Effort (BestEffort)
Définition : Le Pod n'a aucune Requête ou Limite définie pour aucun conteneur.
- Avantage : Aucun, à part la simplicité.
- Risque : Ces Pods sont les premières cibles d'éviction lorsque le nœud subit une pression sur les ressources. Ils sont également sujets à une limitation ou à des OOMKills immédiats si la capacité du nœud est dépassée.
- Cas d'Usage : Tâches par lots non critiques ou agents de journalisation qui peuvent être facilement redémarrés.
Stratégies d'Optimisation Pratiques
Une gestion efficace des ressources nécessite de la mesure, de l'itération et une planification minutieuse.
Stratégie 1 : Mesurer et Définir les Requêtes avec Précision
Les Requêtes doivent refléter la charge typique ou minimale durable dont votre application a besoin. Si vous définissez des requêtes trop élevées, vous gaspillez la capacité du cluster car le planificateur réserve cette ressource même si le conteneur ne l'utilise pas.
Meilleure Pratique : Utilisez des outils de surveillance (tels que Prometheus/Grafana) pour analyser les données d'utilisation historiques. Définissez les requêtes près du 90e centile de l'utilisation observée en fonctionnement normal.
Stratégie 2 : Définir des Limites Conservatrices
Les Limites agissent comme un filet de sécurité. Pour la mémoire, définissez toujours des limites légèrement supérieures à votre pic mesuré pour éviter les plantages. Pour le CPU, définir des limites empêche un processus défaillant d'affamer les processus frères critiques sur le même nœud.
Avertissement sur les Limites CPU : Définir des limites CPU trop agressives (par exemple, 50 % du besoin réel) entraîne une dégradation sévère des performances due à une limitation constante. Privilégiez toujours la QoS Burstable, sauf si vous avez un besoin spécifique d'isolement Garanti.
Stratégie 3 : Tirer Parti de l'Autoscaler Vertical de Pod (VPA)
L'ajustement manuel des ressources est difficile et chronophage. L'Autoscaler Vertical de Pod (VPA) surveille l'utilisation à l'exécution et ajuste automatiquement les Requêtes et les Limites définies dans vos spécifications de Pod au fil du temps. VPA aide à faire passer les charges de travail d'états mal configurés (ou BestEffort) à des configurations Burstable ou Guaranteed optimales.
Stratégie 4 : Quotas de Ressources pour les Espaces de Noms
Pour empêcher l'accaparement des ressources entre équipes ou environnements, les administrateurs doivent utiliser des Quotas de Ressources au niveau de l'Espace de Noms. Un ResourceQuota impose des limites agrégées sur la quantité totale de Requêtes et de Limites de CPU/Mémoire pouvant exister dans cet espace de noms, assurant l'équité.
Exemple de Quota d'Espace de Noms
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: development
spec:
hard:
requests.cpu: "10"
limits.memory: "20Gi"
Ceci garantit que le CPU total demandé par tous les Pods dans l'espace de noms development ne peut pas dépasser 10 cœurs, et que les limites totales de mémoire ne peuvent pas dépasser 20Gi.
Conclusion
Maîtriser les Requêtes et Limites de Ressources Kubernetes ne consiste pas seulement à prévenir les plantages ; il s'agit d'obtenir des performances prévisibles et de maximiser le retour sur votre investissement en infrastructure. En définissant correctement les Requêtes pour l'assurance de la planification et les Limites pour la sécurité contre la consommation débridée, vous élevez vos Pods à la classe QoS souhaitée (de préférence Burstable ou Guaranteed). Examinez régulièrement les métriques de performance et envisagez d'utiliser des outils comme VPA pour maintenir un alignement optimal des ressources à mesure que vos applications évoluent.