
Définir les requêtes et limites de ressources (CPU/Mémoire) - pourquoi c'est important
Comprenez l'importance cruciale de définir les requêtes et limites de ressources (CPU, Mémoire) dans Kubernetes pour garantir la stabilité du cluster et la performance des applications.
Le dilemme des ressources partagées dans un cluster Kubernetes
Un cluster Kubernetes est, par nature, un environnement mutualisé où de multiples applications (Pods) s'exécutent sur un ensemble partagé de machines (Noeuds). Chaque noeud dispose d'une quantité finie de ressources matérielles, principalement du CPU et de la mémoire vive (RAM). Sans une gestion appropriée, un risque majeur apparaît : le phénomène du "voisin bruyant" (noisy neighbor). Une application particulièrement gourmande ou mal optimisée pourrait consommer une part disproportionnée des ressources d'un noeud, dégradant ainsi les performances, voire provoquant des pannes, pour toutes les autres applications hébergées sur ce même noeud.
Comment Kubernetes peut-il allouer les ressources de manière équitable et prévisible ? Comment le scheduler peut-il prendre des décisions intelligentes pour placer un nouveau Pod sur un noeud disposant de capacités suffisantes ? Comment éviter qu'un pic de charge sur une application n'entraîne l'arrêt brutal (par manque de mémoire) d'une autre application critique ?
La réponse réside dans la définition explicite des besoins et des limitations de chaque conteneur grâce aux Requests (Requêtes) et Limits (Limites) de ressources. Définir ces paramètres n'est pas une simple option de configuration, c'est une pratique fondamentale pour assurer la stabilité, la performance et l'utilisation efficace de votre cluster Kubernetes.
Resource Requests : garantir un minimum vital pour vos conteneurs
La Requête (Request) de ressource (CPU ou mémoire) spécifie la quantité minimale garantie de cette ressource que Kubernetes doit allouer au conteneur. Le rôle principal des requêtes est d'influencer la décision du scheduler Kubernetes. Lorsqu'un Pod doit être déployé, le scheduler ne considérera que les noeuds capables de satisfaire la somme des requêtes de ressources de tous les conteneurs de ce Pod.
Par exemple, si un conteneur demande 500 millicores (0.5 CPU) et 256 Mebibytes (MiB) de mémoire, le scheduler ne le placera que sur un noeud disposant d'au moins cette capacité disponible. Une fois le Pod placé, cette quantité de ressource lui est réservée sur le noeud, même s'il ne l'utilise pas activement à cet instant précis.
Définir des requêtes appropriées est donc essentiel pour garantir que vos applications disposent des ressources minimales nécessaires pour démarrer et fonctionner correctement. Cela évite les scénarios où un Pod est placé sur un noeud déjà surchargé, conduisant à une instabilité immédiate. Les requêtes sont la base de la prévisibilité et de la garantie de service dans Kubernetes.
Resource Limits : plafonner la consommation maximale
La Limite (Limit) de ressource définit la quantité maximale de CPU ou de mémoire qu'un conteneur est autorisé à consommer sur un noeud. Les limites servent à contenir les applications et à les empêcher de monopoliser les ressources au détriment des autres.
Le comportement lorsqu'une limite est atteinte diffère selon la ressource :
- Limite CPU : Si un conteneur tente d'utiliser plus de CPU que sa limite, il sera "throttlé" (bridé). Son utilisation du CPU sera artificiellement plafonnée à la valeur de la limite. L'application ralentira, mais ne sera pas tuée.
- Limite Mémoire : Si un conteneur tente d'allouer plus de mémoire que sa limite, il risque d'être tué par le système. Sur Linux, le mécanisme OOM (Out Of Memory) Killer interviendra et mettra fin au processus qui dépasse la limite pour protéger la stabilité du noeud. Pour Kubernetes, cela se traduit par un Pod dont le statut devient `OOMKilled`, puis qui est généralement redémarré.
Définir des limites est crucial pour protéger la stabilité globale du cluster. Elles empêchent une application de causer une dégradation généralisée des performances ou des pannes en cascade sur un noeud en raison d'une consommation excessive de ressources (par exemple, suite à une fuite mémoire ou un pic de charge inattendu).
Unités de mesure et configuration YAML
Il est important de comprendre les unités utilisées pour définir les requêtes et limites :
- CPU : L'unité de base est le "core" Kubernetes, qui peut correspondre à un vCPU cloud, un hyperthread ou un core physique selon l'infrastructure. On utilise très souvent les millicores (ou millicpu), représentés par la lettre `m`. Ainsi, `500m` signifie 0.5 core CPU, `100m` signifie 0.1 core CPU, et `1` signifie 1 core CPU complet.
- Mémoire : La mémoire est mesurée en octets (bytes). On utilise les suffixes de puissance de deux standard : `Ki` (Kibioctet), `Mi` (Mebioctet), `Gi` (Gibioctet), etc. Par exemple, `128Mi` représente 128 Mebioctets, `1Gi` représente 1 Gibioctet.
Voici comment définir les requêtes et limites dans la section `resources` d'un conteneur dans un manifeste YAML :
apiVersion: v1
kind: Pod
metadata:
name: mon-app-ressources
spec:
containers:
- name: mon-app-container
image: mon-app:latest
resources:
requests:
memory: "128Mi" # Requête minimale de mémoire garantie
cpu: "250m" # Requête minimale de CPU garantie (0.25 core)
limits:
memory: "512Mi" # Limite maximale de mémoire (tué si dépassée)
cpu: "1" # Limite maximale de CPU (throttlé si dépassée)Il est recommandé de toujours définir les requêtes. Définir les limites est également fortement conseillé, en particulier pour la mémoire, afin d'éviter les OOMKills incontrôlés qui pourraient affecter d'autres Pods.
Impact sur la Qualité de Service (QoS) et conclusion
La manière dont vous définissez (ou non) les requêtes et limites pour les conteneurs d'un Pod détermine sa Classe de Qualité de Service (QoS Class) attribuée par Kubernetes. Il y a trois classes :
- Guaranteed : Tous les conteneurs du Pod ont des limites et des requêtes définies pour CPU et mémoire, et les limites sont égales aux requêtes pour chaque ressource. Ces Pods ont la plus haute priorité et sont les moins susceptibles d'être tués en cas de pénurie de ressources sur le noeud.
- Burstable : Au moins un conteneur dans le Pod a une requête ou une limite de CPU ou de mémoire définie, mais les critères pour `Guaranteed` ne sont pas remplis (par exemple, limites > requêtes, ou seulement des requêtes définies). Ces Pods ont une priorité moyenne.
- BestEffort : Aucun conteneur dans le Pod n'a de requête ou de limite définie pour CPU ou mémoire. Ces Pods ont la plus basse priorité et sont les premiers à être tués en cas de manque de ressources sur le noeud. Il est fortement déconseillé d'utiliser cette classe pour des charges de travail de production.
En conclusion, définir des requêtes et des limites de ressources n'est pas une simple optimisation, c'est une nécessité pour opérer des applications fiables et performantes sur Kubernetes. Les requêtes garantissent que vos Pods obtiennent les ressources minimales dont ils ont besoin et permettent au scheduler de fonctionner efficacement. Les limites protègent vos applications et le cluster contre les consommations excessives et imprévues. En définissant judicieusement ces valeurs, vous améliorez la stabilité, la prévisibilité et l'efficacité de votre infrastructure Kubernetes, tout en vous assurant que vos applications critiques bénéficient de la priorité appropriée grâce aux classes QoS.