Contactez-nous

Définir les requêtes (requests) et les limites (limits) de CPU et mémoire

Apprenez à définir précisément les requêtes (requests) et limites (limits) de CPU et mémoire pour vos conteneurs Kubernetes, un pilier de la performance et stabilité.

Requests et Limits : les gardiens des ressources conteneurs

Au coeur de la gestion des ressources dans Kubernetes se trouvent deux concepts fondamentaux que vous pouvez spécifier pour chaque conteneur au sein d'un Pod : les requêtes (requests) et les limites (limits). Ces paramètres permettent de déclarer les besoins et les plafonds de consommation pour le CPU et la mémoire, donnant ainsi des informations cruciales au système pour l'ordonnancement et la gestion de l'exécution.

Comprendre la distinction et l'impact de ces deux valeurs est essentiel. Les requests influencent principalement la décision du Scheduler Kubernetes : elles indiquent la quantité minimale de ressource que le conteneur est censé nécessiter pour fonctionner correctement. Un Pod ne sera ordonnancé sur un noeud que si ce dernier dispose d'assez de ressources non allouées pour satisfaire la somme des requests de tous les conteneurs du Pod.

Les limits, quant à elles, définissent le plafond maximum absolu de ressource qu'un conteneur est autorisé à consommer sur le noeud. Elles sont appliquées par le système d'exploitation du noeud (via les cgroups Linux) pendant l'exécution du conteneur pour éviter qu'il ne dépasse cette borne et n'impacte les autres processus ou le système lui-même.

Spécifier les ressources CPU

La ressource CPU est considérée comme 'compressible'. Si un conteneur atteint sa limite CPU, il ne sera pas terminé mais plutôt throttlé (ralenti). Il obtiendra moins de temps de calcul alloué par le système d'exploitation.

  • CPU Requests (requests.cpu) : Indique la quantité minimale de CPU garantie au conteneur. Le Scheduler utilise cette valeur pour le placement. Si un noeud a 4 coeurs et que la somme des requests CPU des Pods déjà présents est de 3.5 coeurs, un nouveau Pod demandant 1 coeur ne pourra pas y être placé. La request détermine également la part relative de CPU que le conteneur recevra en cas de contention (un conteneur demandant 200m recevra deux fois plus de temps CPU qu'un autre demandant 100m, si les deux tentent d'utiliser plus que leur request). L'unité CPU est exprimée en 'cores' (coeurs). On utilise souvent les millicores (m). 1000m équivaut à 1 core vCPU/Hyperthread. 500m représente un demi-coeur.
  • CPU Limits (limits.cpu) : Définit le plafond maximum de CPU que le conteneur peut utiliser. Si un conteneur tente d'utiliser plus de CPU que sa limite, il sera throttlé. Par exemple, avec une limite de 100m, un conteneur ne pourra pas utiliser plus de 10% d'un coeur CPU sur une période donnée. Si la limite n'est pas définie, le conteneur peut potentiellement utiliser tout le CPU disponible sur le noeud.

Exemple de définition dans le manifeste d'un conteneur :

apiVersion: v1
kind: Pod
metadata:
  name: cpu-example-pod
spec:
  containers:
  - name: cpu-demo-ctr
    image: nginx
    resources:
      requests:
        cpu: "100m" # Garantit 0.1 coeur
      limits:
        cpu: "200m" # Plafond à 0.2 coeur

Spécifier les ressources Mémoire

La mémoire est une ressource 'incompressible'. Si un conteneur tente d'utiliser plus de mémoire que sa limite, il ne peut pas être simplement ralenti. Il sera généralement terminé par le système d'exploitation : c'est le fameux OOMKill (Out Of Memory Killer).

  • Memory Requests (requests.memory) : Indique la quantité minimale de mémoire garantie pour le conteneur. Comme pour le CPU, le Scheduler utilise cette valeur pour décider si un Pod peut être placé sur un noeud. Un Pod ne sera placé que si le noeud a suffisamment de mémoire disponible (non allouée par les requests d'autres Pods) pour satisfaire sa demande. Cette valeur influence aussi fortement la classe de QoS du Pod (voir section suivante) et donc sa probabilité d'être tué en cas de pression mémoire sur le noeud.
  • Memory Limits (limits.memory) : Définit le plafond maximum absolu de mémoire (RAM) que le conteneur peut allouer. Si le processus dans le conteneur tente de dépasser cette limite, le noyau Linux via les cgroups le terminera brutalement (OOMKill). Il est crucial de définir une limite mémoire pour éviter qu'un conteneur avec une fuite mémoire ne consomme toute la RAM du noeud et ne le déstabilise. Si la limite n'est pas définie, le Pod peut utiliser toute la mémoire disponible et est plus susceptible d'être tué en cas de pénurie sur le noeud (classé BestEffort ou Burstable selon la request).

L'unité pour la mémoire est le byte. On utilise couramment les suffixes de puissance de 2 (binaires) : Ki (Kibioctet), Mi (Mebioctet), Gi (Gibioctet), ou de puissance de 10 (décimaux) : k, M, G. Il est fortement recommandé d'utiliser les unités binaires (Ki, Mi, Gi) pour la cohérence.

Exemple de définition dans le manifeste d'un conteneur :

apiVersion: v1
kind: Pod
metadata:
  name: memory-example-pod
spec:
  containers:
  - name: memory-demo-ctr
    image: ubuntu
    command: ["/bin/bash", "-c", "sleep infinity"]
    resources:
      requests:
        memory: "64Mi"  # Garantit 64 Mebioctets
      limits:
        memory: "128Mi" # Plafond à 128 Mebioctets (sinon OOMKill)

Importance et considérations

Définir correctement les requests et limits est un exercice d'équilibre crucial pour la santé de votre cluster et de vos applications :

  • Ne pas définir de requests/limits : Le Pod est classé BestEffort. Il n'a aucune garantie de ressource et peut être tué en premier en cas de contention. Il peut aussi consommer beaucoup de ressources sans contrôle. Non recommandé en production.
  • Définir uniquement les requests : Le Pod est classé Burstable. Il a une garantie de base mais peut utiliser plus de ressources (jusqu'aux limites du noeud si aucune limite n'est fixée). Il est moins prioritaire qu'un Pod Guaranteed en cas de pénurie.
  • Définir requests et limits identiques : Le Pod est classé Guaranteed. C'est le plus haut niveau de priorité. Idéal pour les applications critiques, mais peut conduire à un gaspillage de ressources si les valeurs sont surestimées.
  • Définir requests < limits : Le Pod est classé Burstable. Il a une garantie (request) et un plafond (limit), lui permettant de consommer plus temporairement si les ressources sont disponibles. C'est un compromis courant.

Il est essentiel de monitorer la consommation réelle de vos applications pour ajuster ces valeurs. Des requests trop basses peuvent conduire à un placement sur des noeuds qui deviendront surchargés. Des requests trop hautes gaspillent des ressources. Des limites trop basses peuvent tuer ou ralentir inutilement votre application. Des limites trop hautes (ou absentes) peuvent déstabiliser les noeuds.

En résumé, les requests dictent l'ordonnancement et fournissent une garantie minimale, tandis que les limits imposent un plafond strict pour protéger le noeud. La bonne définition de ces paramètres est une étape clé vers des déploiements Kubernetes robustes et efficaces.