virli/tutorial/3/cgroups.md

319 lines
11 KiB
Markdown
Raw Normal View History

2016-10-03 10:27:18 +00:00
\newpage
2021-10-05 15:23:09 +00:00
Les *cgroup*s
-------------
2016-10-03 10:27:18 +00:00
Les *cgroup*s (pour *Control Group*s) permettent de collecter des statistiques
2021-10-05 15:23:09 +00:00
sur des **groupes de processus** (voire même, des threads !) et de leur
attribuer des propriétés. Il est par exemple possible de leur imposer des
limites d'utilisation de ressources ou d'altérer leur comportement : quantité
de RAM, temps CPU, bande passante, ...
Apparue dès [Linux
2.6.24](https://kernelnewbies.org/Linux_2_6_24#Task_Control_Groups)
(en 2008 !), les *cgroup*s sont répartis en différents sous-systèmes
(*subsystem*), chacun étant responsable d'un type de ressources
spécifique :
- [`blkio` (`io` dans la v2)
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/blkio-controller.html)
limites et statistiques de bande passante sur les disques ;
- `cpu` : cycles CPU minimum garantis ;
- [`cpuacct` (inclus dans `cpu` dans la v2)
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpuacct.html)
statistiques du temps CPU utilisé ;
- [`cpuset`
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpusets.html)
associe des tâches à un/des CPU particuliers (par exemple pour dédier un cœur
du CPU à un programme, qui ne pourra alors utiliser que ce CPU et pas les
autres) ;
- [`devices`
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/devices.html)
règles de contrôle de création (`mknod`) et d'accès aux périphériques ;
- [`freezer`
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/freezer-subsystem.html)
pour suspendre et reprendre l'exécution d'un groupe de tâches ;
- [`hugetlb` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/hugetlb.html) statistiques et limitation de l'usage de la fonctionnalité `HugeTLB` (permettant d'obtenir des pages mémoires plus grande que 4 kB) ;
- [`memory` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html) statistiques et limitation d'usage de la mémoire vive et de la *swap* ;
- [`net_cls` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_cls.html) applique un `classid` à tous les paquets émis par les tâches du *cgroup*, pour filtrage par le pare-feu en sortie ;
- [`net_prio` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_prio.html) surcharge la valeur de l'option de priorité `SO_PRIORITY`, ordonant la file d'attente des paquets sortants ;
- [`pids` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/pids.html) statistiques et limitation du nombre de processus ;
- ...
2016-10-03 10:27:18 +00:00
2021-10-05 15:23:09 +00:00
Nous allons commencer par faire quelques tests avec le *cgroup* *freezer*, qui
permet d'interrompre l'exécution d'un groupe de processus, puis de la reprendre
lorsqu'on le décide.
2016-10-03 10:27:18 +00:00
2021-10-05 15:23:09 +00:00
### Montage du *freezer*
2016-10-03 10:27:18 +00:00
2021-10-05 15:23:09 +00:00
En fonction de la configuration de votre système, vous allez vous trouver dans
l'une de ces trois situations :
2016-10-05 20:49:08 +00:00
2021-10-05 15:23:09 +00:00
- Votre dossier `/sys/fs/cgroup` contient à la fois des fichiers `cgroup.*` et
éventuellement des dossiers : vous avez une distribution moderne qui utilise
la nouvelle version des `cgroup`s.
2016-10-03 10:27:18 +00:00
2021-10-05 15:23:09 +00:00
- Votre dossier `/sys/fs/cgroup` contient d'autres dossiers au nom des
sous-systèmes que l'on a listé ci-dessus : il s'agit des `cgroup`s v1.
2016-10-03 10:27:18 +00:00
2021-10-05 15:23:09 +00:00
- Votre dossier `/sys/fs/cgroup` est vide ou inexistant, vous pouvez choisir
d'utiliser la version de votre choix :
Pour utiliser la v1 :
<div lang="en-US">
```bash
mkdir /sys/fs/cgroup/freezer/
mount -t cgroup -o freezer none /sys/fs/cgroup/freezer/
```
</div>
Pour utiliser la v2 :
<div lang="en-US">
```bash
mkdir /sys/fs/cgroup/
mount -t cgroup2 none /sys/fs/cgroup/
```
</div>
2016-10-03 10:27:18 +00:00
2021-10-05 15:23:09 +00:00
::::: {.question}
Avant d'aller plus loin, notez que les exemples seront donnés pour les deux
versions des `cgroup`s à chaque fois.
La principale différence entre les deux est la fusion des différents
sous-systèmes au sein d'une même arborescence. Dans la première version, chaque
sous-système disposait de sa propre arborescence et il fallait créer les
groupes et associer les tâches pour chaque sous-système. Avec la seconde
version, une seule création est nécessaire, quelque soit le nombre de
sous-systèmes que l'on souhaite utiliser.
:::::
2016-10-05 20:49:08 +00:00
2016-10-03 10:27:18 +00:00
### Création d'un nouveau groupe
2021-10-05 15:23:09 +00:00
Les *cgroup*s sont organisé autour d'une arborescence de groupe, où chaque
groupe est représenté par un dossier. Il peut bien évidemment y avoir des
sous-groupes, en créant des dossiers dans les dossiers existants, etc.\
La première étape dans l'utilisation d'un *cgroup* est donc de créer un groupe.
2016-10-03 10:27:18 +00:00
2017-10-22 22:14:32 +00:00
Pour ce faire, il suffit de créer un nouveau dossier dans un groupe existant,
2021-10-05 15:23:09 +00:00
par exemple la racine.
On commence par se rendre à la racine :
2016-10-03 10:27:18 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
2021-10-05 15:23:09 +00:00
cd /sys/fs/cgroup/freezer/ # v1
cd /sys/fs/cgroup/ # v2
```
</div>
Puis on crée notre groupe :
<div lang="en-US">
```bash
mkdir virli
ls virli/
2016-10-03 10:27:18 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2016-10-03 10:27:18 +00:00
2017-09-27 08:02:52 +00:00
Nous avons maintenant un nouveau groupe de processus `virli` dans le *cgroup*
2017-10-22 22:14:32 +00:00
*Freezer*. Comme il s'agit d'une hiérarchie, le groupe `virli` hérite des
2016-10-03 10:27:18 +00:00
propriétés de son (ses) père(s).
2016-10-05 20:49:08 +00:00
2021-10-05 15:23:09 +00:00
### Sélection de contrôleur (v2 seulement)
Du fait de l'unification de tous les sous-systèmes, si vous utilisez la seconde
version, vous allez devoir activer le ou les contrôleurs dont vous avez besoin
(tandis que dans la première version, on se rendait dans l'arborescence du
sous-système que l'on voulait).
Pour activer le contrôleur *memory* dans notre groupe `virli`, nous utilisons
la commande suivante :
<div lang="en-US">
```bash
echo "+memory" > virli/cgroup.subtree_control
```
</div>
::::: {.warning}
Si vous obtenez l'erreur `No such file or directory`, c'est sans doute que vous
avez les `cgroup`s v1 activé quelque part. Vous devriez plutôt utiliser la
première version, le fait qu'elle soit active empêche l'utilisation de la v2 en
parallèle.
:::::
On peut contrôler les contrôleurs actifs en consultant le fichier
`virli/cgroup.controllers`.
Le contrôleur *freezer* est activé par défaut, il n'y a pas besoin de
l'activer.
2016-10-03 10:27:18 +00:00
### Rattachement de processus
2021-10-05 15:23:09 +00:00
Pour le moment, ce nouveau groupe ne contient aucun processus, comme le montre
le fichier `cgroup.procs` de notre groupe. Ce fichier contient la liste des
processus rattachés à notre *cgroup*.
2016-10-03 10:27:18 +00:00
2017-10-22 22:14:32 +00:00
Ouvrons un nouveau terminal (c'est lui que l'on va geler), et récupérons son
2016-10-03 10:27:18 +00:00
PID : `echo $$`.
2021-10-05 15:23:09 +00:00
Pour ajouter une tâche à ce groupe, cela se passe de cette manière :
2016-10-03 10:27:18 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
2021-10-05 15:23:09 +00:00
echo $PID > /sys/fs/cgroup/{,freezer/}virli/cgroup.procs
2016-10-03 10:27:18 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2016-10-03 10:27:18 +00:00
Il faut ici remplacer `$PID` par le PID du shell que l'on a relevé juste avant.
2017-09-27 08:02:52 +00:00
En validant cette commande, nous avons déplacé le processus dans ce groupe, il
2016-10-05 20:49:08 +00:00
n'est alors plus dans aucun autre groupe (pour ce *cgroup*, il ne bouge pas
2016-10-03 10:27:18 +00:00
dans les autres *cgroup*s).
2021-10-05 15:23:09 +00:00
Malgré l'utilisation de la redirection `>` (et non `>>`), il s'agit bel et
2017-10-22 22:14:32 +00:00
bien d'un ajout au fichier et non d'un écrasement. Il faut garder en tête que
le système de fichier est entièrement simulé et que certains comportements sont
adaptés.
2016-10-05 20:49:08 +00:00
2016-10-03 10:27:18 +00:00
### Consultation de l'état
2017-10-23 20:25:51 +00:00
En affichant le contenu du dossier `virli`, nous pouvions constater que
2021-10-05 15:23:09 +00:00
celui-ci contenait déjà un certain nombre de fichiers. Certains d'entre-eux
sont en lecture seule et permettent de lire des statistiques instantanées sur
le groupe ; tandis que d'autres sont des propriétés que nous pouvons modifier.
2016-10-03 10:27:18 +00:00
Nous pouvons consulter l'état de gel du groupe en affichant le contenu du
fichier\
2021-10-05 15:23:09 +00:00
`/sys/fs/cgroup/freezer/virli/freezer.state` ou `/sys/fs/cgroup/virli/cgroup.freeze`.
2016-10-03 10:27:18 +00:00
2021-10-05 15:23:09 +00:00
Pour plus d'informations sur les différents fichiers présents dans ce *cgroup*,
2017-10-22 22:14:32 +00:00
consultez
2019-10-22 16:03:09 +00:00
[la documentation associée](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/freezer-subsystem.html).
2016-10-05 20:49:08 +00:00
2016-10-03 10:27:18 +00:00
### Changement d'état
Faisons exécuter à notre interpréteur une commande pour voir effectivement
l'exécution s'arrêter. Si vous manquez d'inspiration, utilisez :
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
for i in $(seq 9999); do echo -n $i; sleep .1; echo -n " - "; sleep .1; done
2016-10-03 10:27:18 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2016-10-03 10:27:18 +00:00
Maintenant, nous avons donné l'ordre au noyau de ne plus allouer de temps de
calcul à notre shell et ses fils :
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
2021-10-05 15:23:09 +00:00
echo FROZEN > /sys/fs/cgroup/freezer/virli/freezer.state # v1
echo 1 > /sys/fs/cgroup/virli/cgroup.freeze # v2
2016-10-03 10:27:18 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2016-10-03 10:27:18 +00:00
À cet instant, vous devriez voir votre compteur s'arrêter. Pour reprendre
l'exécution :
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
2021-10-05 15:23:09 +00:00
echo THAWED > /sys/fs/cgroup/freezer/virli/freezer.state # v1
echo 0 > /sys/fs/cgroup/virli/cgroup.freeze # v2
2016-10-03 10:27:18 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2016-10-03 10:27:18 +00:00
2021-10-05 15:23:09 +00:00
### Exercice : script de monitoring {- #script-monitoring}
2016-10-05 20:49:08 +00:00
À nous maintenant de concevoir un script qui va enregistrer vers une base de
2021-10-05 15:23:09 +00:00
données des statistiques issues des *cgroup*s, tel `telegraf`.
2016-10-03 10:27:18 +00:00
2017-10-22 22:14:32 +00:00
Dans un premier temps, commençons par afficher dans la console, la quantité de
2016-10-03 10:27:18 +00:00
mémoire utilisée par le groupe monitoré.
2021-10-05 15:23:09 +00:00
::::: {.code}
2019-11-03 17:54:39 +00:00
Vous pouvez utiliser un programme comme
[`memhog`](https://virli.nemunai.re/memhog.c) pour remplir rapidement votre
2016-10-03 10:27:18 +00:00
mémoire.
2021-10-05 15:23:09 +00:00
:::::
2016-10-03 10:27:18 +00:00
<div lang="en-US">
2018-10-31 08:41:27 +00:00
```
42sh# mkdir /sys/fs/cgroup...
2021-10-05 15:23:09 +00:00
42sh$ echo $$ | sudo tee /sys/fs/cgroup.../cgroup.procs
42sh# ./monitor group_name memhog 500
~~~ 13595 ~~~ Current memory usage: 75194368/550502400 (13%)
~~~ 13595 ~~~ Current memory usage: 150290432/550502400 (27%)
~~~ 13595 ~~~ Current memory usage: 223690752/550502400 (40%)
~~~ 13595 ~~~ Current memory usage: 296828928/550502400 (53%)
~~~ 13595 ~~~ Current memory usage: 368001024/550502400 (66%)
~~~ 13595 ~~~ Current memory usage: 438517760/550502400 (79%)
~~~ 13595 ~~~ Current memory usage: 480329728/550502400 (87%)
~~~ 13595 ~~~ Current memory usage: 155648/550502400 (0%)
2018-10-31 08:41:27 +00:00
```
</div>
2018-10-31 08:41:27 +00:00
2021-10-05 15:23:09 +00:00
::::: {.warning}
2017-10-23 20:25:51 +00:00
Si vous n'avez pas le *cgroup* *memory*, il est possible qu'il ne soit pas
activé par défaut par votre système. Si vous êtes dans ce cas, essayez
d'ajouter `cgroup_enable=memory` à la ligne de commande de votre noyau.
2021-10-05 15:23:09 +00:00
:::::
2016-10-03 10:27:18 +00:00
2021-10-05 15:23:09 +00:00
### Fixer des limites {#Fixer-des-limites}
2016-10-05 20:49:08 +00:00
2021-10-05 15:23:09 +00:00
Au-delà de la simple consultation, les *cgroup*s peuvent servir à limiter la
quantité de ressources mises à disposition à un groupe de processus.
2017-10-04 23:42:56 +00:00
2017-10-22 22:14:32 +00:00
Pour définir une limite, nous allons écrire la valeur dans le fichier
correspondant à une valeur limite, comme par exemple
2021-10-05 15:23:09 +00:00
`memory.max_usage_in_bytes`/`memory.max`, qui limite le nombre d'octets que
notre groupe de processus va pouvoir allouer au maximum :
2017-10-04 23:42:56 +00:00
<div lang="en-US">
```
2021-10-05 15:23:09 +00:00
# cgroup v1
42sh$ cat /sys/fs/cgroup/memory/virli/memory.max_usage_in_bytes
0
# 0 = Aucune limite
42sh$ echo 4M > /sys/fs/cgroup/memory/virli/memory.max_usage_in_bytes
# Maintenant, la limite est à 4MB, vérifions...
42sh$ cat /sys/fs/cgroup/memory/virli/memory.max_usage_in_bytes
4194304
2017-10-22 22:14:32 +00:00
```
</div>
2017-10-04 23:42:56 +00:00
2021-10-05 15:23:09 +00:00
<div lang="en-US">
```
# cgroup v2
42sh$ cat /sys/fs/cgroup/virli/memory.max
max
# max = Aucune limite
42sh$ echo 4M > /sys/fs/cgroup/virli/memory.max
# Maintenant, la limite est à 4MB, vérifions...
42sh$ cat /sys/fs/cgroup/virli/memory.max
4194304
```
</div>
Chaque *cgroup*s définit de nombreux indicateurs et possède de nombreux
2017-10-22 22:14:32 +00:00
limiteurs, n'hésitez pas à consulter la documentation associée à chaque
*cgroup*.
2017-10-04 23:42:56 +00:00
2021-10-05 15:23:09 +00:00
### Pour aller plus loin {-}
2016-10-05 20:49:08 +00:00
2017-09-27 08:05:55 +00:00
Pour tout connaître en détails, [la série d'articles de Neil Brown sur les
2021-10-05 15:23:09 +00:00
Control groups](https://lwn.net/Articles/604609/) est excellente ! Plus [cet
article sur la version 2](https://lwn.net/Articles/679786/).