Espaces de noms et cgroups sous Linux : le véritable fondement des conteneurs

Dernière mise à jour: 24 de Février 2026
  • Sous Linux, les conteneurs s'appuient sur les espaces de noms pour isoler ce que les processus peuvent voir et sur les cgroups pour limiter la quantité de ressources qu'ils peuvent utiliser.
  • Il existe différents types d'espaces de noms (PID, NET, MNT, UTS, IPC, USER, cgroup, temps) et de contrôleurs cgroup (CPU, mémoire, E/S, pids) qui sont combinés en fonction du cas.
  • Docker, Kubernetes et systemd s'appuient sur ces primitives du noyau pour créer des environnements isolés, appliquer des politiques de ressources et gérer les services de manière uniforme.
  • Le suivi des métriques cgroup et la compréhension de la topologie des espaces de noms sont essentiels pour diagnostiquer les erreurs de mémoire insuffisante, les problèmes de performance et garantir une isolation solide en production.

espaces de noms cgroups des conteneurs Linux

Si vous travaillez avec Docker, Kubernetes ou toute autre plateforme de conteneurisation, vous serez tôt ou tard amené à explorer le fonctionnement interne du système. Derrière la « magie » du lancement de conteneurs en quelques secondes se cachent deux composants clés du noyau Linux : les espaces de noms et les cgroups, qui assurent l’isolation et la gestion précise des ressources . Leur compréhension fait toute la différence entre la simple utilisation d’outils et la conception de l’infrastructure.

Tout au long de cet article, nous expliquerons calmement, mais sans entrer dans trop de détails, comment ils fonctionnent. espaces de noms (ce qu'un processus peut voir) et cgroups (ce qu'un processus peut utiliser)Comment Docker et Kubernetes les exploitent ; comment les manipuler à un niveau bas à l’aide de commandes comme unshare, ip netns ou en écrivant directement dans /sys/fs/cgroupEt quelles astuces sont utiles pour optimiser les performances, la sécurité et le dépannage dans les environnements de production ?

Que fait concrètement un conteneur sous Linux ?

Lorsque vous exécutez quelque chose comme docker runAucune machine virtuelle magique n'est créée ; Vous obtenez ainsi un processus Linux (ou un groupe de processus) fortement isolé et disposant de ressources limitées.L’« astuce » repose sur quatre mécanismes fondamentaux :

  • Espaces de nomsIls contrôlent ce que le processus voit (PID, réseau, système de fichiers, nom d'hôte, etc.).
  • Groupes CIls contrôlent la quantité de ressources que le processus peut utiliser (CPU, RAM, E/S, PID…).
  • Chroot / système de fichiers racine isolé: ils attribuent au processus son propre système de fichiers.
  • Processus Linux normauxAu final, tout se résume aux PID hôtes gérés par le noyau.

En d'autres termes, un conteneur est simplement un processus s'exécutant avec un ensemble de nouveaux espaces de noms, imbriqués dans un ou plusieurs cgroups, et doté d'un système de fichiers personnalisé . Le reste est géré par l'outil (Docker, containerd, runc, etc.) grâce à l'automatisation et à des API conviviales.

Espaces de noms Linux : isoler ce que chaque processus peut voir

Les espaces de noms sont une couche d'abstraction du noyau qui crée des « mondes » distincts pour des groupes de processus . Un processus ne voit que les ressources situées dans son espace de noms ; le reste du système est toujours présent, mais invisible pour lui.

Linux dispose actuellement de plusieurs types d'espaces de noms, chacun étant axé sur une partie spécifique du système. Combinés, ils permettent à un conteneur d'être perçu comme un système d'exploitation indépendant même s'il partage un noyau avec l'hôte.

Principaux types d'espaces de noms

Chaque type d'espace de noms isole une dimension différente. Dans un conteneur « sérieux », il est courant d'en utiliser plusieurs simultanément. Voici les plus importants :

  • espace de noms PID: isole l'espace des identifiants de processus. Dans le conteneur, le processus principal est généralement le PID 1Même si l'hôte possède un numéro différent, les processus appartenant à des espaces de noms différents peuvent avoir le même PID sans interférer entre eux et ne peuvent s'envoyer de signaux que si l'hôte l'autorise explicitement.
  • Espace de noms réseau (NET): crée une pile réseau indépendante, avec ses propres interfaces, routes, règles de pare-feu, sockets, etc. Chaque conteneur possède sa propre interface de bouclage, ses propres adresses IP et son propre routage.De cette manière, vous pouvez réutiliser la même adresse IP dans différents espaces de noms sans conflit et appliquer des règles iptables isolées.
  • Espace de noms Mount (MNT): sépare la vue des points de fixation. Les processus ne voient que la hiérarchie de fichiers de leur espace de noms.Même si des points de montage, des volumes partagés, des superpositions, etc. sont présents en dessous, c'est ce qui permet à un conteneur de sembler avoir son propre répertoire racine (« / ») sans accéder à la racine réelle de l'hôte.
  • Espace de noms UTS: contrôle le nom d'hôte et le domaine NIS. Dans un espace de noms UTS, Vous pouvez modifier le nom d'hôte sans affecter le système hôte.Très utile pour distinguer les conteneurs ou simuler des nœuds dans des environnements de test.
  • espace de noms IPC: isole les files d'attente de messages, les sémaphores et la mémoire partagée du système V. Empêcher les différents processus de conteneur d'interférer avec l'IPC en raison d'un accident ou d'une mauvaise conception.
  • espace de noms utilisateurProbablement le plus délicat. Il permet Associer les UID et GID des espaces de noms internes à d'autres ID d'hôtesCela permet d'associer l'utilisateur « root » au sein du conteneur à un utilisateur non privilégié sur l'hôte, réduisant considérablement le risque d'élévation de privilèges et améliorant la sécurité. sécurité des conteneurs.
  • espace de noms Cgroup: offre une vue virtualisée de /proc/self/cgroup et la hiérarchie des cgroups. De l'intérieur du conteneur, seuls ses propres groupes sont visibles.Cela masque la structure réelle de l'hôte et renforce l'isolement.
  • Espace de noms Temps: permet d'offrir différentes perceptions du temps (horloges comme CLOCK_MONOTONIC ou CLOCK_BOOTTIME) pour différents groupes de processus. Utile pour tester des scénarios ou obtenir une isolation très fine.
  Comment synchroniser des dossiers entre un PC et un appareil Android en local et sans passer par les services cloud ?

Tous ces espaces de noms sont exposés dans /proc/<pid>/ns/et peuvent être créés ou combinés avec des outils tels que unshare y nsenterLorsque le dernier processus appartenant à un espace de noms s'arrête, cet espace de noms est automatiquement détruit.

Expérimentation avec les espaces de noms depuis la ligne de commande

La commande unshare C'est l'un des principes de base de l'expérimentation : crée un processus enfant avec un ou plusieurs nouveaux espaces de nomsPar exemple, pour tester un espace de noms PID isolé :

unshare --pid --fork --mount-proc bash
ps aux
echo $$

À l'intérieur, vous ne verrez que les processus de cet espace de noms, et votre shell apparaîtra avec l'identifiant de processus 1, même si l'hôte conservera tous ses processus habituels. Il s'agit en fait de la structure de base du fonctionnement d'un environnement d'exécution OCI au démarrage d'un conteneur.

Espaces de noms réseau en détail

L'aspect réseau est l'un des plus polyvalents. Lors de la création d'un espace de noms NET avec ip netns addVous obtenez une pile vide, à l'exception de la pile de bouclage. À partir de là, vous pouvez :

  • Connectez cet espace de noms à l'hôte avec une paire veth (deux interfaces virtuelles reliées par un câble logique).
  • Créer des ponts tipo br0 et connecter plusieurs espaces de noms à ce pont afin qu'ils puissent se voir mutuellement en utilisant des adresses IP privées.
  • NAT et redirection pour donner accès à Internet à ces « conteneurs faits maison » avec iptables et /proc/sys/net/ipv4/ip_forward.

C'est exact, à un niveau très bas, c'est ce que Docker fait avec le pont. docker0 et leurs réseaux par défaut : Il configure les espaces de noms réseau, les pairs veth, les ponts et les règles NAT. pour que les conteneurs puissent communiquer entre eux et sortir.

Espaces de noms de montage et d'utilisateur pour le système de fichiers racine et la sécurité

Avec `mount namespace`, vous pouvez expérimenter la création d'un système de fichiers conteneur sans utiliser Docker. Le schéma typique est le suivant :

  • Assembler ou préparer un système de fichiers racine minimal (par exemple, un minirootfs Alpine téléchargé par wget et extrait dans un répertoire).
  • Créez un espace de noms de montage et procédez comme suit : pivot_root o chroot dans ce répertoire.
  • Ride /proc, /sys et d'autres pseudo-systèmes au sein de la nouvelle racine.

Ainsi, votre shell ne verra que ce système de fichiers, mais Vous restez un processus hôte normal, avec votre véritable PID et contrôlable par l'administrateur.Si vous utilisez également un espace de noms utilisateur avec --map-root-userIl est possible d'avoir un « root » interne qui n'est pas un utilisateur disposant de privilèges.

Cgroups : quantité de ressources que chaque processus peut allouer

Alors que les espaces de noms déterminent ce qu'un processus peut voir, les cgroups limitent la quantité de ressources système qu'un groupe de processus peut consommer . Ils ont été introduits dans le noyau 2.6.24 et sont désormais essentiels sur toute plateforme de conteneurs moderne.

Sur le plan conceptuel, un cgroup est un répertoire à l'intérieur /sys/fs/cgroup avec des fichiers qui décrivent les limites, les priorités et les indicateursLorsque vous ajoutez un PID au fichier approprié (par exemple, cgroup.procs), ce processus est soumis à ces règles.

Contrôleurs de ressources dans les cgroups

Les Cgroups sont composés de contrôleurs (sous-systèmes) qui agissent sur des ressources spécifiques. Parmi les plus couramment utilisés, on trouve :

  • Processeur: contrôle le temps CPU alloué. Avec partages définit la priorité relative ; avec quotas limites strictes (par exemple, délai d'expiration du processeur de 50 ms par période de 100 ms) ; avec CPUsets Vous assignez des processus à des cœurs spécifiques.
  • Mémoire: limite la RAM et le swap. Autorise Limites strictes et souples, paramètres de gestion de la mémoire insuffisante, statistiques et pression sur la mémoireTrès utile pour empêcher un service d'accaparer la totalité du serveur.
  • E/S par bloc (blkio / io): limite la bande passante et les IOPS par périphérique. Vous pouvez attribuer un poids proportionnel ou définir des limites exactes en octets/s opérations/s.
  • RéseauDes mécanismes existent pour limiter la bande passante et les paquets, bien que la prise en charge soit moins mature et soit généralement combinée avec tc et QoS.
  • PID: marquer le nombre maximal de processus/threads qui peut créer un groupe, atténuant ainsi les risques de fork bombs ou d'erreurs de code déclenchant des threads.

Le principe est très simple : vous placez votre application dans un cgroup et spécifiez les valeurs maximales de CPU, de mémoire, d’E/S et de PID . Le noyau se charge ensuite d’appliquer les règles.

cgroups v1 vs cgroups v2

En production, vous trouverez deux variantes de cgroups, et il est important de bien comprendre dans quel domaine vous vous trouvez :

  • cgroup v1Chaque contrôleur possède sa propre hiérarchie indépendante. Vous avez des routes comme /sys/fs/cgroup/cpu/..., /sys/fs/cgroup/memory/..., etc. Il est flexible mais complexe à gérer à grande échelle.De nombreuses distributions et plateformes classiques l'utilisent encore ou le prennent en charge pour des raisons de compatibilité.
  • cgroup v2: regroupe tout sous un hiérarchie unifiée en /sys/fs/cgroupLes limites sont configurées via des fichiers tels que cpu.max, memory.max, io.max et analogues. Cela simplifie la gestion et améliore le réglage fin des ressourcesLes distributions modernes ont tendance à utiliser la version 2 par défaut, parfois en mode hybride.
  Comment intégrer la PS5 et la Xbox à Home Assistant

En /proc/cgroups Vous pouvez voir quels contrôleurs sont activés, le nombre de cgroups actifs et si vous êtes en v1 ou v2 (en v2, vous verrez une hiérarchie unifiée avec l'ID 0). La commande mount | grep cgroup Il vous indique également le type de système de fichiers (cgroup2fs implique v2, tmpfs (indique généralement v1).

Création manuelle de cgroups et limites typiques

Pour bien comprendre le fonctionnement interne de Docker, il est utile de créer manuellement des cgroups. Le schéma général est le suivant :

  • Créez un répertoire cgroup.
  • Configurer les fichiers de limite/priorité (Processeur, mémoire, E/S, PID…).
  • Ajoutez les PID au cgroup en saisissant cgroup.procs o tasks (dans v1).

Par exemple, dans cgroups v2, vous pourriez avoir quelque chose comme ceci pour le processeur et la mémoire :

mkdir /sys/fs/cgroup/test_app
echo "+cpu +memory +io +pids" > /sys/fs/cgroup/cgroup.subtree_control
echo "50000 100000" > /sys/fs/cgroup/test_app/cpu.max
echo "512M" > /sys/fs/cgroup/test_app/memory.max
echo $$ > /sys/fs/cgroup/test_app/cgroup.procs

De ce fait, le processus actuel se limite à 50 % d'un cœur et 512 Mo de RAMSi vous commencez quelque chose d'intensif (un dd Si vous déplacez le périphérique vers /dev/null, par exemple, vous constaterez que le système ne dysfonctionne pas. Dans cgroups v1, le schéma est similaire, mais avec des fichiers comme cpu.shares, cpu.cfs_quota_us, memory.limit_in_bytesetc., chacun dans sa propre hiérarchie.

Comment Docker, Kubernetes et le noyau s'empilent

Au-dessus des espaces de noms et des cgroups se trouvent plusieurs couches logicielles qui se relaient jusqu'à atteindre le noyau. Même si le nom de l'outil change, le résultat final est toujours le même : des appels au noyau pour créer des espaces de noms, configurer les cgroups et monter les systèmes de fichiers.

Aujourd'hui, une pile de conteneurs typique ressemble beaucoup à ceci :

  • Couche d'orchestrationKubernetes, Docker Swarm, Nomad… Ils gèrent le cycle de vie des pods/services, la planification, la mise à l'échelle et le support. architectures de microservices.
  • environnement d'exécution de conteneurs de haut niveau: Docker Engine, containerd, CRI-O. Ils reçoivent les ordres de l'orchestrateur et les transforment en actions concrètes. (télécharger des images, créer des conteneurs, gérer les instantanés, etc.).
  • Exécution OCI de bas niveauRunc, crun et les outils similaires implémentent la spécification OCI et sont directement responsables de sa mise en œuvre. ils appellent clone(), unshare(), mount() et compagnie matérialiser le conteneur.
  • Noyau LinuxIl fournit les espaces de noms, les cgroups, OverlayFS et toutes les autres primitives. C'est là que la véritable « magie » opère.

Quand vous lancez un docker runLe chemin est le suivant : client CLI → dockerd → containerd → runc → appels au noyau. Ce chemin permet la création d’espaces de noms, l’attribution de cgroups, le montage du système de fichiers racine avec OverlayFS et ses volumes, ainsi que la connexion des interfaces réseau et du pont réseau. Ce que vous voyez comme « un conteneur » est, pour le noyau, une poignée de processus dotés de certains indicateurs et de chemins d'accès spéciaux..

Exigences et vérifications préalables du système

Avant de vous amuser à manipuler les espaces de noms et les cgroups sur un serveur, il est conseillé de vérifier que le matériel et le noyau répondent à des exigences minimales raisonnables , surtout si vous prévoyez de mettre en place un environnement similaire à un environnement de production.

À titre de référence, il est généralement recommandé d'avoir au moins 2 processeurs logiques, 4 Go de RAM (idéalement 8 Go ou plus) , environ 20 Go d'espace disque libre et un noyau 3.10 ou supérieur (idéalement 4.x ou 5.x pour bénéficier de toutes les fonctionnalités modernes de cgroups v2).

Pour vérifier que le noyau prend en charge les espaces de noms et les cgroups, il suffit de consulter le fichier de configuration de la version utilisée :

grep -E "CONFIG_.*_NS" /boot/config-$(uname -r)
grep -E "CONFIG_CGROUP" /boot/config-$(uname -r)

Des options comme celles-ci devraient apparaître là. CONFIG_NAMESPACES, CONFIG_PID_NS, CONFIG_NET_NS, CONFIG_CGROUPS, CONFIG_MEMCG, CONFIG_CGROUP_SCHED marqué comme =ySans cela, vous n'aurez pas beaucoup de temps de jeu.

Un autre détail pratique est de savoir si le système permet créer des espaces de noms utilisateur sans être administrateurC'est très utile pour les tests et certains outils. Cela se contrôle avec sysctl. kernel.unprivileged_userns_cloneSi le niveau est à 0, vous devrez l'activer (ou utiliser votre transpiration partout).

Exploration des cgroups et des espaces de noms sur des machines « réelles »

Une manière assez simple d'assimiler ces concepts consiste à observer comment le système lui-même et vos conteneurs les utilisent . Voici quelques conseils utiles :

  • ls /proc/self/ns/ Il vous indique les espaces de noms auxquels appartient votre shell actuel (cgroup, ipc, mnt, net, pid, user, uts…).
  • systemd-cgtop Il affiche l'utilisation du processeur, de la mémoire et des E/S par cgroup, de manière très similaire à top mais regroupés par services et conteneurs.
  • En /sys/fs/cgroup Vous pouvez localiser les cgroups que Docker ou Podman créent pour chaque conteneur, généralement en utilisant l'ID du conteneur dans le chemin d'accès. À l'intérieur, cgroup.procs Liste des PID associés.
  • /proc/<pid>/cgroup Il vous indique à quels cgroups un processus spécifique est affecté, ce qui est idéal pour traquer une application problématique.
  Docker Swarm : orchestration de conteneurs pour les environnements réels

Vous constaterez que les conteneurs constituent simplement une autre branche de la hiérarchie des cgroups, avec leurs propres limites de CPU, de mémoire, de blkio et autres, tout comme vous pourriez les créer manuellement . L'avantage de Docker est qu'il le fait automatiquement grâce à une API conviviale.

Stratégies de performance, NUMA et d'affinité

Dans les scénarios de forte charge (bases de données volumineuses, traitement intensif, streaming, etc.), le simple « lancement de conteneurs » ne suffit pas. La manière dont vous allouez le processeur et la mémoire à chaque service a un impact significatif sur les performances.

Le pilote cpuset permet d'affecter des processus ou des services à des ensembles spécifiques de processeurs et de nœuds NUMA. C'est très simple :

mkdir /sys/fs/cgroup/cpuset/dedicated_cpus
echo "4-7" > /sys/fs/cgroup/cpuset/dedicated_cpus/cpuset.cpus
echo "0" > /sys/fs/cgroup/cpuset/dedicated_cpus/cpuset.mems
echo 1 > /sys/fs/cgroup/cpuset/dedicated_cpus/cpuset.cpu_exclusive

Il permet de réserver un groupe de cœurs pour un service spécifique et d'empêcher les interférences du reste du système. Cela réduit le bruit, les migrations de threads et les problèmes de latence qui surviennent souvent lorsque plusieurs processus se disputent les mêmes processeurs.

Au niveau de la mémoire, l'utilisation conjointe de numactl et de cgroups (ou l'utilisation directe des paramètres NUMA du contrôleur mémoire lorsqu'ils sont disponibles) permet de maintenir les données sur le nœud physique le plus proche des cœurs qui les utilisent. Ceci est particulièrement visible dans les applications sensibles à la latence.

Surveillance et observabilité des cgroups et des espaces de noms

Définir des limites de ressources est une bonne chose, mais Si vous ne mesurez pas ce qui se passe, vous pourriez vous tirer une balle dans le pied sans même vous en rendre compte.cgroup v2 offre en lui-même un certain nombre de métriques utiles dans ses journaux. *.stat, *.events y *.pressure.

Quelques exemples pratiques :

  • cpu.stat Il vous indique la quantité de temps processeur utilisée par le groupe, le nombre de fois où sa vitesse a été réduite, etc.
  • memory.current y memory.max Ils indiquent la consommation actuelle et la limite configurée.
  • memory.events Il enregistre les erreurs de mémoire insuffisante, les limites logicielles atteintes et autres alertes.
  • io.stat accumule les lectures/écritures par périphérique.

Pour un aperçu rapide, systemd-cgtop C'est très pratique, et si vous voulez quelque chose de plus industriel, des outils comme cAdvisor Ils exportent les métriques cgroup Docker/container vers Prometheus, ce qui vous permet de créer des tableaux de bord complets dans Grafana sans trop d'efforts, idéal pour un moniteur système avancé.

Lors du débogage de problèmes d'espace de noms, des scripts simples qui parcourent /proc/<pid>/ns/ et comparer les liens symboliques aident à savoir quels processus partagent exactement le même espace de nomsou pour localiser un espace de noms réseau « perdu » qui est devenu bloqué.

Utilisation de systemd comme gestionnaire de cgroups

Dans la plupart des distributions modernes, systemd s'appuie fortement sur les cgroups pour gérer les services, les segments et les étendues . Lorsque vous définissez une unité avec des limites de ressources, systemd crée en réalité un cgroup pour ce service et configure ses gestionnaires.

Un service déclaré avec des directives telles que :

CPUQuota=50%
CPUWeight=500
MemoryMax=512M
IOReadBandwidthMax=/dev/sda 10M

Cela se traduit par des limites de cgroup sur le processeur, la mémoire et les E/S pour le processus de cette unité. Ceci permet d'aligner la gestion de services « classique » avec le modèle de conteneur, en utilisant le même sous-système noyau sous-jacent. Pour plus de détails sur systemd et ses exigences, consultez la page relative aux modifications apportées à systemd.

Pour les équipes qui mélangent services traditionnels et conteneurs (très courant), s'appuyer sur systemd pour définir des limites sur les démons critiques est un moyen élégant d' empêcher que les ressources ne soient tuées par les pods dans l'environnement conteneurisé.

Dans les environnements comportant de multiples charges de travail, des bases de données aux agents de surveillance en passant par les applications personnalisées, la maîtrise des espaces de noms et des cgroups permet de définir des politiques d'isolation robustes, d'ajuster la qualité de service et de garantir à chaque composant une allocation de CPU et de mémoire parfaitement maîtrisée . Comprendre comment Docker, Kubernetes et systemd exploitent ces fonctionnalités du noyau vous permet de concevoir des infrastructures mutualisées plus sécurisées, de déboguer des problèmes complexes (des erreurs de mémoire insuffisante aux goulots d'étranglement d'E/S) et d'optimiser l'utilisation de votre matériel sans compromettre la stabilité.

systemd 259 prend en charge musl
Article connexe:
systemd 259 : prise en charge de musl, sécurité et modifications importantes