Work on tuto 3
This commit is contained in:
parent
07195409eb
commit
b459443d9e
@ -5,13 +5,156 @@ Les capabilities
|
|||||||
|
|
||||||
## Présentation
|
## Présentation
|
||||||
|
|
||||||
## La `libcap`
|
Historiquement, dans la tradition UNIX, on distingue deux catégories de
|
||||||
|
processus :
|
||||||
|
|
||||||
## Les attributs étendus
|
* les processus *privilégiés* : dont l'identifiant de son utilisateur est 0 ;
|
||||||
|
* les processus *non-privilégiés* : dont l'identifiant de son utilisateur n'est
|
||||||
|
pas 0.
|
||||||
|
|
||||||
|
Lors des différents tests de permission fait par le noyau, les processus
|
||||||
|
privilégiés outrepassaient ces tests, tandis que les autres devaient passer les
|
||||||
|
tests de l'effective UID, effective GID, et autres groupes supplémentaires...
|
||||||
|
|
||||||
|
Depuis Linux 2.2 (en 1998), les processus privilégiés peuvent activer ou
|
||||||
|
désactiver des *capabilities*, chacune donnant accès à un groupe d'actions
|
||||||
|
privilégiées au sein du noyau.
|
||||||
|
|
||||||
|
On trouve par exemple :
|
||||||
|
|
||||||
|
* `CAP_CHOWN` : permet de modifier le propriétaire d'un fichier de manière
|
||||||
|
arbitraire ;
|
||||||
|
* `CAP_KILL` : permet de tuer n'importe quel processus ;
|
||||||
|
* `CAP_SYS_BOOT` : permet d'arrêter ou de redémarrer la machine ;
|
||||||
|
* `CAP_SYS_MODULE` : permet de charger et décharger des modules ;
|
||||||
|
* et beaucoup d'autres, il y en a environ 39 en tout !
|
||||||
|
|
||||||
|
|
||||||
|
### `ping`
|
||||||
|
|
||||||
|
Pour émettre un ping, il est nécessaire d'envoyer des paquets ICMP. À la
|
||||||
|
différence des datagrammes UDP ou des segments TCP, il n'existe pas d'interface
|
||||||
|
exposée par le noyau aux utilisateurs pour envoyer des paquets ICMP. Pour le
|
||||||
|
faire, il est nécessaire de pouvoir écrire directement sur l'interface ; ça,
|
||||||
|
seul le super-utilisateur peut le faire.
|
||||||
|
|
||||||
|
Pour permettre à tous les utilisateurs de pouvoir envoyer des ping, le
|
||||||
|
programme est donc généralement Setuid root. Cela permet à n'importe quel
|
||||||
|
utilisateur de prendre les droits du super-utilisateur, le temps de l'exécution
|
||||||
|
du programme.
|
||||||
|
|
||||||
|
Les problèmes surviennent lorsque l'on découvre des vulnérabilités dans les
|
||||||
|
programmes Setuid root. En effet, s'il devient possible à un utilisateur
|
||||||
|
d'exécuter du code arbitraire, ce code sera exécuté avec les privilèges de
|
||||||
|
l'utilisateur root ! Dans le cas de ping, on se retrouverait alors à pouvoir
|
||||||
|
lire l'intégralité de la mémoire, alors que l'on avait juste besoin d'écrire
|
||||||
|
sur une interface réseau.
|
||||||
|
|
||||||
|
C'est donc à ce moment que les *capabilities* entrent en jeu : un processus (ou
|
||||||
|
même un thread) privilégié peut décider, à son lancement, de réduire ses
|
||||||
|
*capabilities*, pour ne garder que celles dont il a réellement besoin. Ainsi,
|
||||||
|
`ping` pourrait se contenter de `CAP_NET_RAW`.
|
||||||
|
|
||||||
|
|
||||||
|
## Les attributs de fichier étendus
|
||||||
|
|
||||||
|
Une grosse majorité des systèmes de fichiers (ext[234], XFS, btrfs, ...)
|
||||||
|
permettent d'enregistrer, pour chaque fichier, des attributs (dits attributs
|
||||||
|
*étendus*, par opposition aux attributs *réguliers* qui sont réservés à l'usage
|
||||||
|
du système de fichiers).
|
||||||
|
|
||||||
|
Sous Linux, les attributs sont regroupés dans des espaces de noms :
|
||||||
|
|
||||||
|
* *security* : espace utilisé par les modules de sécurité du noyau, tel que
|
||||||
|
SELinux, ... ;
|
||||||
|
* *system* : espace utilisé par le noyau pour stocker des objets système, tels
|
||||||
|
que les ACL POSIX ;
|
||||||
|
* *trusted*: espace dont la lecture et l'écriture est limité au
|
||||||
|
super-utilisateur ;
|
||||||
|
* *user* : modifiable sans restriction, à partir du moment où l'on est le
|
||||||
|
propriétaire du fichier.
|
||||||
|
|
||||||
|
Par exemple, on peut définir un attribut sur un fichier comme cela :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
42sh$ echo 'Hello World!' > toto
|
||||||
|
42sh$ setfattr -n user.foo -v bar toto
|
||||||
|
42sh$ getfattr -d toto
|
||||||
|
# file: toto
|
||||||
|
user.foo="bar"
|
||||||
|
```
|
||||||
|
|
||||||
|
Encore plus fort, vous pouvez utiliser les ACL POSIX :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
42sh$ sudo chown root:root toto && sudo chmod o-r toto
|
||||||
|
42sh$ cat toto
|
||||||
|
cat: toto: Permission denied
|
||||||
|
42sh$ sudo setfattr -m u:$USER:r toto
|
||||||
|
42sh$ cat toto
|
||||||
|
Hello World!
|
||||||
|
```
|
||||||
|
|
||||||
|
Bien que les droits UNIX traditionnels ne vous donne pas accès au fichier, les
|
||||||
|
ACL POSIX vous autorisent à lire le contenu du fichier.
|
||||||
|
|
||||||
|
Vous pouvez voir ces attributs avec la commande :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
42sh$ getfattr -d -m "^system" toto
|
||||||
|
# file: toto
|
||||||
|
system.posix_acl_access=0sgAAEAD/////AgAEOgDAEAA/////xAABAD////8=
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### `ping`
|
||||||
|
|
||||||
|
De la même manière que l'on peut définir de manière plus fine les droits
|
||||||
|
d'accès par utilisateur, un attribut de l'espace de nom *security* peut être
|
||||||
|
définit pour accroître les *capabilities* d'un processus lorsqu'il est lancé
|
||||||
|
par un utilisateur non-privilégié. On peut alors voir le Setuid root comme
|
||||||
|
l'utilisation de cet attribut auquel on accroîtrait l'ensemble des
|
||||||
|
*capabilities*.
|
||||||
|
|
||||||
|
Si votre distribution profite de ces attributs étendus, vous devriez obtenir :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
42sh$ getfattr -d -m "^security" $(which ping)
|
||||||
|
# file: bin/ping
|
||||||
|
security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA=
|
||||||
|
```
|
||||||
|
|
||||||
|
Ou, dans sa version plus lisible :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
42sh$ getcap $(which ping)
|
||||||
|
/bin/ping = cap_net_raw+ep
|
||||||
|
```
|
||||||
|
|
||||||
`getcap` et `setcap` sur `ping`
|
|
||||||
|
|
||||||
## Exercice : visualisateur de capabilities d'un processus
|
## Exercice : visualisateur de capabilities d'un processus
|
||||||
|
|
||||||
|
Écrivons maintenant un script permettant de voir les *capabilities* d'un
|
||||||
|
processus :
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Rendu
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Aller plus loin
|
||||||
|
|
||||||
|
Je vous recommande la lecture des *man* suivants :
|
||||||
|
|
||||||
|
* `capabilities(7)` : énumérant tous les capabilities, leur utilisation, etc. ;
|
||||||
|
* `xattrs(7)` : à propos des attributs étendus.
|
||||||
|
|
||||||
|
Et de ces quelques articles :
|
||||||
|
|
||||||
|
* [https://www.freedesktop.org/wiki/CommonExtendedAttributes/](Guidelines for
|
||||||
|
extended attributes)
|
||||||
|
* [https://lwn.net/Articles/211883/](File-based capabilities)
|
||||||
|
* [http://lwn.net/Articles/199004/](A bid to resurrect Linux capabilities)
|
||||||
|
@ -14,11 +14,12 @@ de ressources ou altérer leurs priorités.
|
|||||||
Nous allons commencer par faire quelques tests avec le *cgroup* freezer, qui
|
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 et de la reprendre.
|
||||||
|
|
||||||
|
|
||||||
### Montage du *cgroup*
|
### Montage du *cgroup*
|
||||||
|
|
||||||
En fonction de la configuration de votre système, il est possible que les
|
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
|
*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, monter-le en suivant la
|
pas de dossier `freezer` ou si celui-ci est vide, montez-le en suivant la
|
||||||
procédure suivante :
|
procédure suivante :
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -27,8 +28,9 @@ mount -t cgroup -o freezer none /sys/fs/cgroup/freezer/
|
|||||||
```
|
```
|
||||||
|
|
||||||
Cette dernière commande monte le groupe de processus racine, pour le *cgroup*
|
Cette dernière commande monte le groupe de processus racine, pour le *cgroup*
|
||||||
freezer. Tous les dossiers contenu dans cette racine sont des sous-groupes de
|
freezer. Tous les dossiers contenu dans cette racine sont donc des
|
||||||
cette dernière.
|
sous-groupes.
|
||||||
|
|
||||||
|
|
||||||
### Création d'un nouveau groupe
|
### Création d'un nouveau groupe
|
||||||
|
|
||||||
@ -47,6 +49,7 @@ Vous avez maintenant un nouveau groupe de processus `virli` dans le *cgroup*
|
|||||||
Freezer. Comme il s'agit d'une hiérarchie, le groupe `virli` hérite des
|
Freezer. Comme il s'agit d'une hiérarchie, le groupe `virli` hérite des
|
||||||
propriétés de son (ses) père(s).
|
propriétés de son (ses) père(s).
|
||||||
|
|
||||||
|
|
||||||
### Rattachement de processus
|
### Rattachement de processus
|
||||||
|
|
||||||
Pour le moment, ce nouveau groupe ne contient aucune tâche.
|
Pour le moment, ce nouveau groupe ne contient aucune tâche.
|
||||||
@ -64,22 +67,24 @@ echo $PID > /sys/fs/cgroup/freezer/virli/tasks
|
|||||||
Il faut ici remplacer `$PID` par le PID du shell que l'on a relevé juste avant.
|
Il faut ici remplacer `$PID` par le PID du shell que l'on a relevé juste avant.
|
||||||
|
|
||||||
En validant cette commande, vous avez déplacé le processus dans ce groupe, il
|
En validant cette commande, vous avez déplacé le processus dans ce groupe, il
|
||||||
n'est alors plus dans aucun autre groupe (dans ce *cgroup*, il ne bouge pas
|
n'est alors plus dans aucun autre groupe (pour ce *cgroup*, il ne bouge pas
|
||||||
dans les autres *cgroup*s).
|
dans les autres *cgroup*s).
|
||||||
|
|
||||||
|
|
||||||
### Consultation de l'état
|
### Consultation de l'état
|
||||||
|
|
||||||
En affichant le contenu du dossier `virli`, nous avons pu constater que
|
En affichant le contenu du dossier `virli`, nous pouvons constater que celui-ci
|
||||||
celui-ci contenait déjà un certain nombre de fichiers. Certain d'entre-eux sont
|
contenait déjà un certain nombre de fichiers. Certain d'entre-eux sont en
|
||||||
en lecture seule et permettent de lire des statistiques instantanées sur le
|
lecture seule et permettent de lire des statistiques instantanées sur le groupe
|
||||||
groupe ; tandis que d'autres sont des propriétés que vous pouvez modifier.
|
; tandis que d'autres sont des propriétés que vous pouvez modifier.
|
||||||
|
|
||||||
Nous pouvons consulter l'état de gel du groupe en affichant le contenu du
|
Nous pouvons consulter l'état de gel du groupe en affichant le contenu du
|
||||||
fichier\newline `/sys/fs/cgroup/freezer/virli/freezer.state`.
|
fichier\newline `/sys/fs/cgroup/freezer/virli/freezer.state`.
|
||||||
|
|
||||||
Pour plus d'information sur les différents fichiers présents dans ce *cgroup*,
|
Pour plus d'information sur les différents fichiers présents dans ce *cgroup*,
|
||||||
consulter la documentation, accessible ici :
|
consulter
|
||||||
<https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt>
|
[la documentation associée](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt).
|
||||||
|
|
||||||
|
|
||||||
### Changement d'état
|
### Changement d'état
|
||||||
|
|
||||||
@ -105,11 +110,28 @@ echo THAWED > /sys/fs/cgroup/freezer/virli/freezer.state
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Script de monitoring
|
## Exercice : script de 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) :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run -d -p 8086:8086 -p 8083:8083 influxdb
|
||||||
|
```
|
||||||
|
|
||||||
|
Il nous faut ensuite créer une base de données pour y stocker les métriques,
|
||||||
|
rendez-vous à <http://localhost:8083/> puis entrez la requête :
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE DATABASE metrics;
|
||||||
|
```
|
||||||
|
|
||||||
À nous maintenant de concevoir un script qui va enregistrer vers la base de
|
|
||||||
données créée (*metrics*) dans la partie précédente, des statistiques issues
|
|
||||||
des *cgroup*s.
|
|
||||||
|
|
||||||
### Monitoring instantané vers la console
|
### Monitoring instantané vers la console
|
||||||
|
|
||||||
@ -125,30 +147,29 @@ mémoire utilisée par le groupe monitoré.
|
|||||||
Vous pouvez utiliser un programme comme `memhog` pour remplir rapidement votre
|
Vous pouvez utiliser un programme comme `memhog` pour remplir rapidement votre
|
||||||
mémoire.
|
mémoire.
|
||||||
|
|
||||||
Si vous n'avez pas le *cgroup* memory, il est possible qu'il ne soit
|
Si vous n'avez pas le *cgroup* memory, il est possible qu'il ne soit pas activé
|
||||||
pas activé par défaut par votre système. Si vous êtes dans ce cas, essayez d'ajouter
|
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.
|
||||||
|
|
||||||
```
|
|
||||||
cgroup_enable=memory
|
|
||||||
```
|
|
||||||
|
|
||||||
### Monitoring vers InfluxDB
|
### Monitoring vers InfluxDB
|
||||||
|
|
||||||
Maintenant, envoyons nos données vers la base
|
Maintenant, envoyons nos données vers la base
|
||||||
<https://influxdb.com/docs/v0.9/guides/writing_data.html> :
|
<https://docs.influxdata.com/influxdb/v1.0/guides/writing_data/> :
|
||||||
|
|
||||||
```
|
```
|
||||||
curl -i -XPOST 'http://172.23.42.2:8086/write?db=metrics' --data-binary \
|
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)"
|
"$my_cgroup_name memory.usage_in_bytes=$(cat .../my_cgroup_name/memory.usage_in_bytes)"
|
||||||
```
|
```
|
||||||
|
|
||||||
Pour vérifier que les données sont bien ajoutées, vous pouvez effectuez la
|
Pour vérifier que les données ont bien été ajoutées, vous pouvez effectuez la
|
||||||
requête suivante dans l'interface web d'InfluxDB :
|
requête suivante dans l'interface web d'InfluxDB :
|
||||||
|
|
||||||
```
|
```
|
||||||
SELECT * from "$my_cgroup_name";
|
SELECT * from "$my_cgroup_name";
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Monitorer davantage de données
|
### Monitorer davantage de données
|
||||||
|
|
||||||
Liste non exhaustive de données à monitorer :
|
Liste non exhaustive de données à monitorer :
|
||||||
@ -159,7 +180,8 @@ Liste non exhaustive de données à monitorer :
|
|||||||
* trafic réseau généré ;
|
* trafic réseau généré ;
|
||||||
* ...
|
* ...
|
||||||
|
|
||||||
<https://www.kernel.org/doc/Documentation/cgroups/>
|
<https://www.kernel.org/doc/Documentation/cgroup-v1/>
|
||||||
|
|
||||||
|
|
||||||
### Permettre à l'utilisateur de monitorer des process
|
### Permettre à l'utilisateur de monitorer des process
|
||||||
|
|
||||||
@ -172,7 +194,7 @@ bons droits, tandis que le deuxième va utiliser effectuer le monitoring, sans
|
|||||||
#### Exemple
|
#### Exemple
|
||||||
|
|
||||||
```
|
```
|
||||||
42sh# ./monitor_init my_cgroup_name
|
42sh$ sudo ./monitor_init my_cgroup_name
|
||||||
42sh$ ./monitor my_cgroup_name memhog 500
|
42sh$ ./monitor my_cgroup_name memhog 500
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -181,8 +203,7 @@ bons droits, tandis que le deuxième va utiliser effectuer le monitoring, sans
|
|||||||
|
|
||||||
### Script de monitoring
|
### Script de monitoring
|
||||||
|
|
||||||
Rendez la révision la plus avancée de vos scripts de monitoring de process via
|
Rendez la révision la plus avancée de vos scripts de monitoring de processus.
|
||||||
les *cgroup*s.
|
|
||||||
|
|
||||||
### Questions
|
### Questions
|
||||||
|
|
||||||
@ -194,3 +215,19 @@ les *cgroup*s.
|
|||||||
|
|
||||||
1. Actuellement, comment peut-on limiter le nombre de processus lancés par un
|
1. Actuellement, comment peut-on limiter le nombre de processus lancés par un
|
||||||
utilisateur ou un groupe ?
|
utilisateur ou un groupe ?
|
||||||
|
|
||||||
|
|
||||||
|
## Pour aller plus loin
|
||||||
|
|
||||||
|
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 :
|
||||||
|
|
||||||
|
* [https://lwn.net/Articles/679786/](Understanding the new control groups API)
|
||||||
|
;
|
||||||
|
* [https://www.kernel.org/doc/Documentation/cgroup-v2.txt](Kernel Document
|
||||||
|
about Control Group v2).
|
||||||
|
|
||||||
|
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 !
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
L'isolation du pauvre
|
L'isolation ... du pauvre
|
||||||
=====================
|
=========================
|
||||||
|
|
||||||
Depuis les premières version d'Unix, il est possible de changer le répertoire
|
Depuis les premières version d'Unix, il est possible de changer le répertoire
|
||||||
vu comme étant la racine du système de fichiers.
|
vu comme étant la racine du système de fichiers.
|
||||||
@ -74,7 +74,7 @@ Dans le nouvel environnement, vous ne devriez pas pouvoir faire :
|
|||||||
cat ../foo
|
cat ../foo
|
||||||
```
|
```
|
||||||
|
|
||||||
Mais une fois votre programme exécuté, vous devriez pouvoir !
|
Mais une fois votre programme `escape` exécuté, vous devriez pouvoir !
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
./escape
|
./escape
|
||||||
|
@ -1,214 +0,0 @@
|
|||||||
\newpage
|
|
||||||
|
|
||||||
# Utiliser `lxc`
|
|
||||||
|
|
||||||
Le but de cette première partie est d'appréhender la virtualisation légère au
|
|
||||||
travers d'un programme, `lxc`, qui va mettre en place pour nous tout un
|
|
||||||
environnement distinct.
|
|
||||||
|
|
||||||
|
|
||||||
## Lancer un conteneur
|
|
||||||
|
|
||||||
Avec le paquet `lxc` que nous avons précédemment installé, nous avons également
|
|
||||||
récupéré un certain nombre de *modèles* de système (souvent installés dans le
|
|
||||||
dossier `/usr/share/lxc/templates/`) : il s'agit d'une suite de commandes
|
|
||||||
(principalement des `wget`, `chroot` ou `debootstrap`) permettant d'obtenir un
|
|
||||||
système basic fonctionnel, en suivant les étapes d'installation habituelle de
|
|
||||||
la distribution.
|
|
||||||
|
|
||||||
La méthode la plus simple pour lancer un conteneur `lxc` est d'utiliser l'un de
|
|
||||||
ces modèles pour obtenir un nouveau système. On utilise pour cela la commande
|
|
||||||
`lxc-create` :
|
|
||||||
|
|
||||||
```
|
|
||||||
lxc-create --name toto_first --template debian
|
|
||||||
```
|
|
||||||
|
|
||||||
Ce modèle va créer un dossier dans `/var/lib/lxc/` (pouvant varier d'une
|
|
||||||
distribution à l'autre) portant le nom que nous avons précisé. Ce dossier va
|
|
||||||
contenir la configuration `lxc` du conteneur (`config`), la table des
|
|
||||||
partitions (`fstab`) s'il y a besoin de faire des montages particuliers et
|
|
||||||
enfin le dossier `rootfs` contenant le système en lui-même.
|
|
||||||
|
|
||||||
Une fois l'installation terminée, on peut démarrer le conteneur :
|
|
||||||
|
|
||||||
```
|
|
||||||
lxc-start --name toto_first
|
|
||||||
```
|
|
||||||
|
|
||||||
`lxc` va appeler `/sbin/init` et démarrer tous les services que l'on peut
|
|
||||||
s'attendre à trouver dans n'importe quelle machine virtuelle (et même physique)
|
|
||||||
plus classique (la seule différence réside donc dans le fait que le noyau est
|
|
||||||
partagé avec l'hôte).
|
|
||||||
|
|
||||||
Généralement on lance `lxc-start` avec l'option `--daemon`, car on n'a pas
|
|
||||||
vraiment envie d'avoir un conteneur bloquant un terminal. En mode daemon, on va
|
|
||||||
utiliser la commande `lxc-console` pour nous attacher aux conteneurs. À tout
|
|
||||||
moment, nous pouvons nous détacher de la console (sans que cela n'affecte
|
|
||||||
l'état du conteneur) en pressant les touches : `^A q`.
|
|
||||||
|
|
||||||
Connectons-nous, lancons quelques commandes puis éteignons la machine en
|
|
||||||
lançant la commande `poweroff` dans le conteneur. Il est également possible de
|
|
||||||
lancer la commande `lxc-stop --name toto_first` dans un autre terminal, depuis
|
|
||||||
la machine hôte.
|
|
||||||
|
|
||||||
|
|
||||||
## Le réseau
|
|
||||||
|
|
||||||
Le modèle *Debian*, que nous avons utilisé, préremplit un fichier de
|
|
||||||
configuration sans définir de paramètre pour le réseau. Il n'y a donc pas
|
|
||||||
d'interface dans le conteneur pour le connecter :
|
|
||||||
|
|
||||||
```
|
|
||||||
lxc.network.type = empty
|
|
||||||
```
|
|
||||||
|
|
||||||
Un excellent article détaillant les différents types de configuration réseau
|
|
||||||
est accessible à
|
|
||||||
<https://blog.flameeyes.eu/2010/09/linux-containers-and-networking>.
|
|
||||||
|
|
||||||
N'ayant qu'une seule interface physique sur la machine et n'ayant pas accès à
|
|
||||||
la configuration des VLAN de la pièce, il ne nous reste que deux méthodes pour
|
|
||||||
obtenir du réseau dans nos conteneurs : Virtual Ethernet ou MACVLAN.
|
|
||||||
|
|
||||||
### MACVLAN
|
|
||||||
|
|
||||||
Cette méthode est la plus simple : le noyau va orienter les paquets en fonction
|
|
||||||
de leur adresse MAC de destination. Le conteneur sera donc comme une machine
|
|
||||||
supplémentaire sur le réseau.
|
|
||||||
|
|
||||||
Modifions notre fichier de configuration afin qu'il ressemble à quelque chose
|
|
||||||
comme :
|
|
||||||
|
|
||||||
```
|
|
||||||
lxc.network.type = macvlan
|
|
||||||
lxc.network.macvlan.mode = bridge
|
|
||||||
lxc.network.flags = up
|
|
||||||
lxc.network.link = eth0
|
|
||||||
```
|
|
||||||
|
|
||||||
Après avoir démarré le conteneur, il devrait avoir obtenu une IP du serveur
|
|
||||||
DHCP de l'école. L'inconvénient dans cette configuration est qu'il faille un
|
|
||||||
client netsoul dans chaque conteneur, puisque chacun est considéré comme une
|
|
||||||
machine différente aux yeux du routeur.
|
|
||||||
|
|
||||||
|
|
||||||
### Virtual Ethernet
|
|
||||||
|
|
||||||
Virtual Ethernet est la configuration la moins optimale, mais sans doute la
|
|
||||||
plus flexible.
|
|
||||||
|
|
||||||
Voici un extrait de configuration correspondant au paramétrage d'une interface
|
|
||||||
virtuelle pour un conteneur donné :
|
|
||||||
|
|
||||||
```
|
|
||||||
lxc.network.type = veth
|
|
||||||
lxc.network.ipv4 = 172.23.42.2/24
|
|
||||||
lxc.network.flags = up
|
|
||||||
```
|
|
||||||
|
|
||||||
Dans cette situation, au démarrage du conteneur, `lxc` va créer une interface
|
|
||||||
veth, avec un côté placé dans la machine hôte et l'autre côté placé dans le
|
|
||||||
conteneur. `lxc` configure l'interface dans le conteneur, il nous appartient
|
|
||||||
ensuite de configurer la machine hôte.
|
|
||||||
|
|
||||||
Commençons par attribuer une IP à cette nouvelle interface, en adaptant à votre
|
|
||||||
identifiant d'interface :
|
|
||||||
|
|
||||||
```
|
|
||||||
ip addr add 172.23.42.1/24 dev vethYJWD6R
|
|
||||||
```
|
|
||||||
|
|
||||||
À partir de là, nous devrions pouvoir pinger notre conteneur depuis notre
|
|
||||||
machine hôte : `ping 172.23.42.2`.
|
|
||||||
|
|
||||||
Notre conteneur ne peut cependant pas encore accéder à Internet. Pour cela, la
|
|
||||||
machine hôte doit faire office de routeur et donc router les paquets d'un
|
|
||||||
réseau à l'autre : en l'occurence, du réseau 172.23.42.1 vers Internet
|
|
||||||
via 10.0.0.0/8, le réseau de l'école.
|
|
||||||
|
|
||||||
Pour que notre machine hôte route les paquets, exécuter la commande :
|
|
||||||
|
|
||||||
```
|
|
||||||
sysctl -w net.ipv4.ip_forward=1
|
|
||||||
```
|
|
||||||
|
|
||||||
Cette variable, que nous retrouvons dans `/proc/sys/net/ipv4/ip_forward`,
|
|
||||||
indique au noyau qu'il peut faire passer les paquets réseau d'une interface à
|
|
||||||
l'autre. Sans plus de directives, les paquets vont conserver leur adresse
|
|
||||||
source (172.23.42.2 pour les paquets en provenance du conteneur). Cette adresse
|
|
||||||
est une adresse privée, non routable sur Internet, ni même par le bocal. Il
|
|
||||||
faut donc ajouter une couche de NAT/PAT pour réécrire les adresses sources
|
|
||||||
avant d'envoyer les paquets sur internet :
|
|
||||||
|
|
||||||
```
|
|
||||||
iptables -t nat -A POSTROUTING ! -o vethYJWD6R -s 172.23.42.0/24 -j MASQUERADE
|
|
||||||
```
|
|
||||||
|
|
||||||
Dernière étape, dans notre conteneur, nous devons indiquer la route à utiliser
|
|
||||||
pour accéder à internet :
|
|
||||||
|
|
||||||
```
|
|
||||||
ip route add default via 172.23.42.1
|
|
||||||
```
|
|
||||||
|
|
||||||
Nous avons maintenant internet dans notre conteneur !
|
|
||||||
|
|
||||||
|
|
||||||
## Utilisation du conteneur
|
|
||||||
|
|
||||||
### Installation de InfluxDB
|
|
||||||
|
|
||||||
```
|
|
||||||
apt-get update
|
|
||||||
apt-get install wget
|
|
||||||
wget https://s3.amazonaws.com/influxdb/influxdb_0.9.4.2_amd64.deb
|
|
||||||
dpkg -i influxdb_0.9.4.2_amd64.deb
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test de l'installation
|
|
||||||
|
|
||||||
```
|
|
||||||
/opt/influxdb/influxd
|
|
||||||
```
|
|
||||||
|
|
||||||
Une fois que le service est démarré, vous devriez pouvoir accéder à l'interface
|
|
||||||
à : <http://172.23.42.2:8083/>
|
|
||||||
|
|
||||||
Créons une nouvelle base de données "metrics", elle nous servira dans la partie suivante.
|
|
||||||
|
|
||||||
|
|
||||||
## Rendu
|
|
||||||
|
|
||||||
### Configuration du conteneur
|
|
||||||
|
|
||||||
En plus des modifications que vous avez effectuées durant le TP, modifiez la
|
|
||||||
configuration du conteneur afin qu'il ne puisse pas utiliser plus que 256 MB de
|
|
||||||
RAM et 512 MB de swap.
|
|
||||||
|
|
||||||
Limitez ensuite les `capabilities(7)` de ce conteneur afin qu'il s'exécute avec
|
|
||||||
le strict minimum de droits, nécessaire au bon fonctionnement des programmes
|
|
||||||
installés.
|
|
||||||
|
|
||||||
**Rendez le fichier `config` de ce premier conteneur.** N'hésitez pas à laisser
|
|
||||||
des commentaires justifiant vos éventuels choix.
|
|
||||||
|
|
||||||
### Questions
|
|
||||||
|
|
||||||
1. Quels sont les autres types de virtualisation réseau existants ? Expliquez
|
|
||||||
en chacun une phrase leurs particularités.
|
|
||||||
|
|
||||||
1. Quel fichier de configuration devriez-vous changer pour rendre persistante la
|
|
||||||
valeur d'`ip_forward` ?
|
|
||||||
|
|
||||||
1. Dans quel langage InfluxDB a-t-il été écrit ? Quelle est la particularité
|
|
||||||
des binaires générés par ce langage ?
|
|
||||||
|
|
||||||
1. Quels sont les avantages et les inconvénients associés au linkage statique
|
|
||||||
et au linkage dynamique ? (pas forcément que dans le cadre de la
|
|
||||||
virtualisation légère).
|
|
||||||
|
|
||||||
1. J'ai utilisé la méthode *Virtual Ethernet* pour relier mes conteneurs à
|
|
||||||
Internet, via l'interface `br0`. Quelle(s) règle(s) `iptables` devrais-je
|
|
||||||
écrire sur mon hôte afin de permettre l'accès à InfluxDB depuis une autre
|
|
||||||
machine ?
|
|
@ -1,133 +0,0 @@
|
|||||||
\newpage
|
|
||||||
|
|
||||||
# Utiliser les *namespaces*
|
|
||||||
|
|
||||||
## Comparaison de *namespace*
|
|
||||||
|
|
||||||
Écrivez un script ou un programme, `cmpns`, dans le langage courant de votre
|
|
||||||
choix, permettant de déterminer si deux programmes s'exécutent dans les mêmes
|
|
||||||
*namespaces*.
|
|
||||||
|
|
||||||
### Exemples
|
|
||||||
|
|
||||||
```sh
|
|
||||||
42sh$ cmpns $(pgrep influxdb) $(pgrep init)
|
|
||||||
- ipc: differ
|
|
||||||
- mnt: differ
|
|
||||||
- net: differ
|
|
||||||
- pid: differ
|
|
||||||
- user: same
|
|
||||||
- uts: same
|
|
||||||
```
|
|
||||||
|
|
||||||
```sh
|
|
||||||
42sh$ cmpns $(pgrep init) self
|
|
||||||
- ipc: same
|
|
||||||
- mnt: same
|
|
||||||
- net: same
|
|
||||||
- pid: same
|
|
||||||
- user: same
|
|
||||||
- uts: same
|
|
||||||
```
|
|
||||||
|
|
||||||
Ici, `self` fait référence au processus actuellement exécuté.
|
|
||||||
|
|
||||||
|
|
||||||
## Rejoindre un *namespace*
|
|
||||||
|
|
||||||
Dans le langage courant de votre choix, écrivez un programme : `setns`,
|
|
||||||
permettant, à la manière de `unshare(1)` et `unshare(2)`, d'utiliser `setns(2)`
|
|
||||||
via votre interpréteur.
|
|
||||||
|
|
||||||
Les options attendues sont :
|
|
||||||
|
|
||||||
* rejoindre un *namespace* IPC : `-i`, `--ipc` ;
|
|
||||||
* rejoindre un *namespace* mount : `-m`, `--mount` ;
|
|
||||||
* rejoindre un *namespace* net : `-n`, `--net` ;
|
|
||||||
* rejoindre un *namespace* PID : `-p`, `--pid` ;
|
|
||||||
* rejoindre un *namespace* UTS : `-u`, `--uts` ;
|
|
||||||
* rejoindre un *namespace* user : `-U`, `--user`.
|
|
||||||
|
|
||||||
### Exemples
|
|
||||||
|
|
||||||
```sh
|
|
||||||
42sh# setns /bin/bash
|
|
||||||
bash# _
|
|
||||||
```
|
|
||||||
|
|
||||||
#### IPC and PID Namespaces
|
|
||||||
|
|
||||||
```sh
|
|
||||||
42sh# setns --ipc=/proc/42/ns/ipc -p /proc/42/ns/pid /bin/echo toto
|
|
||||||
toto
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Net Namespace
|
|
||||||
|
|
||||||
```sh
|
|
||||||
42sh# setns --net=/proc/42/ns/net ip a
|
|
||||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
|
|
||||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00::00
|
|
||||||
inet 127.0.0.1/8 brd 127.255.255.255 scope lo
|
|
||||||
valid_lft forever preferred_lft
|
|
||||||
inet6 ::1/128 scope host
|
|
||||||
valid_lft forever preferred_lft forever
|
|
||||||
```
|
|
||||||
|
|
||||||
#### UTS Namespace
|
|
||||||
|
|
||||||
```sh
|
|
||||||
42sh# hostname --fqdn
|
|
||||||
koala.zoo.paris
|
|
||||||
42sh# setns --uts=/proc/42/ns/uts hostname --fqdn
|
|
||||||
lynx.zoo.paris
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## My Little Container
|
|
||||||
|
|
||||||
En utilisant le langage courant de votre choix, concevez l'exécutable `mlc`,
|
|
||||||
permettant de lancer une application dans un environnement différent (comme un
|
|
||||||
`chroot`, mais sans permettre de s'en échapper) et avec des privilèges réduits.
|
|
||||||
|
|
||||||
Votre solution doit créer au moins un nouveau *namespace* mount et PID.
|
|
||||||
|
|
||||||
Vous aurez sans doute besoin de : `clone(2)`, `capabilities(7)`, `capset(2)`, `pivot_root(2)`,
|
|
||||||
|
|
||||||
### Exemples
|
|
||||||
|
|
||||||
```sh
|
|
||||||
42sh# ls newroot
|
|
||||||
bin etc home usr root proc var
|
|
||||||
|
|
||||||
42sh# mlc newroot/ /bin/bash
|
|
||||||
bash# ls ../../../
|
|
||||||
bin etc home usr root proc var
|
|
||||||
|
|
||||||
bash# escape_chroot ls
|
|
||||||
bin etc home usr root proc var
|
|
||||||
|
|
||||||
bash# ls -ld /proc/[0-9]* | wc -l
|
|
||||||
2
|
|
||||||
|
|
||||||
bash# curl http://www.linuxcontainers.org/ | md5sum
|
|
||||||
0123456789abcdef
|
|
||||||
|
|
||||||
bash# ping 8.8.8.8
|
|
||||||
Operation not permitted
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Rendu
|
|
||||||
|
|
||||||
Pour chaque exercice de cette partie, vous pouvez rendre un seul fichier s'il
|
|
||||||
s'agit d'un script ; sinon, vous devez rendre une tarball contenant un
|
|
||||||
`Makefile` permettant de générer les éventuels exécutables et/ou un `README`
|
|
||||||
expliquant comment s'en servir.
|
|
||||||
|
|
||||||
Vous devez donc rendre 3 fichiers : `cmpns` ou `cmpns.tar.bz2`, `setns` ou
|
|
||||||
`setns.tar.bz2` et `mlc` ou `mlc.tar.bz2`.
|
|
||||||
|
|
||||||
\vspace{3em}
|
|
||||||
|
|
||||||
Bon courage !
|
|
@ -5,6 +5,9 @@ Projet et rendu
|
|||||||
|
|
||||||
## Sujet
|
## Sujet
|
||||||
|
|
||||||
|
**Ce projet, étalé sur ce TP et le TP suivant, constitue le cœur de la notation
|
||||||
|
de ce cours.**
|
||||||
|
|
||||||
Vous allez commencer aujourd'hui un projet qui s'étendra au prochain TP et qui
|
Vous allez commencer aujourd'hui un projet qui s'étendra au prochain TP et qui
|
||||||
consistera à réaliser la partie d'isolation de la moulinette des ACUs !
|
consistera à réaliser la partie d'isolation de la moulinette des ACUs !
|
||||||
|
|
||||||
@ -26,36 +29,82 @@ principalement question de faire des appels système.
|
|||||||
|
|
||||||
### Stage 1 : Restreindre l'environnement
|
### Stage 1 : Restreindre l'environnement
|
||||||
|
|
||||||
Après avoir mis en place les bases de votre programme,
|
Après avoir mis en place les bases de votre programme, commencez par créer les
|
||||||
|
différentes hiérarchies (si vous avez un noyau récent, vous pouvez les
|
||||||
|
cgroups-v2) dont vous allez avoir besoin pour limiter l'utilisation de
|
||||||
|
ressources.
|
||||||
|
|
||||||
|
Puis, mettez en place ces limites :
|
||||||
|
|
||||||
|
* pas plus d'1 GB de mémoire utilisée ;
|
||||||
|
* 1 seul CPU au maximum ;
|
||||||
|
* ...
|
||||||
|
|
||||||
|
|
||||||
### Stage 2 : Réduire les capabilities
|
### Stage 2 : Réduire les *capabilities*
|
||||||
|
|
||||||
|
Réduisez au maximum les capabilities, de telle sorte qu'il ne soit pas possible
|
||||||
|
de faire un ping dans l'environnement restreint :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
42sh# ping 8.8.8.8
|
||||||
|
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
|
||||||
|
64 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=3.93 ms
|
||||||
|
64 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=3.97 ms
|
||||||
|
^C
|
||||||
|
--- 8.8.8.8 ping statistics ---
|
||||||
|
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
|
||||||
|
rtt min/avg/max/mdev = 3.931/3.954/3.978/0.067 ms
|
||||||
|
|
||||||
|
42sh# ./mymoulette /bin/bash
|
||||||
|
bash# curl http://www.linuxcontainers.org/ | md5sum
|
||||||
|
59e714c4331e71ac3529a6502994ef1d
|
||||||
|
|
||||||
|
bash# ping 8.8.8.8
|
||||||
|
Operation not permitted
|
||||||
|
```
|
||||||
|
|
||||||
|
Astuces : `prctl(2)`, `capabilities(7)`, `capget(2)`, `capset(2)`, ...
|
||||||
|
|
||||||
|
|
||||||
### Stage 3 : Script d'initialisation
|
### Stage 3 : Utilisable par un utilisateur
|
||||||
|
|
||||||
|
Jouez avec les attributs étendus pour qu'un utilisateur non-privilégié puisse
|
||||||
|
exécuter votre moulinette. Ajouter la/les commande(s) à votre Makefile ou
|
||||||
|
script d'installation.
|
||||||
|
|
||||||
|
|
||||||
### Stage 4 : Utilisable par un utilisateur
|
### Création d'un environnement d'exécution minimal
|
||||||
|
|
||||||
Une autre solution
|
Plutôt que d'utiliser votre système hôte au complet, avec tous ses programmes
|
||||||
|
et toutes ses bibliothèques, il faudrait utiliser un système contenant le
|
||||||
|
strict minimum. Recréez un environnement minimaliste, comme on a pu en voir
|
||||||
|
dans la partie sur les *chroot*.
|
||||||
|
|
||||||
|
**Ne rendez pas cet environnement, il vous sera seulement utile pour faire des
|
||||||
|
tests.**
|
||||||
|
|
||||||
|
|
||||||
### Stage 5 : Création de l'environnement d'exécution
|
### Stage 4 : Isolation du pauvre
|
||||||
|
|
||||||
Plutôt que d'utiliser votre système hôte complet, il faudrait utiliser un
|
|
||||||
système contenant le struct minimum.
|
|
||||||
|
|
||||||
|
|
||||||
### Stage 6 : Isolation du pauvre
|
|
||||||
|
|
||||||
Nous n'avons pas encore vu de meilleure méthode pour mieux isoler
|
Nous n'avons pas encore vu de meilleure méthode pour mieux isoler
|
||||||
l'environnement que de faire un `chroot`, ajouter à votre programme cette
|
l'environnement que de faire un `chroot`, ajouter à votre programme cette
|
||||||
isolation rudimentaire.
|
isolation rudimentaire. Et rendez-vous au prochain cours pour avoir de
|
||||||
|
moyen d'isolation !
|
||||||
|
|
||||||
|
|
||||||
### Stage 7 (bonus) : automatisation de l'environnement
|
### Stage 5 (bonus) : automatisation de la création de l'environnement
|
||||||
|
|
||||||
LVM
|
Pour moulinéter plusieurs étudiants en parallèle, vous allez avoir besoin de
|
||||||
|
plusieurs environnements identiques. Plutôt que de recopier cet environnement,
|
||||||
|
de le nettoyer, de le recréer, pour chaque étudiant, ajoutez à votre moulinette
|
||||||
|
un support pour LVM : utiliser des *snapshots* pour figer votre environnement
|
||||||
|
et le dupliquer facilement pour chaque étudiant.
|
||||||
|
|
||||||
|
L'usage est laissé à votre discrétion : vous pouvez ajouter un/des paramètres à
|
||||||
|
votre moulette pour indiquer le volume LVM à utiliser ou le définir en dur ou
|
||||||
|
encore séparer la création de l'environnement et de la snapshot initiale dans
|
||||||
|
un programme distinct.
|
||||||
|
|
||||||
|
|
||||||
## Modalité de rendu
|
## Modalité de rendu
|
||||||
@ -82,8 +131,12 @@ Voici une arborescence type:
|
|||||||
|
|
||||||
```
|
```
|
||||||
login_x-TP3/questions.txt
|
login_x-TP3/questions.txt
|
||||||
login_x-TP3/
|
login_x-TP3/chroot/escape.c
|
||||||
|
login_x-TP3/pseudofs/rev_kdb_leds.sh
|
||||||
|
login_x-TP3/pseudofs/procinfo
|
||||||
|
login_x-TP3/caps/view_caps
|
||||||
|
login_x-TP3/cgroups/monitor
|
||||||
|
login_x-TP3/cgroups/monitor_init
|
||||||
|
login_x-TP3/mymoulette/README
|
||||||
|
login_x-TP3/mymoulette/...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Astuces
|
|
||||||
|
@ -53,6 +53,32 @@ exemple, pour modifier les paramètres du noyau, on passe par le fichier
|
|||||||
|
|
||||||
## Exercice
|
## Exercice
|
||||||
|
|
||||||
|
### `rev_kdb_leds.sh`
|
||||||
|
|
||||||
|
Explorons le pseudo système de fichiers `/sys` pour écrire un script
|
||||||
|
qui va inverser l'état des diodes de notre clavier.
|
||||||
|
|
||||||
|
Si vous avez :
|
||||||
|
|
||||||
|
* numlock On,
|
||||||
|
* capslock Off,
|
||||||
|
* scrolllock Off ;
|
||||||
|
|
||||||
|
Après avoir exécuté le script, nous devrions avoir :
|
||||||
|
|
||||||
|
* numlock Off,
|
||||||
|
* capslock On,
|
||||||
|
* scrolllock On.
|
||||||
|
|
||||||
|
Voici un exemple d'utilisation :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
42sh$ ./rev_kdb_leds.sh input20
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### `procinfo`
|
||||||
|
|
||||||
Explorons le pseudo système de fichiers `/proc` pour écrire un script qui va
|
Explorons le pseudo système de fichiers `/proc` pour écrire un script qui va
|
||||||
afficher des informations sur un processus donné :
|
afficher des informations sur un processus donné :
|
||||||
|
|
||||||
@ -60,7 +86,7 @@ afficher des informations sur un processus donné :
|
|||||||
42sh$ ./procinfo $$
|
42sh$ ./procinfo $$
|
||||||
PID: 4242
|
PID: 4242
|
||||||
Path: /bin/bash
|
Path: /bin/bash
|
||||||
Arguments:
|
Command line: bash
|
||||||
Working directory: /home/nemunaire/virli/
|
Working directory: /home/nemunaire/virli/
|
||||||
Root: /
|
Root: /
|
||||||
State: S (sleeping)
|
State: S (sleeping)
|
||||||
@ -83,11 +109,18 @@ CGroups
|
|||||||
|
|
||||||
Namespaces
|
Namespaces
|
||||||
==========
|
==========
|
||||||
cgroup -> cgroup:[4026531835]
|
cgroup:[4026531835]
|
||||||
ipc -> ipc:[4026531839]
|
ipc:[4026531839]
|
||||||
mnt -> mnt:[4026531840]
|
mnt:[4026531840]
|
||||||
net -> net:[4026531969]
|
net:[4026531969]
|
||||||
pid -> pid:[4026531836]
|
pid:[4026531836]
|
||||||
user -> user:[4026531837]
|
user:[4026531837]
|
||||||
uts -> uts:[4026531838]
|
uts:[4026531838]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Rendu
|
||||||
|
|
||||||
|
### Fichiers
|
||||||
|
|
||||||
|
Rendez vos scripts `rev_kdb_leds.sh` et `procinfo`.
|
||||||
|
@ -1,195 +0,0 @@
|
|||||||
\newpage
|
|
||||||
|
|
||||||
# Utiliser 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, comme par exemple pour leur imposer des limitations d'utilisation
|
|
||||||
de ressources ou altérer leurs priorités.
|
|
||||||
|
|
||||||
|
|
||||||
## Premiers tests
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
### Montage du *cgroup*
|
|
||||||
|
|
||||||
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, monter-le en suivant la
|
|
||||||
procédure suivante :
|
|
||||||
|
|
||||||
```
|
|
||||||
mkdir /sys/fs/cgroup/freezer/
|
|
||||||
mount -t cgroup -o freezer none /sys/fs/cgroup/freezer/
|
|
||||||
```
|
|
||||||
|
|
||||||
Cette dernière commande monte le groupe de processus racine, pour le *cgroup*
|
|
||||||
freezer. Tous les dossiers contenu dans cette racine sont des sous-groupes de
|
|
||||||
cette dernière.
|
|
||||||
|
|
||||||
### Création d'un nouveau groupe
|
|
||||||
|
|
||||||
La première étape dans l'utilisation d'un *cgroup* est de créer un nouveau
|
|
||||||
groupe.
|
|
||||||
|
|
||||||
Pour créer un groupe, il suffit de créer un nouveau dossier dans un groupe
|
|
||||||
existant, par exemple la racine :
|
|
||||||
|
|
||||||
```
|
|
||||||
mkdir /sys/fs/cgroup/freezer/virli/
|
|
||||||
ls /sys/fs/cgroup/freezer/virli/
|
|
||||||
```
|
|
||||||
|
|
||||||
Vous avez maintenant un nouveau groupe de processus `virli` dans le *cgroup*
|
|
||||||
Freezer. Comme il s'agit d'une hiérarchie, le groupe `virli` hérite des
|
|
||||||
propriétés de son (ses) père(s).
|
|
||||||
|
|
||||||
### Rattachement de processus
|
|
||||||
|
|
||||||
Pour le moment, ce nouveau groupe ne contient aucune tâche.
|
|
||||||
|
|
||||||
Ouvrons un nouveau terminal (c'est lui que l'on va freezer), 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 :
|
|
||||||
|
|
||||||
```
|
|
||||||
echo $PID > /sys/fs/cgroup/freezer/virli/tasks
|
|
||||||
```
|
|
||||||
|
|
||||||
Il faut ici remplacer `$PID` par le PID du shell que l'on a relevé juste avant.
|
|
||||||
|
|
||||||
En validant cette commande, vous avez déplacé le processus dans ce groupe, il
|
|
||||||
n'est alors plus dans aucun autre groupe (dans ce *cgroup*, il ne bouge pas
|
|
||||||
dans les autres *cgroup*s).
|
|
||||||
|
|
||||||
### Consultation de l'état
|
|
||||||
|
|
||||||
En affichant le contenu du dossier `virli`, nous avons pu 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 vous pouvez modifier.
|
|
||||||
|
|
||||||
Nous pouvons consulter l'état de gel du groupe en affichant le contenu du
|
|
||||||
fichier\newline `/sys/fs/cgroup/freezer/virli/freezer.state`.
|
|
||||||
|
|
||||||
Pour plus d'information sur les différents fichiers présents dans ce *cgroup*,
|
|
||||||
consulter la documentation, accessible ici :
|
|
||||||
<https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt>
|
|
||||||
|
|
||||||
### 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 :
|
|
||||||
|
|
||||||
```
|
|
||||||
for i in $(seq 9999); do echo -n $i; sleep .1; echo -n " - "; sleep .1; done
|
|
||||||
```
|
|
||||||
|
|
||||||
Maintenant, nous avons donné l'ordre au noyau de ne plus allouer de temps de
|
|
||||||
calcul à notre shell et ses fils :
|
|
||||||
|
|
||||||
```
|
|
||||||
echo FROZEN > /sys/fs/cgroup/freezer/virli/freezer.state
|
|
||||||
```
|
|
||||||
|
|
||||||
À cet instant, vous devriez voir votre compteur s'arrêter. Pour reprendre
|
|
||||||
l'exécution :
|
|
||||||
|
|
||||||
```
|
|
||||||
echo THAWED > /sys/fs/cgroup/freezer/virli/freezer.state
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Script de monitoring
|
|
||||||
|
|
||||||
À nous maintenant de concevoir un script qui va enregistrer vers la base de
|
|
||||||
données créée (*metrics*) dans la partie précédente, des statistiques issues
|
|
||||||
des *cgroup*s.
|
|
||||||
|
|
||||||
### Monitoring instantané vers la console
|
|
||||||
|
|
||||||
Dans un premier temps, commençons par afficher dans la console la quantité de
|
|
||||||
mémoire utilisée par le groupe monitoré.
|
|
||||||
|
|
||||||
* Arguments de la ligne de commande :
|
|
||||||
- premier fils à lancer dans le groupe,
|
|
||||||
- intervalle de temps entre deux rafraîchissement ;
|
|
||||||
* *cgroup* `memory`;
|
|
||||||
* `memory.usage_in_bytes`.
|
|
||||||
|
|
||||||
Vous pouvez utiliser un programme comme `memhog` pour remplir rapidement votre
|
|
||||||
mémoire.
|
|
||||||
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
### Monitoring vers InfluxDB
|
|
||||||
|
|
||||||
Maintenant, envoyons nos données vers la base
|
|
||||||
<https://influxdb.com/docs/v0.9/guides/writing_data.html> :
|
|
||||||
|
|
||||||
```
|
|
||||||
curl -i -XPOST 'http://172.23.42.2:8086/write?db=metrics' --data-binary \
|
|
||||||
"$my_cgroup_name memory.usage_in_bytes=$(cat .../my_cgroup_name/memory.usage_in_bytes)"
|
|
||||||
```
|
|
||||||
|
|
||||||
Pour vérifier que les données sont bien ajoutées, vous pouvez effectuez la
|
|
||||||
requête suivante dans l'interface web d'InfluxDB :
|
|
||||||
|
|
||||||
```
|
|
||||||
SELECT * from "$my_cgroup_name";
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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é ;
|
|
||||||
* ...
|
|
||||||
|
|
||||||
<https://www.kernel.org/doc/Documentation/cgroups/>
|
|
||||||
|
|
||||||
### Permettre à l'utilisateur de monitorer des process
|
|
||||||
|
|
||||||
Maintenant, séparer votre 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 utiliser effectuer le monitoring, sans
|
|
||||||
|
|
||||||
#### Exemple
|
|
||||||
|
|
||||||
```
|
|
||||||
42sh# ./monitor_init my_cgroup_name
|
|
||||||
42sh$ ./monitor my_cgroup_name memhog 500
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Rendu
|
|
||||||
|
|
||||||
### Script de monitoring
|
|
||||||
|
|
||||||
Rendez la révision la plus avancée de vos scripts de monitoring de process via
|
|
||||||
les *cgroup*s.
|
|
||||||
|
|
||||||
### Questions
|
|
||||||
|
|
||||||
1. Un même processus peut-il être dans plusieurs *cgroup*s de type différents
|
|
||||||
(freezer et cpuacct par exemple) ?
|
|
||||||
|
|
||||||
1. Que sera-t-il possible de limiter via un nouveau *cgroup* dans la prochaine
|
|
||||||
version du noyau (4.3) ?
|
|
||||||
|
|
||||||
1. Actuellement, comment peut-on limiter le nombre de processus lancés par un
|
|
||||||
utilisateur ou un groupe ?
|
|
@ -1,55 +0,0 @@
|
|||||||
\newpage
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
|
|
||||||
## Noyau Linux
|
|
||||||
|
|
||||||
Ce TP requiert un noyau Linux 3.8 au minimum. De plus, il doit être
|
|
||||||
compilé avec les options suivantes :
|
|
||||||
|
|
||||||
```
|
|
||||||
General setup --->
|
|
||||||
[*] Control Group support --->
|
|
||||||
[*] Freezer cgroup subsystem
|
|
||||||
[*] Device controller for cgroups
|
|
||||||
[*] Cpuset support
|
|
||||||
[*] Include legacy /proc/<pid>/cpuset file
|
|
||||||
[*] Simple CPU accounting cgroup subsystem
|
|
||||||
[*] Group CPU scheduler --->
|
|
||||||
[*] Group scheduling for SCHED_OTHER
|
|
||||||
[*] Group scheduling for SCHED_RR/FIFO
|
|
||||||
<*> Block IO controller
|
|
||||||
-*- Namespaces support
|
|
||||||
[*] UTS namespace
|
|
||||||
[*] IPC namespace
|
|
||||||
[*] User namespace
|
|
||||||
[*] PID Namespaces
|
|
||||||
[*] Network namespace
|
|
||||||
[*] Networking support --->
|
|
||||||
Networking options --->
|
|
||||||
<*> 802.1d Ethernet Bridging
|
|
||||||
<M> 802.1Q VLAN Support
|
|
||||||
[*] Network priority cgroup
|
|
||||||
[*] Network classid cgroup
|
|
||||||
Device Drivers --->
|
|
||||||
[*] Network device support --->
|
|
||||||
<M> MAC-VLAN support
|
|
||||||
<*> Virtual ethernet pair device
|
|
||||||
Character devices --->
|
|
||||||
-*- Unix98 PTY support
|
|
||||||
[*] Support multiple instances of devpts
|
|
||||||
```
|
|
||||||
|
|
||||||
Une fois que vous aurez installé LXC, vous pouvez vérifier la compatibilité de
|
|
||||||
la configuration de votre noyau en utilisant la commande `lxc-checkconfig`.
|
|
||||||
|
|
||||||
|
|
||||||
## LXC
|
|
||||||
|
|
||||||
Pour installer LXC, utilisez le gestionnaire de paquets de votre
|
|
||||||
distribution. Toute les bonnes distributions fournissent un paquet
|
|
||||||
`lxc`. Vérifiez que la version installée est au moins la 1.0.
|
|
||||||
|
|
||||||
Aucune configuration ne devrait vous être demandé durant l'installation. Une
|
|
||||||
fois installé, exécutez la commande `lxc-checkconfig` pour vérifier que votre
|
|
||||||
noyau possède bien toutes les options nécessaires.
|
|
Loading…
x
Reference in New Issue
Block a user