Tuto 3 done

This commit is contained in:
nemunaire 2021-10-05 17:23:09 +02:00
commit 8c402e6d65
15 changed files with 604 additions and 310 deletions

View file

@ -1,50 +1,123 @@
\newpage
Utiliser les *cgroup*s
======================
Les *cgroup*s
-------------
Les *cgroup*s (pour *Control Group*s) permettent de collecter des statistiques
sur des groupes de processus (appelés tâches) et de leur attribuer des
propriétés. Par exemple, il est possible leur imposer des limites d'utilisation
de ressources ou d'altérer leur comportement.
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 :
## Premiers tests
- [`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 ;
- ...
Nous allons commencer par faire quelques tests avec le *cgroup* *freezer*, qui
permet d'interrompre l'exécution d'un groupe de processus et de la reprendre.
permet d'interrompre l'exécution d'un groupe de processus, puis de la reprendre
lorsqu'on le décide.
### Montage du *cgroup*
### Montage du *freezer*
En fonction de la configuration de votre système, il est possible que les
*cgroup*s ne soient pas montés au démarrage dans `/sys/fs/cgroup/`. Si vous n'avez
pas de dossier `freezer` ou si celui-ci est vide, montez-le en suivant la
procédure suivante :
En fonction de la configuration de votre système, vous allez vous trouver dans
l'une de ces trois situations :
<div lang="en-US">
```bash
mkdir /sys/fs/cgroup/freezer/
mount -t cgroup -o freezer none /sys/fs/cgroup/freezer/
```
</div>
- 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.
Cette dernière commande monte l'arborescence de groupes relative à ce *cgroup*
*freezer*. Tous les dossiers contenus dans cette racine sont donc des
sous-groupes.
- 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.
- 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>
::::: {.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.
:::::
### Création d'un nouveau groupe
La première étape dans l'utilisation d'un *cgroup* est de créer un groupe.
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.
Pour ce faire, il suffit de créer un nouveau dossier dans un groupe existant,
par exemple la racine :
par exemple la racine.
On commence par se rendre à la racine :
<div lang="en-US">
```bash
mkdir /sys/fs/cgroup/freezer/virli/
ls /sys/fs/cgroup/freezer/virli/
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/
```
</div>
@ -53,19 +126,50 @@ Nous avons maintenant un nouveau groupe de processus `virli` dans le *cgroup*
propriétés de son (ses) père(s).
### 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.
### Rattachement de processus
Pour le moment, ce nouveau groupe ne contient aucune tâche.
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*.
Ouvrons un nouveau terminal (c'est lui que l'on va geler), et récupérons son
PID : `echo $$`.
La liste des processus rattachés à un *cgroup* se trouve dans le fichier `task`
du groupe. Pour ajouter une tâche à ce groupe, cela se passe de cette manière :
Pour ajouter une tâche à ce groupe, cela se passe de cette manière :
<div lang="en-US">
```bash
echo $PID > /sys/fs/cgroup/freezer/virli/tasks
echo $PID > /sys/fs/cgroup/{,freezer/}virli/cgroup.procs
```
</div>
@ -75,7 +179,7 @@ En validant cette commande, nous avons déplacé le processus dans ce groupe, il
n'est alors plus dans aucun autre groupe (pour ce *cgroup*, il ne bouge pas
dans les autres *cgroup*s).
Malgré l'utilisation de la redirection `>` (et non `>>`), il s'agit belle et
Malgré l'utilisation de la redirection `>` (et non `>>`), il s'agit bel et
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.
@ -84,15 +188,15 @@ adaptés.
### Consultation de l'état
En affichant le contenu du dossier `virli`, nous pouvions constater que
celui-ci contenait déjà un certain nombre de fichiers. Certain 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.
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.
Nous pouvons consulter l'état de gel du groupe en affichant le contenu du
fichier\
`/sys/fs/cgroup/freezer/virli/freezer.state`.
`/sys/fs/cgroup/freezer/virli/freezer.state` ou `/sys/fs/cgroup/virli/cgroup.freeze`.
Pour plus d'information sur les différents fichiers présents dans ce *cgroup*,
Pour plus d'informations sur les différents fichiers présents dans ce *cgroup*,
consultez
[la documentation associée](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/freezer-subsystem.html).
@ -113,7 +217,8 @@ calcul à notre shell et ses fils :
<div lang="en-US">
```bash
echo FROZEN > /sys/fs/cgroup/freezer/virli/freezer.state
echo FROZEN > /sys/fs/cgroup/freezer/virli/freezer.state # v1
echo 1 > /sys/fs/cgroup/virli/cgroup.freeze # v2
```
</div>
@ -122,57 +227,30 @@ l'exécution :
<div lang="en-US">
```bash
echo THAWED > /sys/fs/cgroup/freezer/virli/freezer.state
echo THAWED > /sys/fs/cgroup/freezer/virli/freezer.state # v1
echo 0 > /sys/fs/cgroup/virli/cgroup.freeze # v2
```
</div>
## Exercice : script de monitoring
### Exercice : script de monitoring {- #script-monitoring}
À nous maintenant de concevoir un script qui va enregistrer vers une base de
données des statistiques issues des *cgroup*s.
### Rappel d'InfluxDB
Commençons par lancer le conteneur Docker d'InfluxDB (pour éviter de
l'installer sur notre machine) :
<div lang="en-US">
```bash
docker container run --name mytsdb -d -p 8086:8086 influxdb
```
</div>
Il nous faut ensuite créer une base de données pour y stocker nos
métriques. Voici comment on s'était débrouillé dans un précédent TP pour
interagir avec InfluxDB :
<div lang="en-US">
```bash
docker container exec -i mytsdb influx <<EOF
CREATE DATABASE metrics;
SHOW DATABASES;
EOF
```
</div>
Vérifiez que la base de données `metrics` a bien été créée.
### Monitoring instantané vers la console
données des statistiques issues des *cgroup*s, tel `telegraf`.
Dans un premier temps, commençons par afficher dans la console, la quantité de
mémoire utilisée par le groupe monitoré.
::::: {.code}
Vous pouvez utiliser un programme comme
[`memhog`](https://virli.nemunai.re/memhog.c) pour remplir rapidement votre
mémoire.
:::::
<div lang="en-US">
```
42sh# mkdir /sys/fs/cgroup...
42sh$ echo $$ | sudo tee /sys/fs/cgroup.../tasks
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%)
@ -185,79 +263,26 @@ mémoire.
```
</div>
::::: {.warning}
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.
:::::
### Monitoring vers InfluxDB
### Fixer des limites {#Fixer-des-limites}
Maintenant, envoyons nos données vers la base
<https://docs.influxdata.com/influxdb/v1.6/guides/writing_data/> :
<div lang="en-US">
```bash
curl -i -XPOST 'http://localhost:8086/write?db=metrics' --data-binary \
"$my_cgroup_name memory.usage_in_bytes=$(cat .../my_cgroup_name/memory.usage_in_bytes)"
```
</div>
Pour vérifier que les données ont bien été ajoutées, nous pouvons effectuer la
requête suivante dans notre client `influx` :
<div lang="en-US">
```sql
SELECT * from "$my_cgroup_name";
```
</div>
### Monitorer davantage de données
Liste non exhaustive de données à monitorer :
* Nombre d'IOs effectué ;
* nombre d'octets lu/écrit sur les disques ;
* temps de calcul utilisé ;
* trafic réseau généré ;
* ...
Tous les cgroups existants dans le dernier noyau publié ont leur documentation
accessible ici :
<https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/index.html>
### Permettre à l'utilisateur de monitorer des processus
Maintenant, séparons notre script en deux parties afin qu'un utilisateur normal
(non-root) puisse utiliser la partie monitoring de notre script.
Un premier script doit s'occuper de créer le(s) *cgroup*s et lui attribuer les
bons droits, tandis que le deuxième va effectuer le monitoring, sans privilèges
particuliers.
#### Exemple
<div lang="en-US">
```
42sh$ sudo ./monitor_init my_cgroup_name
42sh$ ./monitor my_cgroup_name memhog 500
```
</div>
## Fixer des limites
Au delà de la simple consultation, les *cgroup*s peuvent servir à limiter la
quantité de ressources mise à disposition à un groupe de processus.
Au-delà de la simple consultation, les *cgroup*s peuvent servir à limiter la
quantité de ressources mises à disposition à un groupe de processus.
Pour définir une limite, nous allons écrire la valeur dans le fichier
correspondant à une valeur limite, comme par exemple
`memory.max_usage_in_bytes`, qui limite le nombre d'octets que notre groupe de
processus va pouvoir allouer au maximum :
`memory.max_usage_in_bytes`/`memory.max`, qui limite le nombre d'octets que
notre groupe de processus va pouvoir allouer au maximum :
<div lang="en-US">
```
# cgroup v1
42sh$ cat /sys/fs/cgroup/memory/virli/memory.max_usage_in_bytes
0
# 0 = Aucune limite
@ -268,21 +293,26 @@ processus va pouvoir allouer au maximum :
```
</div>
Chaque *cgroup*s défini de nombreux indicateurs et possède de nombreux
<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
limiteurs, n'hésitez pas à consulter la documentation associée à chaque
*cgroup*.
## Pour aller plus loin {-}
### Pour aller plus loin {-}
Pour tout connaître en détails, [la série d'articles de Neil Brown sur les
Control groups](https://lwn.net/Articles/604609/) est excellente !
Depuis les noyaux 4.5, il est possible d'utiliser la nouvelle version du
pseudo système de fichiers des *CGroup*s. Le principal changement vient du
regroupement au sein d'une seule hiérarchie des différents *CGroup*s que l'on
avait dans la v1. Davantage d'informations sont disponibles :
* [Understanding the new control groups API](https://lwn.net/Articles/679786/)
;
* [Kernel Document about Control Group v2](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html).
Control groups](https://lwn.net/Articles/604609/) est excellente ! Plus [cet
article sur la version 2](https://lwn.net/Articles/679786/).