From 49c5a2788555fb4ca63aa7c029667f1b6fb4e45d Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 8 Oct 2015 03:48:26 +0200 Subject: [PATCH] Tuto 1 done --- tutorial/1/cgroups.md | 164 +++++++++++++++++++++++++++--- tutorial/1/installation.md | 53 +++++----- tutorial/1/lxc.md | 202 ++++++++++++++++++++++++------------- tutorial/1/namespaces.md | 16 +-- tutorial/1/tutorial.md | 8 +- 5 files changed, 327 insertions(+), 116 deletions(-) diff --git a/tutorial/1/cgroups.md b/tutorial/1/cgroups.md index eb26291..a52541c 100644 --- a/tutorial/1/cgroups.md +++ b/tutorial/1/cgroups.md @@ -1,35 +1,172 @@ \newpage -# Utiliser les *cgroups* +# 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 -### Consultatation de l'état +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 : + ### 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 -### Monitoring instantanné vers la console +À 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. -#### Option pour choisir l'intervalle de polling +### 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. ### Monitoring vers InfluxDB +Maintenant, envoyons nos données vers la base + : + +``` +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é ; +* ... + + + ### Permettre à l'utilisateur de monitorer des process -#### Séparer en deux scripts +Maintenant, séparer votre script en deux parties afin qu'un utilisateur normal +(non-root) puisse utiliser la partie monitoring de notre script. -#### Ajouter les bonnes capabilities sur le premier 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 -#### Rendre ok avec les exécutions concurrentes du second script +#### Exemple -### Monitorer chaque fils indépendamment +``` +42sh# ./monitor_init my_cgroup_name +42sh$ ./monitor my_cgroup_name memhog 500 +``` ## Rendu @@ -37,14 +174,15 @@ ### Script de monitoring Rendez la révision la plus avancées de vos scripts de monitoring de process via -les *cgroups*. +les *cgroup*s. ### Questions -1. Un même processus peut-il être dans plusieurs cgroups de type différents (freezer et cpuacct par exemple) ? +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 +1. Que sera-t-il possible de limiter via un nouveau *cgroup* dans la prochaine version du noyau (4.3) ? -1. Comment peut-on limiter le nombre de processus lancés par un utilisateur ou - un groupe ? +1. Actuellement, comment peut-on limiter le nombre de processus lancés par un + utilisateur ou un groupe ? diff --git a/tutorial/1/installation.md b/tutorial/1/installation.md index c35499f..6b64372 100644 --- a/tutorial/1/installation.md +++ b/tutorial/1/installation.md @@ -4,38 +4,40 @@ ## Noyau Linux -Ce TP requiert d'avoir un noyau Linux en version 3.8 au minimum. De plus, il -doit être compilé avec les options suivantes : +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//cpuset file - [*] Simple CPU accounting cgroup subsystem - [*] Group CPU scheduler ---> - [*] Group scheduling for SCHED_OTHER - [*] Group scheduling for SCHED_RR/FIFO - <*> Block IO controller + [*] Freezer cgroup subsystem + [*] Device controller for cgroups + [*] Cpuset support + [*] Include legacy /proc//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 + [*] UTS namespace + [*] IPC namespace + [*] User namespace + [*] PID Namespaces + [*] Network namespace [*] Networking support ---> Networking options ---> - <*> 802.1d Ethernet Bridging - 802.1Q VLAN Support + <*> 802.1d Ethernet Bridging + 802.1Q VLAN Support + [*] Network priority cgroup + [*] Network classid cgroup Device Drivers ---> [*] Network device support ---> - MAC-VLAN support - <*> Virtual ethernet pair device + MAC-VLAN support + <*> Virtual ethernet pair device Character devices ---> - -*- Unix98 PTY support - [*] Support multiple instances of devpts + -*- Unix98 PTY support + [*] Support multiple instances of devpts ``` Une fois que vous aurez installé LXC, vous pouvez vérifier la compatibilité de @@ -45,8 +47,9 @@ 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`. +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 l'installation terminée, exécutez la commande `lxc-checkconfig` pour -vérifier que votre noyau possède bien toutes les options nécessaires. +fois installé, exécutez la commande `lxc-checkconfig` pour vérifier que votre +noyau possède bien toutes les options nécessaires. diff --git a/tutorial/1/lxc.md b/tutorial/1/lxc.md index 8800147..211745e 100644 --- a/tutorial/1/lxc.md +++ b/tutorial/1/lxc.md @@ -1,30 +1,34 @@ \newpage -# Utiliser LXC +# 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 un +travers d'un programme, `lxc`, qui va mettre en place pour nous tout un environnement distinct. ## Lancer un conteneur -Avec le paquet LXC que vous avez installé, vous avez également récupéré un -certain nombre de modèles de système (souvent installés dans le dossier -`/usr/share/lxc/templates/`). +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 qui va installer tout un environnement pour vous. On utilise pour -cela la commande `lxc-create` : +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 ubuntu +lxc-create --name toto_first --template debian ``` -Ce modèle va créer un dossier dans `/var/lib/lxc/` portant le nom que vous avez -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. +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 : @@ -32,86 +36,147 @@ 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 plus classique (la -seule différence réside donc dans le fait que le noyau est partagé avec -l'hôte). +`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 ne s'attend -pas à ce que la machine s'arrête lorsque l'on va quitter notre terminal. Dans -ce cas, utiliser la commande `lxc-console` pour vous attacher à votre -conteneur. À tout moment, vous pouvez vous détacher de la console (sans que -cela n'affecte l'état du conteneur) en pressant les touches : `^A q`. +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`. -Connectez-vous, lancez quelques commandes puis éteignez la machine avec `sudo -poweroff` dans le conteneur. Vous pouvez aussi lancer la commande `lxc-stop ---name toto_first` dans un autre terminal, depuis la machine hôte. +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 ubuntu que vous avez utilisé initialise un fichier de configuration -sans paramètres pour le réseau. Vous n'avez donc pas d'interface dans le -conteneur pour le connecter au 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 : -Un excellent article détaillant les différents types de réseau est accessible à +``` +lxc.network.type = empty +``` + +Un excellent article détaillant les différents types de configuration réseau +est accessible à . 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. Malheureusement, ces deux méthodes nécessitent de mettre en place un -pont Ethernet sur votre machine : - - -### Installation du pont réseau - -#### Bridge interface - -#### Port forwarding - - -### Virtual Ethernet - -Virtual Ethernet est la configuration la plus simple. On met en place un pont -sur la machine hôte, puis on crée une interface `veth` par conteneur que l'on -veut lancer. On n'oubliera pas d'ajouter ces interfaces au pont. - -Voici un extrait de configuration correspondant au paramétrage d'une interface -`eth0` pour un conteneur donné : - -``` -lxc.network.type = veth -lxc.network.flags = up -lxc.network.link = br0 -``` - -Cette technique a pour inconvénient de laisser au noyau le soin de router les -paquets selon leur adresse IP, ce qui peut être lent et coûteux étant donné que -la carte est placé en mode de promiscuité. - +obtenir du réseau dans nos conteneurs : Virtual Ethernet ou MACVLAN. ### MACVLAN -Ici, le noyau va orienter les paquets en fonction de leur adresse MAC de -destination. +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 = br0 +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 -### Redémarrage du conteneur +### Installation de InfluxDB -### Installation de InFluxDB et Graphana +``` +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 +à : + +Créons une nouvelle base de données "metrics", elle nous servira dans la partie suivante. + ## Rendu @@ -130,11 +195,12 @@ installés. ### Questions -1. Quel type de virtualisation réseau avez-vous utilisé ? pourquoi ? - 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 était écrit ? Quelle est la particularité des binaires générés par ce langage ? @@ -143,6 +209,6 @@ installés. virtualisation légère). 1. J'ai utilisé la méthode *Virtual Ethernet* pour relier mes conteneurs à - Internet, via un PAT (`br0`). Quelle(s) règle(s) `iptables` devrais-je + 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 ? diff --git a/tutorial/1/namespaces.md b/tutorial/1/namespaces.md index 43fb6cc..32092d9 100644 --- a/tutorial/1/namespaces.md +++ b/tutorial/1/namespaces.md @@ -41,12 +41,12 @@ 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`. +* 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 @@ -127,3 +127,7 @@ 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 ! diff --git a/tutorial/1/tutorial.md b/tutorial/1/tutorial.md index c830263..2ed31a9 100644 --- a/tutorial/1/tutorial.md +++ b/tutorial/1/tutorial.md @@ -6,10 +6,10 @@ Le but de ce premier TP est d'utiliser les commandes et les appels systèmes vu durant le cours. Tous les éléments de ce TP (exercices et questions) sont à rendre à - au plus tard le mercredi 21 octobre 2015 à 23 h 42. Consultez la -dernière section de chaque partie pour plus d'information sur les éléments à -rendre. Vous pouvez placer les réponses aux questions dans le corps du courriel -ou dans un fichier joint. + au plus tard le **mercredi 21 octobre 2015 à 23 +h 42**. Consultez la dernière section de chaque partie pour plus d'information +sur les éléments à rendre. Vous pouvez placer les réponses aux questions dans +le corps du courriel ou dans un fichier texte joint. En tant que personnes sensibilisées à la sécurité des échanges électroniques, vous devriez m'envoyer vos rendus signés avec votre clef PGP. Pensez à