Guide complet sur les Cgroups systemd pour la limitation et l'isolation des ressources

Maîtrisez la gestion des ressources Linux avec systemd et cgroups. Ce guide explique comment utiliser les tranches (slices), les scopes et les services systemd pour appliquer des limites précises de CPU, de mémoire et d'E/S. Apprenez à isoler les processus critiques, à prévenir l'épuisement des ressources et à assurer la stabilité du système grâce à des exemples pratiques et des meilleures pratiques pour une optimisation efficace des performances.

35 vues

Guide Complet sur les Cgroups Systemd pour la Limitation et l'Isolation des Ressources

Systemd, le système d'initialisation moderne et le gestionnaire de systèmes et de services pour Linux, offre des outils puissants pour gérer les ressources système. Parmi ses capacités les plus significatives se trouve l'intégration avec les Control Groups (cgroups), une fonctionnalité du noyau Linux qui permet la limitation, la comptabilité et l'isolation de l'utilisation des ressources (CPU, mémoire, E/S disque, réseau, etc.) pour un ensemble de processus. Ce guide explorera comment systemd utilise les cgroups à travers ses types d'unités — slices, scopes et services — pour permettre une limitation et une isolation précises des ressources, garantissant que les processus critiques reçoivent les ressources dont ils ont besoin tout en empêchant les applications incontrôlables d'affecter la stabilité du système.

Comprendre et exploiter l'intégration de systemd avec les cgroups est crucial pour les administrateurs système, les développeurs et toute personne responsable du maintien de la performance et de la fiabilité des systèmes Linux. En définissant des limites de ressources appropriées, vous pouvez prévenir l'épuisement des ressources, améliorer la prévisibilité des performances des applications et renforcer la stabilité globale du système. Ce guide offrira une approche pratique pour configurer ces limites, rendant la gestion complexe des ressources accessible et efficace.

Comprendre les Control Groups (cgroups)

Avant de plonger dans l'implémentation de systemd, il est essentiel de saisir les concepts fondamentaux des cgroups. Les cgroups sont un mécanisme hiérarchique du noyau Linux qui vous permet de regrouper des processus et d'assigner ensuite des politiques de gestion des ressources à ces groupes. Ces politiques peuvent inclure :

  • CPU : Limitation du temps CPU, priorisation de l'accès CPU.
  • Mémoire : Définition des limites d'utilisation de la mémoire, prévention des conditions de manque de mémoire (OOM).
  • E/S : Régulation des opérations de lecture/écriture sur disque.
  • Réseau : Limitation de la bande passante réseau.
  • Accès aux périphériques : Contrôle de l'accès à des périphériques spécifiques.

Le noyau expose les configurations des cgroups via un système de fichiers virtuel, généralement monté à /sys/fs/cgroup. Chaque contrôleur (par exemple, cpu, memory) possède son propre répertoire, et au sein de ceux-ci, des hiérarchies de répertoires représentent les groupes et leurs limites de ressources associées.

Architecture de gestion des Cgroups par Systemd

Systemd abstrait la complexité de la manipulation directe des cgroups en fournissant un système structuré de gestion d'unités. Il organise les processus en une hiérarchie d'unités, qui sont ensuite mappées aux hiérarchies de cgroups. Les principaux types d'unités pertinents pour la gestion des ressources sont :

  • Slices : Ce sont des conteneurs abstraits pour les unités de service. Les slices forment une hiérarchie, permettant la délégation de ressources. Par exemple, une slice pour les sessions utilisateur peut contenir des slices pour des applications individuelles. Systemd crée automatiquement des slices pour les services système, les sessions utilisateur et les machines virtuelles/conteneurs.
  • Scopes : Ils sont généralement utilisés pour des groupes de processus temporaires ou créés dynamiquement, souvent associés à des sessions utilisateur ou à des services système qui ne sont pas gérés comme des unités de service complètes. Ils sont transitoires et existent tant que les processus qu'ils contiennent sont en cours d'exécution.
  • Services : Ce sont les unités fondamentales pour la gestion des démons et des applications. Lorsqu'une unité de service est démarrée, systemd place ses processus dans une hiérarchie cgroup, généralement au sein d'une slice. Les limites de ressources peuvent être appliquées directement aux unités de service.

La hiérarchie par défaut de Systemd ressemble souvent à ceci :

-.slice (Root slice)
  |- system.slice
  |  |- <service_name>.service
  |  |- another-service.service
  |  ... 
  |- user.slice
  |  |- user-1000.slice
  |  |  |- session-c1.scope
  |  |  |  |- <application>.service (if started by user)
  |  |  |  ...
  |  |  ...
  |  ... 
  |- machine.slice (for VMs/containers)
  ... 

Application des limites de ressources avec les fichiers d'unité Systemd

Systemd vous permet de spécifier les limites de ressources cgroup directement dans les fichiers d'unité .service, .slice ou .scope. Ces directives sont placées respectivement sous les sections [Service], [Slice] ou [Scope].

Limites de CPU

Les directives principales pour le contrôle des ressources CPU sont :

  • CPUQuota= : Limite le temps CPU total que l'unité peut utiliser. Ceci est spécifié en pourcentage (par exemple, 50 % pour la moitié d'un cœur de CPU) ou en fraction d'un cœur de CPU (par exemple, 0.5). Il est également possible de spécifier une valeur en microsecondes par période. La période par défaut est de 100 ms.
  • CPUShares= : Définit une pondération relative pour le temps CPU. Une unité avec CPUShares=2048 obtiendra deux fois plus de temps CPU qu'une unité avec CPUShares=1024 en cas de contention.
  • CPUWeight= : Un alias de CPUShares= mais avec une plage différente (1-10000, par défaut 100).
  • CPUQuotaPeriodSec= : Définit la période pour CPUQuota. La valeur par défaut est 100ms.

Exemple : Limiter un serveur web à 75 % d'un cœur de CPU :

Créez ou modifiez un fichier de service, par exemple, /etc/systemd/system/mywebapp.service :

[Unit]
Description=My Web Application

[Service]
ExecStart=/usr/bin/mywebapp
User=webappuser
Group=webappgroup

# Limit to 75% of one CPU core
CPUQuota=75%

[Install]
WantedBy=multi-user.target

Après avoir créé ou modifié le fichier de service, rechargez le démon systemd et redémarrez le service :

sudo systemctl daemon-reload
sudo systemctl restart mywebapp.service

Limites de mémoire

Les limites de mémoire sont contrôlées par des directives telles que :

  • MemoryLimit= : Définit une limite stricte sur la quantité de RAM que les processus de l'unité peuvent consommer. Cela peut être spécifié en octets ou avec des suffixes comme K, M, G, T (par exemple, 512M).
  • MemoryMax= : Similaire à MemoryLimit, mais souvent considéré comme plus moderne et flexible dans son interaction avec la comptabilité de la mémoire. Il est généralement recommandé par rapport à MemoryLimit.
  • MemoryHigh= : Définit une limite souple. Lorsque cette limite est approchée, la récupération de mémoire (swapping) est déclenchée plus agressivement, mais la limite stricte n'est pas encore appliquée.
  • MemorySwapMax= : Limite la quantité d'espace d'échange (swap) que l'unité peut utiliser.

Exemple : Limiter une base de données à 2 Go de RAM :

Créez ou modifiez un fichier de service, par exemple, /etc/systemd/system/mydb.service :

[Unit]
Description=My Database Service

[Service]
ExecStart=/usr/bin/mydb
User=dbuser
Group=dbgroup

# Limit memory to 2 Gigabytes
MemoryMax=2G

[Install]
WantedBy=multi-user.target

Rechargez et redémarrez :

sudo systemctl daemon-reload
sudo systemctl restart mydb.service

Limites d'E/S

La régulation des E/S peut être contrôlée à l'aide de directives telles que :

  • IOWeight= : Définit un poids relatif pour les opérations d'E/S. Des valeurs plus élevées donnent une priorité d'E/S plus importante. La plage est de 1 à 1000 (par défaut 500).
  • IOReadBandwidthMax= : Limite la bande passante d'E/S en lecture. Spécifié comme [<périphérique>] <octets_par_seconde>. Par exemple, IOReadBandwidthMax=/dev/sda 100M limite les opérations de lecture sur /dev/sda à 100 Mo/s.
  • IOWriteBandwidthMax= : Limite la bande passante d'E/S en écriture. Format similaire à IOReadBandwidthMax.

Exemple : Limiter un service de traitement en arrière-plan à 50 Mo/s sur un disque spécifique :

Créez ou modifiez un fichier de service, par exemple, /etc/systemd/system/batchproc.service :

[Unit]
Description=Batch Processing Service

[Service]
ExecStart=/usr/bin/batchproc
User=batchuser
Group=batchgroup

# Limit write operations to 50MB/s on /dev/sdb
IOWriteBandwidthMax=/dev/sdb 50M

# Give it a moderate read priority
IOWeight=200

[Install]
WantedBy=multi-user.target

Rechargez et redémarrez :

sudo systemctl daemon-reload
sudo systemctl restart batchproc.service

Gestion et surveillance des Cgroups

Systemd fournit des outils pour inspecter et gérer les cgroups associés à vos unités.

Inspection du statut des Cgroups

La commande systemctl status fournit des informations sur l'appartenance d'une unité à un cgroup et son utilisation des ressources.

systemctl status mywebapp.service

Recherchez les lignes indiquant le chemin du cgroup. Par exemple :

● mywebapp.service - My Web Application
     Loaded: loaded (/etc/systemd/system/mywebapp.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2023-10-27 10:00:00 UTC; 1 day ago
       Docs: man:mywebapp(8)
   Main PID: 12345 (mywebapp)
      Tasks: 5 (limit: 4915)
     Memory: 15.5M
        CPU: 2h 30m 15s
      CGroup: /system.slice/mywebapp.service
              └─12345 /usr/bin/mywebapp

Vous pouvez également inspecter directement le système de fichiers cgroup :

systemd-cgls # Affiche la hiérarchie des cgroups gérée par systemd
systemd-cgtop # Similaire à top, mais pour les cgroups

Pour voir les limites spécifiques appliquées au cgroup d'un service :

# Pour les limites de mémoire
catsysfs /sys/fs/cgroup/memory/system.slice/mywebapp.service/memory.max

# Pour les limites de CPU
catsysfs /sys/fs/cgroup/cpu/system.slice/mywebapp.service/cpu.max

(Remarque : Les chemins exacts et les noms de fichiers peuvent varier légèrement en fonction de la version du cgroup et de la configuration du système.)

Modification des limites Cgroup à la volée

Bien qu'il soit recommandé de définir les limites dans les fichiers d'unité, vous pouvez les ajuster temporairement à l'aide de systemctl set-property :

sudo systemctl set-property mywebapp.service CPUQuota=50%

Ces modifications ne sont pas persistantes après un redémarrage. Pour les rendre permanentes, mettez à jour le fichier d'unité et rechargez le démon systemd.

Slices pour la délégation de ressources

Les slices sont puissantes pour gérer des groupes de services ou d'applications. Vous pouvez définir des limites de ressources sur une slice, et tous les services ou scopes au sein de cette slice hériteront ou seront contraints par ces limites.

Exemple : Créer une slice dédiée pour les tâches de traitement par lots gourmandes en ressources :

Créez un fichier de slice, par exemple, /etc/systemd/system/batch.slice :

[Unit]
Description=Batch Processing Slice

[Slice]
# Limit total CPU for all jobs in this slice to 1 core
CPUQuota=100%
# Limit total memory to 4GB
MemoryMax=4G

Maintenant, vous pouvez configurer les services pour qu'ils s'exécutent dans cette slice en utilisant la directive Slice= dans leurs fichiers .service :

[Unit]
Description=Specific Batch Job

[Service]
ExecStart=/usr/bin/mybatchjob

# Place this service into the batch.slice
Slice=batch.slice

[Install]
WantedBy=multi-user.target

Rechargez systemd, activez/démarrez la slice si nécessaire (bien qu'elle soit souvent activée implicitement), et démarrez le service.

sudo systemctl daemon-reload
sudo systemctl start mybatchjob.service

Cette approche vous permet de regrouper les processus associés et de gérer leur consommation collective de ressources.

Bonnes pratiques et considérations

  • Commencez par des limites incrémentielles : Lorsque vous définissez des limites, commencez par des valeurs conservatrices et augmentez-les progressivement si nécessaire. Des limites agressives peuvent déstabiliser les applications.
  • Surveillez : Surveillez régulièrement l'utilisation des ressources de votre système et l'impact de vos paramètres cgroup. Des outils comme systemd-cgtop, htop, top et iotop sont inestimables.
  • Comprenez Cgroup v1 vs. v2 : Systemd prend en charge les cgroup v1 et v2. Bien que de nombreuses directives soient similaires, v2 offre une hiérarchie unifiée et quelques différences de comportement. Assurez-vous de savoir quelle version votre système utilise si vous rencontrez des problèmes complexes.
  • Priorisation vs. Limites Strictes : Utilisez CPUShares/CPUWeight pour la priorisation lorsque les ressources sont rares, et CPUQuota pour des limites strictes. De même, MemoryHigh est pour les limites souples et MemoryMax pour les limites strictes.
  • Service vs. Slice : Utilisez les unités de service pour les applications individuelles et les slices pour gérer des groupes d'applications connexes ou des pools de ressources.
  • Documentation : Documentez clairement les limites de ressources appliquées aux services critiques, en particulier dans les environnements de production.
  • OOM Killer : Sachez que si un processus dépasse sa limite MemoryMax, le tueur Out-Of-Memory (OOM) du noyau pourrait le terminer, même s'il se trouve dans un cgroup. Systemd peut gérer le comportement du tueur OOM pour des cgroups spécifiques à l'aide de directives comme OOMPolicy=.

Conclusion

L'intégration de Systemd avec les cgroups offre un mécanisme robuste et convivial pour contrôler et isoler les ressources système. En maîtrisant l'utilisation des unités de service, de scope et de slice, les administrateurs peuvent appliquer efficacement des limites de CPU, de mémoire et d'E/S pour garantir la stabilité du système, des performances prévisibles et prévenir la famine des ressources. La mise en œuvre de ces contrôles est un aspect fondamental de l'administration moderne des systèmes Linux, permettant un contrôle accru de vos environnements d'application et de l'infrastructure sous-jacente.