1. Introduction
Les cgroups (control groups) permettent de limiter, mesurer et isoler l’utilisation des ressources système (CPU, mémoire, I/O, etc.) pour un ou plusieurs processus. Dans le contexte des conteneurs LXC, ils permettent un contrôle précis de chaque conteneur.
Depuis Linux 4.x, deux versions coexistent :
-
cgroup v1 : hiérarchie par contrôleur
-
cgroup v2 : unifiée, hiérarchie unique avec une syntaxe plus cohérente
2. Prérequis
-
Système Linux (Debian ≥ 11 ou Ubuntu ≥ 20.04)
LXC installé :
sudo apt install lxc -
Kernel avec cgroups v1 ou v2 activés
Privilèges root pour configurer les cgroups
3. Détection de la version de cgroup utilisée
# Affiche le type de montage
mount | grep cgroup
# Ou :
ls /sys/fs/cgroup
-
Si vous voyez
cpu,memory, etc. → cgroup v1 -
Si vous voyez des fichiers comme
cgroup.controllers,cgroup.procs, etc. → cgroup v2
Pour forcer un mode (grub) :
# Pour forcer cgroup v1 (au boot)
GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=0"
# Pour forcer cgroup v2
GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1"
sudo update-grub
4. Configuration des cgroups dans LXC
LXC permet de définir les limites de ressources via :
-
le fichier de configuration du conteneur (
/var/lib/lxc/<nom>/config) -
les fichiers de cgroup dynamiquement (pour conteneurs démarrés)
5. Configuration avec cgroup v1
Exemple : Limiter CPU et mémoire dans le fichier de config
# /var/lib/lxc/mycontainer/config
# CPU : utiliser 50% d’un cœur
lxc.cgroup.cpu.shares = 512
# Mémoire : 512 Mo max, 256 Mo min pour swap
lxc.cgroup.memory.limit_in_bytes = 512M
lxc.cgroup.memory.memsw.limit_in_bytes = 768M
Appliquer après création (si conteneur arrêté)
lxc-start -n mycontainer
6. Configuration avec cgroup v2
a) Exemple de hiérarchie cgroup v2
mkdir -p /sys/fs/cgroup/mycontainer
echo "+cpu +memory" > /sys/fs/cgroup/cgroup.subtree_control
echo $$ > /sys/fs/cgroup/mycontainer/cgroup.procs
b) Limiter les ressources
# Limiter à 512 Mo
echo $((512*1024*1024)) > /sys/fs/cgroup/mycontainer/memory.max
# Limiter à 20% d’un CPU
echo 20000 > /sys/fs/cgroup/mycontainer/cpu.max # 20000us sur 100000us (20%)
Note : en cgroup v2, la gestion CPU s’effectue via
cpu.maxet noncpu.shares.
7. Gestion dynamique des cgroups pour conteneurs en cours d’exécution
Identifier le PID principal du conteneur
lxc-info -n mycontainer -pH
Exemple cgroup v1 : limiter mémoire à chaud
echo 256M > /sys/fs/cgroup/memory/lxc/mycontainer/memory.limit_in_bytes
Exemple cgroup v2 : changer la limite CPU
# Répertoire automatique créé par LXC si cgroup v2 utilisé
CONTAINER_PATH="/sys/fs/cgroup/lxc.payload.mycontainer"
echo 50000 100000 > $CONTAINER_PATH/cpu.max # 50%
8. Exemple complet de fichier config LXC (v1)
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.rootfs.path = dir:/var/lib/lxc/mycontainer/rootfs
lxc.uts.name = mycontainer
# Limites cgroup v1
lxc.cgroup.cpu.shares = 512
lxc.cgroup.memory.limit_in_bytes = 512M
lxc.cgroup.memory.memsw.limit_in_bytes = 768M
9. Supervision des ressources utilisées par un conteneur
Via lxc-info
lxc-info -n mycontainer
Avec top, htop ou ps
Lister les processus et leur PID :
lxc-attach -n mycontainer -- ps aux
10. Scripts utiles
a) Script pour appliquer des limites cgroup v2 à un conteneur LXC
#!/bin/bash
NAME=$1
CPU=$2 # ex: 20000
MEM=$3 # ex: 536870912 (512M)
CGROUP="/sys/fs/cgroup/lxc.payload.${NAME}"
echo "${CPU} 100000" > "${CGROUP}/cpu.max"
echo "${MEM}" > "${CGROUP}/memory.max"
Usage :
sudo ./set_limits.sh mycontainer 25000 536870912
10. Exemples de configuration
🎯 Objectif
-
2 vCPU pour un conteneur LXC (sur 4 cœurs disponibles), et aussi : 1 vCPU
-
Solution pour cgroup v1 et cgroup v2
10.1. cgroup v1 : Limitation via cpuset et cpu.shares
a) Méthode 1 : Utiliser cpuset.cpus (isolation stricte par CPU ID)
Vous pouvez affecter les CPU 0 et 1 à un conteneur (et uniquement ceux-là) :
📄 Exemple dans le fichier config du conteneur :
# /var/lib/lxc/<nom>/config
lxc.cgroup.cpuset.cpus = 0,1 # Pour 2 vCPU
# OU
lxc.cgroup.cpuset.cpus = 2 # Pour 1 vCPU
Cela signifie :
-
Le conteneur ne pourra s’exécuter que sur les CPU physiques/logiques spécifiés.
-
Pas de partage, pas de dépassement possible.
Vérifiez les CPU visibles avec :
lscpuounproc
🔍 À appliquer à chaud (conteneur en cours) :
echo 0,1 > /sys/fs/cgroup/cpuset/lxc/<nom_du_conteneur>/cpuset.cpus
b) Méthode 2 : Utiliser cpu.shares (pondération)
lxc.cgroup.cpu.shares = 512 # moitié de la puissance d’un CPU
lxc.cgroup.cpu.shares = 1024 # ~1 CPU logique
lxc.cgroup.cpu.shares = 2048 # ~2 CPU logiques
Mais :
cpu.sharesne limite pas strictement le CPU, c’est une pondération dans une file d’attente CFS (Completely Fair Scheduler). Il n’y a pas d’isolation stricte.
10.2. cgroup v2 : Isolation stricte avec cpu.max
Avec cgroup v2, on ne parle plus de shares, mais de quantum de temps CPU dans une période.
Formule de base
cpu.max = quota period
-
quotaen microsecondes -
period(optionnel) = durée de référence, souvent100000µs = 100 ms -
Exemple :
20000 100000→ le conteneur a 20% du CPU total
a) Pour 2 vCPU sur 4 (soit 50%)
echo "50000 100000" > /sys/fs/cgroup/lxc.payload.<nom_du_conteneur>/cpu.max
b) Pour 1 vCPU sur 4 (soit 25%)
echo "25000 100000" > /sys/fs/cgroup/lxc.payload.<nom_du_conteneur>/cpu.max
LXC crée généralement des cgroups nommés
lxc.payload.<nom>. À adapter selon votre version de LXC ou configuration systemd.
c) Alternative stricte avec cpuset en v2
Comme en v1, vous pouvez combiner cpu.max avec cpuset.cpus :
echo "0,1" > /sys/fs/cgroup/lxc.payload.<nom>/cpuset.cpus
Cela limite l’accès aux CPU physiques 0 et 1.
Exemple Complet pour cgroup v2 (à chaud)
CONTAINER=mycontainer
CGROUP=/sys/fs/cgroup/lxc.payload.$CONTAINER
# 2 vCPU = 50% des 4 cœurs
echo "50000 100000" > $CGROUP/cpu.max
🧠 Résumé : 1 ou 2 vCPU selon méthode
| Version | Méthode | 1 vCPU | 2 vCPU |
|---|---|---|---|
| cgroup v1 | cpuset.cpus |
lxc.cgroup.cpuset.cpus = 0 |
lxc.cgroup.cpuset.cpus = 0,1 |
| cgroup v1 | cpu.shares |
1024 |
2048 |
| cgroup v2 | cpu.max |
25000 100000 (25%) |
50000 100000 (50%) |
| cgroup v2 | cpuset.cpus |
echo 0 > cpuset.cpus |
echo 0,1 > cpuset.cpus |
11. Compatibilité & notes
-
LXC >= 4 supporte nativement cgroup v2
-
Certains paramètres ne sont pas encore totalement équivalents entre v1 et v2
-
Il est possible de combiner LXC non-privilégié + cgroup v2, mais cela demande une configuration fine (
delegate+subtree_control)
12. Conclusion
L’utilisation des cgroups avec LXC permet un contrôle précis des ressources attribuées aux conteneurs. Que vous utilisiez cgroup v1 ou v2, vous pouvez :
-
Limiter la consommation CPU/mémoire
-
Modifier dynamiquement ces valeurs
-
Automatiser via des scripts ou des hooks
La tendance actuelle étant au passage vers cgroup v2, il est recommandé de s’y adapter dès maintenant pour bénéficier d’une meilleure gestion unifiée des ressources.