Save tuto corrections

This commit is contained in:
nemunaire 2022-02-24 20:43:43 +01:00
commit 10448a6c8d
115 changed files with 1423 additions and 1289 deletions

View file

@ -3,7 +3,7 @@ include ../pandoc-opts.mk
SOURCES = tutorial.md \ SOURCES = tutorial.md \
../docker-basis/discover.md ../docker-basis/installation.md ../docker-basis/what.md ../docker-basis/first.md ../docker-basis/cleaning.md ../docker-basis/ex-flask.md \ ../docker-basis/discover.md ../docker-basis/installation.md ../docker-basis/what.md ../docker-basis/first.md ../docker-basis/cleaning.md ../docker-basis/ex-flask.md \
../docker-basis/volumes.md \ ../docker-basis/volumes.md \
../docker-basis/linking.md \ ../docker-basis/linking.md ../docker-basis/linking-ex-fic.md ../docker-basis/linking-ex-help.md \
../docker-advanced/what.md ../docker-advanced/setup.md ../docker-advanced/manual.md ../docker-advanced/compose.md \ ../docker-advanced/what.md ../docker-advanced/setup.md ../docker-advanced/manual.md ../docker-advanced/compose.md \
../docker-advanced/security.md \ ../docker-advanced/security.md \
rendu.md rendu.md

View file

@ -6,7 +6,7 @@ institute: EPITA
date: Jeudi 16 septembre 2021 date: Jeudi 16 septembre 2021
abstract: | abstract: |
Durant ce premier TP, nous allons apprendre à utiliser Docker, puis Durant ce premier TP, nous allons apprendre à utiliser Docker, puis
nous apprendrons à déployer un groupe de conteneurs ! nous apprendrons à déployer un groupe de conteneurs !
\vspace{1em} \vspace{1em}

View file

@ -3,7 +3,7 @@
Rendu Rendu
===== =====
Est attendu d'ici le TP suivant : Est attendu d'ici le TP suivant :
- le rendu des exercice de ce TP ; - le rendu des exercice de ce TP ;
- vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/12). - vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/12).
@ -41,7 +41,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à
placer dans une tarball (pas d'archive ZIP, RAR, ...). placer dans une tarball (pas d'archive ZIP, RAR, ...).
Voici une arborescence type (vous pourriez avoir des fichiers Voici une arborescence type (vous pourriez avoir des fichiers
supplémentaires) : supplémentaires) :
<div lang="en-US"> <div lang="en-US">
``` ```

View file

@ -7,7 +7,7 @@ date: Jeudi 23 septembre 2021
abstract: | abstract: |
Durant ce deuxième TP, nous allons voir comment créer nos propres Durant ce deuxième TP, nous allons voir comment créer nos propres
images, et comment s'assurer qu'elles n'ont pas de vulnérabilités images, et comment s'assurer qu'elles n'ont pas de vulnérabilités
connues ! connues !
\vspace{1em} \vspace{1em}

View file

@ -35,7 +35,7 @@ On trouve par exemple :
Pour émettre un ping, il est nécessaire d'envoyer des paquets ICMP. À la 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'est pas forcément différence des datagrammes UDP ou des segments TCP, il n'est pas forcément
simple d'envoyer des paquets ICMP lorsque l'on est simple utilisateur, car simple d'envoyer des paquets ICMP lorsque l'on est simple utilisateur, car
l'usage du protocole ICMP dans une socket est restreint : il faut soit être l'usage du protocole ICMP dans une soket est restreint : il faut soit être
super-utilisateur, soit que le noyau ait été configuré pour autoriser certains super-utilisateur, soit que le noyau ait été configuré pour autoriser certains
utilisateurs à envoyer des `ECHO_REQUEST`. utilisateurs à envoyer des `ECHO_REQUEST`.
@ -64,7 +64,7 @@ se mettent à fournir par défaut une configuration qui permette de se passer de
*capabilities* pour lancer `ping`.\ *capabilities* pour lancer `ping`.\
Si vous vous rendez compte que votre binaire `ping` est dans ce cas, testez Si vous vous rendez compte que votre binaire `ping` est dans ce cas, testez
depuis un conteneur, par exemple : depuis un conteneur, par exemple :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -83,7 +83,7 @@ depuis un conteneur, par exemple :
</div> </div>
Dans le conteneur le binaire `ping` est *setuid root*, vous pouvez faire des Dans le conteneur le binaire `ping` est *setuid root*, vous pouvez faire des
tests en retirant le *setuid* : tests en retirant le *setuid* :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -94,7 +94,7 @@ tests en retirant le *setuid* :
``` ```
</div> </div>
Puis en ajoutant la *capability* : Puis en ajoutant la *capability* :
<div lang="en-US"> <div lang="en-US">
``` ```

View file

@ -1,12 +1,12 @@
### Exercice (obligatoire pour les SRS -- optionnel pour les GISTRE) ### Exercice (obligatoire pour les SRS -- optionnel pour les GISTRE)
Poursuivons [notre script de monitoring](#script-monitoring) afin d'envoyer nos Poursuivons [notre script de monitoring](#script-monitoring) afin d'envoyer nos
résultats vers InfluxDB : nous l'appellerons `./telegraf.sh` résultats vers InfluxDB : nous l'appellerons `./telegraf.sh`.
#### Rappel d'InfluxDB\ #### Rappel d'InfluxDB\
Commençons par lancer le conteneur Docker d'InfluxDB (pour éviter de Commençons par lancer le conteneur Docker d'InfluxDB (pour éviter de
l'installer sur notre machine) : l'installer sur notre machine) :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -16,7 +16,7 @@ docker container run --name mytsdb -d -p 8086:8086 influxdb:1.8
Il nous faut ensuite créer une base de données pour y stocker nos Il nous faut ensuite créer une base de données pour y stocker nos
métriques. Voici comment on s'était débrouillé précédemment pour interagir avec métriques. Voici comment on s'était débrouillé précédemment pour interagir avec
InfluxDB : InfluxDB :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -33,7 +33,7 @@ Vérifiez que la base de données `metrics` a bien été créée.
#### Monitoring vers InfluxDB\ #### Monitoring vers InfluxDB\
Maintenant, envoyons nos données vers la base Maintenant, envoyons nos données vers la base
<https://docs.influxdata.com/influxdb/v1.8/guides/write_data/> : <https://docs.influxdata.com/influxdb/v1.8/guides/write_data/> :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -43,7 +43,7 @@ curl -i -XPOST 'http://localhost:8086/write?db=metrics' --data-binary \
</div> </div>
Pour vérifier que les données ont bien été ajoutées, nous pouvons effectuer la Pour vérifier que les données ont bien été ajoutées, nous pouvons effectuer la
requête suivante dans notre client `influx` : requête suivante dans notre client `influx` :
<div lang="en-US"> <div lang="en-US">
```sql ```sql
@ -54,15 +54,15 @@ 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 :
* Nombre d'IOs effectué ; * Nombre d'IOs effectué ;
* nombre d'octets lus/écrits sur les disques ; * nobre d'octets lus/écrits sur les disques ;
* temps de calcul utilisé (`userspace`, `system`, tout confondu) ; * temps de calcul utilisé (`userspace`, `system`, tout confondu) ;
* ... * ...
Tous les cgroups existants dans le dernier noyau publié ont leur documentation Tous les cgroups existants dans le dernier noyau publié ont leur documentation
accessible ici : accessible ici :
- v1 : <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/index.html> - v1 : <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/index.html>
- v2 : <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html> - v2 : <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>

View file

@ -4,40 +4,40 @@ Les *cgroup*s
------------- -------------
Les *cgroup*s (pour *Control Group*s) permettent de collecter des statistiques Les *cgroup*s (pour *Control Group*s) permettent de collecter des statistiques
sur des **groupes de processus** (voire même, des threads !) et de leur 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 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é limites d'utilisation de ressources ou d'altérer leur comportement : quantité
de RAM, temps CPU, bande passante, ... de RAM, temps CPU, bande passante, ...
Apparue dès [Linux Apparue dès [Linux
2.6.24](https://kernelnewbies.org/Linux_2_6_24#Task_Control_Groups) 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 (en 2008 !), les *cgroup*s sont répartis en différents sous-systèmes
(*subsystem*), chacun étant responsable d'un type de ressources (*subsystem*), chacun étant responsable d'un type de ressources
spécifique : spécifique :
- [`blkio` (`io` dans la v2) - [`blkio` (`io` dans la v2)
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/blkio-controller.html) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/blkio-controller.html)
limites et statistiques de bande passante sur les disques ; limites et statistiques de bande passante sur les disques ;
- `cpu` : cycles CPU minimum garantis ; - `cpu` : cycles CPU minimum garantis ;
- [`cpuacct` (inclus dans `cpu` dans la v2) - [`cpuacct` (inclus dans `cpu` dans la v2)
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpuacct.html) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpuacct.html)
statistiques du temps CPU utilisé ; statistiques du temps CPU utilisé ;
- [`cpuset` - [`cpuset`
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpusets.html) :](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 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 du CPU à un programme, qui ne pourra alors utiliser que ce CPU et pas les
autres) ; autres) ;
- [`devices` - [`devices`
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/devices.html) :](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 ; règles de contrôle de création (`mknod`) et d'accès aux périphériques ;
- [`freezer` - [`freezer`
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/freezer-subsystem.html) :](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 ; 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) ; - [`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* ; - [`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_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 ; - [`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 ; - [`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 Nous allons commencer par faire quelques tests avec le *cgroup* *freezer*, qui
@ -48,19 +48,19 @@ lorsqu'on le décide.
### Montage du *freezer* ### Montage du *freezer*
En fonction de la configuration de votre système, vous allez vous trouver dans En fonction de la configuration de votre système, vous allez vous trouver dans
l'une de ces trois situations : l'une de ces trois situations :
- Votre dossier `/sys/fs/cgroup` contient à la fois des fichiers `cgroup.*` et - Votre dossier `/sys/fs/cgroup` contient à la fois des fichiers `cgroup.*` et
éventuellement des dossiers : vous avez une distribution moderne qui utilise éventuellement des dossiers : vous avez une distribution moderne qui utilise
la nouvelle version des `cgroup`s. la nouvelle version des `cgroup`s.
- Votre dossier `/sys/fs/cgroup` contient d'autres dossiers au nom des - 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. 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 - Votre dossier `/sys/fs/cgroup` est vide ou inexistant, vous pouvez choisir
d'utiliser la version de votre choix : d'utiliser la version de votre choix :
Pour utiliser la v1 : Pour utiliser la v1 :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -70,7 +70,7 @@ l'une de ces trois situations :
</div> </div>
Pour utiliser la v2 : Pour utiliser la v2 :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -103,7 +103,7 @@ La première étape dans l'utilisation d'un *cgroup* est donc de créer un group
Pour ce faire, il suffit de créer un nouveau dossier dans un groupe existant, 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 : On commence par se rendre à la racine :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -112,7 +112,7 @@ cd /sys/fs/cgroup/ # v2
``` ```
</div> </div>
Puis on crée notre groupe : Puis on crée notre groupe :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -134,7 +134,7 @@ version, vous allez devoir activer le ou les contrôleurs dont vous avez besoin
sous-système que l'on voulait). sous-système que l'on voulait).
Pour activer le contrôleur *memory* dans notre groupe `virli`, nous utilisons Pour activer le contrôleur *memory* dans notre groupe `virli`, nous utilisons
la commande suivante : la commande suivante :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -163,9 +163,9 @@ le fichier `cgroup.procs` de notre groupe. Ce fichier contient la liste des
processus rattachés à notre *cgroup*. processus rattachés à notre *cgroup*.
Ouvrons un nouveau terminal (c'est lui que l'on va geler), et récupérons son Ouvrons un nouveau terminal (c'est lui que l'on va geler), et récupérons son
PID : `echo $$`. PID : `echo $$`.
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"> <div lang="en-US">
```bash ```bash
@ -190,7 +190,7 @@ adaptés.
En affichant le contenu du dossier `virli`, nous pouvions constater que En affichant le contenu du dossier `virli`, nous pouvions constater que
celui-ci contenait déjà un certain nombre de fichiers. Certains d'entre-eux 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 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. 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 Nous pouvons consulter l'état de gel du groupe en affichant le contenu du
fichier\ fichier\
@ -204,7 +204,7 @@ consultez
### Changement d'état ### Changement d'état
Faisons exécuter à notre interpréteur une commande pour voir effectivement Faisons exécuter à notre interpréteur une commande pour voir effectivement
l'exécution s'arrêter. Si vous manquez d'inspiration, utilisez : l'exécution s'arrêter. Si vous manquez d'inspiration, utilisez :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -213,7 +213,7 @@ for i in $(seq 9999); do echo -n $i; sleep .1; echo -n " - "; sleep .1; done
</div> </div>
Maintenant, nous avons donné l'ordre au noyau de ne plus allouer de temps de Maintenant, nous avons donné l'ordre au noyau de ne plus allouer de temps de
calcul à notre shell et ses fils : calcul à notre shell et ses fils :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -223,7 +223,7 @@ echo 1 > /sys/fs/cgroup/virli/cgroup.freeze # v2
</div> </div>
À cet instant, vous devriez voir votre compteur s'arrêter. Pour reprendre À cet instant, vous devriez voir votre compteur s'arrêter. Pour reprendre
l'exécution : l'exécution :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -233,7 +233,7 @@ echo 0 > /sys/fs/cgroup/virli/cgroup.freeze # v2
</div> </div>
### Exercice : script de monitoring {- #script-monitoring} ### Exercice : script de monitoring {- #script-monitoring}
À nous maintenant de concevoir un script qui va enregistrer vers une base de À nous maintenant de concevoir un script qui va enregistrer vers une base de
données des statistiques issues des *cgroup*s, tel `telegraf`. données des statistiques issues des *cgroup*s, tel `telegraf`.
@ -267,7 +267,7 @@ doit cependant être possible d'y trouver des statistiques intéressantes, dont
la quantité de mémoire utilisée. Ici nous affichons au début le PID du la quantité de mémoire utilisée. Ici nous affichons au début le PID du
processus, ce qui peut simplifier le débogage du script.\ processus, ce qui peut simplifier le débogage du script.\
Il s'utilise de la manière suivante : Il s'utilise de la manière suivante :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -275,7 +275,7 @@ Il s'utilise de la manière suivante :
``` ```
</div> </div>
:  :
- `group_name` correspond au nom du/des *cgroup*(s) à créer/rejoindre. - `group_name` correspond au nom du/des *cgroup*(s) à créer/rejoindre.
- `prog [args [...]]` est la commande que l'on souhaite monitorer, à exécuter - `prog [args [...]]` est la commande que l'on souhaite monitorer, à exécuter
@ -297,7 +297,7 @@ quantité de ressources mises à disposition à un groupe de processus.
Pour définir une limite, nous allons écrire la valeur dans le fichier Pour définir une limite, nous allons écrire la valeur dans le fichier
correspondant à une valeur limite, comme par exemple correspondant à une valeur limite, comme par exemple
`memory.max_usage_in_bytes`/`memory.max`, qui limite le nombre d'octets que `memory.max_usage_in_bytes`/`memory.max`, qui limite le nombre d'octets que
notre groupe de processus va pouvoir allouer au maximum : notre groupe de processus va pouvoir allouer au maximum :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -330,7 +330,7 @@ limiteurs, n'hésitez pas à consulter la documentation associée à chaque
*cgroup*. *cgroup*.
Mettez à jour votre script de monitoring pour prendre en compte les Mettez à jour votre script de monitoring pour prendre en compte les
limites que vous avez définies : limites que vous avez définies :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -352,5 +352,5 @@ limites que vous avez définies :
### 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 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 ! Plus [cet Control groups](https://lwn.net/Articles/604609/) est excellente ! Plus [cet
article sur la version 2](https://lwn.net/Articles/679786/). article sur la version 2](https://lwn.net/Articles/679786/).

View file

@ -1,4 +1,4 @@
L'isolation ... à 1  ? L'isolation ... à 1  ?
----------------------- -----------------------
Depuis les premières versions d'Unix, il est possible de changer le répertoire Depuis les premières versions d'Unix, il est possible de changer le répertoire
@ -83,7 +83,7 @@ pacstrap newroot/
</div> </div>
Dans les deux cas, nous nous retrouvons avec un dossier `newroot` contenant une Dans les deux cas, nous nous retrouvons avec un dossier `newroot` contenant une
distribution complète minimale, dans laquelle nous pouvons entrer : distribution complète minimale, dans laquelle nous pouvons entrer :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -100,9 +100,10 @@ sous forme de tarball :
#### Gentoo\ #### Gentoo\
<http://gentoo.mirrors.ovh.net/gentoo-distfiles/releases/amd64/autobuilds/current-stage3-amd64-openrc/stage3-amd64-openrc-20211128T170532Z.tar.xz>
<div lang="en-US"> <div lang="en-US">
```bash ```bash
wget http://gentoo.mirrors.ovh.net/gentoo-distfiles/releases/amd64/autobuilds/current-stage3-amd64/stage3-amd64-20210630T214504Z.tar.xz
tar xpf stage3-amd64-*.tar.xz -C newroot/ tar xpf stage3-amd64-*.tar.xz -C newroot/
``` ```
</div> </div>
@ -113,7 +114,7 @@ environnement qui tient dans 200 MB.
::::: :::::
Comme pour les autres distributions vues précédemment, nous pouvons entrer dans Comme pour les autres distributions vues précédemment, nous pouvons entrer dans
notre nouvelle racine comme ceci : notre nouvelle racine comme ceci :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -124,15 +125,16 @@ chroot newroot/ bash
#### Alpine\ #### Alpine\
<https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-minirootfs-3.14.2-x86_64.tar.gz>
<div lang="en-US"> <div lang="en-US">
```bash ```bash
wget https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-minirootfs-3.14.2-x86_64.tar.gz
tar xpf alpine-minirootfs-*.tar.xz -C newroot/ tar xpf alpine-minirootfs-*.tar.xz -C newroot/
``` ```
</div> </div>
Alpine se contentant de Busybox pour son système de base, nous n'avons pas Alpine se contentant de Busybox pour son système de base, nous n'avons pas
`bash`, mais on peut tout de même lancer `ash` : `bash`, mais on peut tout de même lancer `ash` :
<div lang="en-US"> <div lang="en-US">
```bash ```bash

View file

@ -8,5 +8,5 @@ allons tâcher d'apprendre comment il fonctionne en nous penchant sur un certain
nombre de fonctionnalités de Linux. nombre de fonctionnalités de Linux.
Dans un premier temps, nous allons aborder la manière dont le noyau Linux Dans un premier temps, nous allons aborder la manière dont le noyau Linux
permet de contrôler les processus : que ce soit en collectant des informations permet de contrôler les processus : que ce soit en collectant des informations
sur eux ou en imposant certaines restrictions. sur eux ou en imposant certaines restrictions.

View file

@ -3,7 +3,7 @@
Gestion de la mémoire Gestion de la mémoire
===================== =====================
Linux a une gestion de la mémoire bien particulière[^vm-overcommit] : par Linux a une gestion de la mémoire bien particulière[^vm-overcommit] : par
défaut, `malloc(3)` ne retournera jamais `NULL`. En se basant sur l'euristique défaut, `malloc(3)` ne retournera jamais `NULL`. En se basant sur l'euristique
qu'un bloc mémoire demandé ne sera pas utilisé directement et que de nombreux qu'un bloc mémoire demandé ne sera pas utilisé directement et que de nombreux
process ne feront pas un usage total des blocks qu'ils ont alloués, le noyau process ne feront pas un usage total des blocks qu'ils ont alloués, le noyau
@ -22,7 +22,7 @@ est-ce `init` qui est en train de gérer le lancement d'un nouveau daemon). On
dit alors que le noyau est *Out-Of-Memory*. dit alors que le noyau est *Out-Of-Memory*.
Pour se sortir d'une telle situation, et après avoir tenté de vider les caches, Pour se sortir d'une telle situation, et après avoir tenté de vider les caches,
il lance son arme ultime, pour retrouver au plus vite de la mémoire : il lance son arme ultime pour retrouver au plus vite de la mémoire :
l'*Out-Of-Memory killer*. l'*Out-Of-Memory killer*.
@ -39,7 +39,7 @@ jusqu'à ce que le système retrouve sa sérénité.
[^oom-algo]: <https://linux-mm.org/OOM_Killer> [^oom-algo]: <https://linux-mm.org/OOM_Killer>
## Esquiver l'OOM killer ? ## Esquiver l'OOM killer ?
Au sein d'un *cgroup* *memory*, les fichiers `memory.oom_control` (v1) ou Au sein d'un *cgroup* *memory*, les fichiers `memory.oom_control` (v1) ou
`memory.events` (v2) peuvent être utilisé afin de recevoir une notification du `memory.events` (v2) peuvent être utilisé afin de recevoir une notification du
@ -58,4 +58,4 @@ ce sujet.
Continuons l'exercice précédent où nous avions [fixé les Continuons l'exercice précédent où nous avions [fixé les
limites](#Fixer-des-limites) de mémoire que pouvez réserver les processus de limites](#Fixer-des-limites) de mémoire que pouvez réserver les processus de
notre groupe. Que se passe-t-il alors si `memhog` dépasse la quantité de notre groupe. Que se passe-t-il alors si `memhog` dépasse la quantité de
mémoire autorisée dans le `cgroup` ? mémoire autorisée dans le `cgroup` ?

View file

@ -1 +0,0 @@
../../subject/2/project-part1.md

115
tutorial/3/project-body.md Normal file
View file

@ -0,0 +1,115 @@
## Palier 1 : Restreindre l'environnement (2 points) {-}
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 utiliser 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 ;
* 100 PIDs ;
* ...
En bonus, vous pouvez gérer les cas où le noyau sur lequel s'exécute votre
moulinette ne possède pas tous ces *CGroup*s, au lieu de planter, ne rien faire
n'est pas forcément une mauvaise solution.
## Palier 2 : Réduire les `capabilities` (2 points) {-}
Réduisez au maximum les *capabilities*, de telle sorte qu'il ne soit pas
possible de faire un ping dans l'environnement restreint :
<div lang="en-US">
```
42sh# ping 9.9.9.9
PING 9.9.9.9 (9.9.9.9) 56(84) bytes of data.
64 bytes from 9.9.9.9: icmp_seq=1 ttl=56 time=3.93 ms
64 bytes from 9.9.9.9: icmp_seq=2 ttl=56 time=3.97 ms
^C
--- 9.9.9.9 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
c7d68d1cb4737125a84cd69f55add202
bash# ping 9.9.9.9
ping: icmp open socket: Permission denied
```
</div>
**Astuces\ :** `prctl(2)`, `capabilities(7)`, `capget(2)`, `capset(2)`, ...
Aidez-vous du visualisateur de *capabilities* de la partie 1.3 du TP, pour voir
si vous êtes sur la bonne voie.
Si votre distribution vous permet d'utiliser `ping` sans privilège, utilisez à
la place n'importe quel binaire ayant besoin de *capabilities* pour vos tests,
par exemple `arping` (qui nécessite `CAP_NET_RAW`) ou `halt` (qui nécessite
`CAP_SYS_BOOT`) :
<div lang="en-US">
```
42sh# ./mymoulette /bin/bash
bash# arping 192.168.0.1
arping: socket: Permission denied
bash# halt -f
halt: (null): Operation not permitted
```
</div>
## Palier bonus : Utilisable par un utilisateur (2 points) {-}
Jouez avec les attributs étendus pour qu'un utilisateur non-privilégié puisse
exécuter votre moulinette. Ajoutez la/les commande(s) à votre `Makefile` ou
script d'installation.
## Création d'un environnement d'exécution minimal {-}
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 mettez pas cet environnement dans votre tarball de rendu, il vous
sera seulement utile pour faire des tests.**
## Palier 3 : Isolation du pauvre (1 point) {-}
Nous n'avons pas encore vu de meilleure méthode pour mieux isoler
l'environnement que de faire un `chroot`, ajoutez à votre programme cette
isolation rudimentaire. Et rendez-vous au prochain cours pour avoir une
meilleure isolation !
<div lang="en-US">
```
42sh$ which firefox
/usr/bin/firefox
42sh# ./mymoulette ./newrootfs/ /bin/bash
bash# which firefox
which: no firefox in (/usr/bin:/usr/local/bin:/bin:/opt/bin)
```
</div>
## Palier 4 : seccomp (2 points) {-}
Filtrez les appels système de telle sorte qu'aucun programme exécuté dans
votre bac à sable ne puisse plus lancer les appels systèmes suivants :
* `nfsservctl(2)` ;
* `personality(2)` ;
* `pivot_root(2)` ;
* ...
N'hésitez pas à en utiliser d'autres pour vos tests ;)
**Astuces\ :** `seccomp(2)`, `seccomp_init(3)`, `seccomp_load(3)`, ...

View file

@ -6,7 +6,7 @@ Projet et rendu
## Sujet ## Sujet
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 !
Cette semaine, il faudra faire en sorte de restreindre un groupe de processus Cette semaine, il faudra faire en sorte de restreindre un groupe de processus
pour qu'il ne puisse pas faire de déni de service sur notre machine. pour qu'il ne puisse pas faire de déni de service sur notre machine.
@ -14,11 +14,11 @@ pour qu'il ne puisse pas faire de déni de service sur notre machine.
Il n'y a pas de restriction sur le langage utilisé, vous pouvez tout aussi bien Il n'y a pas de restriction sur le langage utilisé, vous pouvez tout aussi bien
utiliser du C, du C++, du Python, etc. utiliser du C, du C++, du Python, etc.
L'usage de bibliothèques **non relatives** au projet est autorisé : le but de L'usage de bibliothèques **non relatives** au projet est autorisé : le but de
ce sujet est d'évaluer votre compréhension et votre utilisation de la ce sujet est d'évaluer votre compréhension et votre utilisation de la
tuyauterie bas-niveau du noyau liée à la virtualisation légère. À partir du tuyauterie bas-niveau du noyau liée à la virtualisation légère. À partir du
moment où vous n'utilisez pas une bibliothèque qui abstrait complètement cette moment où vous n'utilisez pas une bibliothèque qui abstrait complètement cette
plomberie, n'hésitez pas à l'utiliser ! plomberie, n'hésitez pas à l'utiliser !
Gardez en tête que ce projet sera à continuer au prochain TP, où il sera Gardez en tête que ce projet sera à continuer au prochain TP, où il sera
principalement question de faire des appels systèmes. principalement question de faire des appels systèmes.

View file

@ -3,7 +3,7 @@
Rendu Rendu
===== =====
Est attendu d'ici le TP suivant : Est attendu d'ici le TP suivant :
- le rendu des exercice de ce TP ; - le rendu des exercice de ce TP ;
- vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/14). - vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/14).
@ -40,7 +40,7 @@ placer dans une tarball (pas d'archive ZIP, RAR, ...).
Voici une arborescence type (adaptez les extensions et les éventuels Voici une arborescence type (adaptez les extensions et les éventuels
fichiers supplémentaires associés au langage que vous aurez choisi fichiers supplémentaires associés au langage que vous aurez choisi
pour chaque exercice) : pour chaque exercice) :
<div lang="en-US"> <div lang="en-US">
``` ```

View file

@ -41,13 +41,13 @@ apporter des modifications.
Linux emploie de nombreux systèmes de fichiers virtuels : Linux emploie de nombreux systèmes de fichiers virtuels :
- `/proc` : contient, principalement, la liste des processus (`top` et ses - `/proc` : contient, principalement, la liste des processus (`top` et ses
dérivés se contentent de lire les fichiers de ce point de montage) ; dérivés se contentent de lire les fichiers de ce point de montage) ;
- `/proc/sys` : contient la configuration du noyau ; - `/proc/sys` : contient la configuration du noyau ;
- `/sys` : contient des informations à propos du matériel (utilisées notamment - `/sys` : contient des informations à propos du matériel (utilisées notamment
par `udev` pour peupler `/dev`) et des périphériques (taille des tampons, par `udev` pour peupler `/dev`) et des périphériques (taille des tampons,
clignottement des DELs, ...) ; clignottement des DELs, ...) ;
- `/sys/firmware/efi/efivars` : pour accéder et modifier les variables de - `/sys/firmware/efi/efivars` : pour accéder et modifier les variables de
l'UEFI ; l'UEFI ;
- ... - ...
Tous ces systèmes de fichiers sont généralement exclusivement stockés en Tous ces systèmes de fichiers sont généralement exclusivement stockés en
@ -130,7 +130,7 @@ uts:[4026531838]
Explorons le pseudo système de fichiers `/sys` pour écrire un script Explorons le pseudo système de fichiers `/sys` pour écrire un script
qui va, en fonction de ce que vous avez de disponible : qui va, en fonction de ce que vous avez de disponible :
* afficher des statistiques sur notre batterie ; * afficher des statistiques sur notre batterie ;
* afficher des statistiques la fréquence du CPU. * afficher des statistiques la fréquence du CPU.
##### `batinfo.sh`\ ##### `batinfo.sh`\
@ -194,7 +194,7 @@ Maintenant que vous savez lire des informations dans `/sys`, tentons d'aller
modifier le comportement de notre système. Au choix, réalisez l'un des scripts modifier le comportement de notre système. Au choix, réalisez l'un des scripts
suivants, en fonction du matériel dont vous disposez : suivants, en fonction du matériel dont vous disposez :
* inverser l'état des diodes de notre clavier ; * inverser l'état des diodes de notre clavier ;
* mettre en veille votre machine, en ayant programmé une heure de réveil. * mettre en veille votre machine, en ayant programmé une heure de réveil.
##### `rev_kdb_leds.sh`\ ##### `rev_kdb_leds.sh`\
@ -203,7 +203,7 @@ Si vous avez :
* numlock On, * numlock On,
* capslock Off, * capslock Off,
* scrolllock Off ; * scrolllock Off ;
Après avoir exécuté le script, nous devrions avoir : Après avoir exécuté le script, nous devrions avoir :
@ -242,7 +242,8 @@ Voici un exemple d'utilisation :
</div> </div>
Vous aurez besoin de définir une alarme au niveau de votre RTC, via le Vous aurez besoin de définir une alarme au niveau de votre RTC, via le
fichier : `/sys/class/rtc/rtcX/wakealarm`. fichier :\
`/sys/class/rtc/rtcX/wakealarm`
::::: {.warning} ::::: {.warning}
Attention au fuseau horaire utilisé par votre RTC, si votre système principal Attention au fuseau horaire utilisé par votre RTC, si votre système principal

View file

@ -12,13 +12,13 @@ particulier peut être renvoyé au programme.
Depuis la version 3.17 du noyau, l'appel système `seccomp(2)` permet de faire Depuis la version 3.17 du noyau, l'appel système `seccomp(2)` permet de faire
entrer le processus courant dans ce mode. En effet, c'est le processus lui-même entrer le processus courant dans ce mode. En effet, c'est le processus lui-même
qui déclare au noyau qu'il peut désormais se contenter d'une liste réduite qui déclare au noyau qu'il peut désormais se contenter d'une liste réduite
d'appels système ; à l'inverse des politiques de sécurité comme SELinux ou d'appels système ; à l'inverse des politiques de sécurité comme SELinux ou
AppArmor, qui encapsulent les programmes pour toute la durée de leur exécution. AppArmor, qui encapsulent les programmes pour toute la durée de leur exécution.
*Seccomp* est particulièrement utile lorsqu'un processus a terminé son *Seccomp* est particulièrement utile lorsqu'un processus a terminé son
initialisation (ne dépendant en général pas de données sujettes à initialisation (ne dépendant en général pas de données sujettes à
l'exploitation de vulnérabilité) et doit commencer à entrer dans des portions l'exploitation de vulnérabilité) et doit commencer à entrer dans des portions
de code promptes aux vulnérabilités : c'est notamment le cas des moteurs de de code promptes aux vulnérabilités : c'est notamment le cas des moteurs de
rendus des navigateurs Firefox et Chrome. rendus des navigateurs Firefox et Chrome.
@ -39,7 +39,7 @@ des appels système `read(2)`, `write(2)` (sur les descripteurs de fichier déj
ouvert), `_exit(2)` et `sigreturn(2)`. ouvert), `_exit(2)` et `sigreturn(2)`.
Historiquement, avant la création de l'appel système `seccomp(2)`, on activait Historiquement, avant la création de l'appel système `seccomp(2)`, on activait
ce mode via : ce mode via :
<div lang="en-US"> <div lang="en-US">
```c ```c
@ -63,7 +63,7 @@ auquel est appliqué un filtre `seccomp`, héritent également de ce filtre.
La construction de ce filtre est faite de manière programmatique, via La construction de ce filtre est faite de manière programmatique, via
des règles BPF (`Berkeley Packet Filter`). On passe ensuite ce filtre BPF en des règles BPF (`Berkeley Packet Filter`). On passe ensuite ce filtre BPF en
argument de l'appel système : argument de l'appel système :
<div lang="en-US"> <div lang="en-US">
```c ```c
@ -79,7 +79,7 @@ seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
### Exercice {-} ### Exercice {-}
Écrivez un programme filtrant un appel système, à l'aide de `seccomp` : Écrivez un programme filtrant un appel système, à l'aide de `seccomp` :
<div lang="en-US"> <div lang="en-US">
``` ```

View file

@ -1,6 +1,6 @@
\newpage \newpage
### Exercice : comparaison de *namespace* -- `cmpns.sh` ### Exercice : comparaison de *namespace* -- `cmpns.sh`
Les *namespaces* d'un programme sont exposés sous forme de liens symboliques Les *namespaces* d'un programme sont exposés sous forme de liens symboliques
dans le répertoire `/proc/<PID>/ns/`. dans le répertoire `/proc/<PID>/ns/`.
@ -46,9 +46,9 @@ que l'on cherche à comparer.
Ici, `self` fait référence au processus actuellement exécuté (comme il existe Ici, `self` fait référence au processus actuellement exécuté (comme il existe
un dossier `/proc/self/`, vous n'avez pas besoin de gérer de cas particulier un dossier `/proc/self/`, vous n'avez pas besoin de gérer de cas particulier
pour ça !). pour ça !).
Et pourquoi pas : Et pourquoi pas :
<div lang="en-US"> <div lang="en-US">
``` ```

View file

@ -1,19 +1,19 @@
\newpage \newpage
Exercice : `docker exec` Exercice : `docker exec`
------------------------ ------------------------
Après voir lu la partie concernant les *namespaces*, vous avez dû comprendre Après voir lu la partie concernant les *namespaces*, vous avez dû comprendre
qu'un `docker exec`, n'était donc rien de plus qu'un `nsenter(1)`. qu'un `docker exec`, n'était donc rien de plus qu'un `nsenter(1)`.
Réécrivons, en quelques lignes, la commande `docker exec` ! Réécrivons, en quelques lignes, la commande `docker exec` !
Pour savoir si vous avez réussi, comparez les sorties des commandes : Pour savoir si vous avez réussi, comparez les sorties des commandes :
- `ip address` ; - `ip address` ;
- `hostname` ; - `hostname` ;
- `mount` ; - `mount` ;
- `pa -aux` ; - `ps -aux` ;
- ... - ...
@ -27,11 +27,11 @@ d63ceae863956f8312aca60b7a57fbcc1fdf679ae4c90c5d9455405005d4980a
234269 234269
42sh# ./mydocker_exec mywebserver ip address 42sh# ./mydocker_exec mywebserver ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group def
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever valid_lft forever preferred_lft forever
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP group def
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.1/16 scope global eth0 inet 172.17.0.1/16 scope global eth0
valid_lft forever preferred_lft forever valid_lft forever preferred_lft forever

View file

@ -33,7 +33,7 @@ En fonction des options qui lui sont passées, `unshare(1)` va créer le/les
nouveaux *namespaces* et placer le processus dedans. nouveaux *namespaces* et placer le processus dedans.
Par exemple, nous pouvons modifier sans crainte le nom de notre machine, si Par exemple, nous pouvons modifier sans crainte le nom de notre machine, si
nous sommes passés dans un autre *namespace* `UTS` : nous sommes passés dans un autre *namespace* `UTS` :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -64,7 +64,7 @@ Ce *syscall*, propre à Linux, crée habituellement un nouveau processus (mais
aussi des threads) enfant de notre processus courant, comme `fork(2)` (qui lui aussi des threads) enfant de notre processus courant, comme `fork(2)` (qui lui
est un appel système POSIX) mais prend en plus de nombreux est un appel système POSIX) mais prend en plus de nombreux
paramètres. L'isolement ou non du processus se fait en fonction des *flags* qui paramètres. L'isolement ou non du processus se fait en fonction des *flags* qui
sont passés : sont passés :
* `CLONE_NEWNS`, * `CLONE_NEWNS`,
* `CLONE_NEWUTS`, * `CLONE_NEWUTS`,
@ -83,7 +83,7 @@ que nous verrons plus tard.
Pour créer un nouveau processus qui sera à la fois dans un nouvel espace de Pour créer un nouveau processus qui sera à la fois dans un nouvel espace de
noms réseau et dans un nouveau *namespace* `cgroup`, on écrirait un code C noms réseau et dans un nouveau *namespace* `cgroup`, on écrirait un code C
semblable à : semblable à :
<div lang="en-US"> <div lang="en-US">
```c ```c
@ -118,7 +118,7 @@ dans un nouvel espace de noms. Dans ce cas, on utilisera l'appel système
::::: {.warning} ::::: {.warning}
Le comportement de `unshare(2)` (ou `unshare(3)`) avec les *namespace*s *PID* Le comportement de `unshare(2)` (ou `unshare(3)`) avec les *namespace*s *PID*
et *Time* n'est pas celui que l'on peut attendre ! et *Time* n'est pas celui que l'on peut attendre !
En effet, après avoir appelé `unshare`, le processus reste tout de même dans En effet, après avoir appelé `unshare`, le processus reste tout de même dans
son *namespace* *Time* ou *PID* d'origine, seuls ses enfants (après un appel à son *namespace* *Time* ou *PID* d'origine, seuls ses enfants (après un appel à

View file

@ -22,12 +22,12 @@ Les espaces de noms du noyau, que l'on appelle *namespaces*, permettent de
dupliquer certaines structures, habituellement considérées uniques pour le dupliquer certaines structures, habituellement considérées uniques pour le
noyau, dans le but de les isoler d'un groupe de processus à un autre. noyau, dans le but de les isoler d'un groupe de processus à un autre.
On en dénombre huit (le dernier ayant été ajouté dans Linux 5.6) : `cgroup`, On en dénombre huit (le dernier ayant été ajouté dans Linux 5.6) : `cgroup`,
`IPC`, `network`, `mount`, `PID`, `time`, `user` et `UTS`. `IPC`, `network`, `mount`, `PID`, `time`, `user` et `UTS`.
La notion d'espace de noms est relativement nouvelle et a été intégrée La notion d'espace de noms est relativement nouvelle et a été intégrée
progressivement au sein du noyau Linux. Aussi, toutes les structures ne sont progressivement au sein du noyau Linux. Aussi, toutes les structures ne sont
pas encore *containerisables* : le document fondateur[^NSDOC] parle ainsi pas encore *containerisables* : le document fondateur[^NSDOC] parle ainsi
d'isoler les journaux d'événements ou encore les modules de sécurité (LSM, tels d'isoler les journaux d'événements ou encore les modules de sécurité (LSM, tels
que AppArmor, SELinux, Yama, ...). que AppArmor, SELinux, Yama, ...).
@ -74,12 +74,12 @@ Cet espace de noms isole la liste des processus et virtualise leurs numéros.
Une fois dans un espace, le processus ne voit que le sous-arbre de processus Une fois dans un espace, le processus ne voit que le sous-arbre de processus
également attachés à son espace. Il s'agit d'un sous-ensemble de l'arbre global également attachés à son espace. Il s'agit d'un sous-ensemble de l'arbre global
de PID : les processus de tous les PID *namespaces* apparaissent donc dans de PID : les processus de tous les PID *namespaces* apparaissent donc dans
l'arbre initial. l'arbre initial.
Pour chaque nouvel espace de noms de processus, une nouvelle numérotation est Pour chaque nouvel espace de noms de processus, une nouvelle numérotation est
initiée. Ainsi, le premier processus de cet espace porte le numéro 1 et aura initiée. Ainsi, le premier processus de cet espace porte le numéro 1 et aura
les mêmes propriétés que le processus `init` usuel\ ; entre autres, si un les mêmes propriétés que le processus `init` usuel\ ; entre autres, si un
processus est rendu orphelin dans ce *namespace*, il devient un fils de ce processus est rendu orphelin dans ce *namespace*, il devient un fils de ce
processus, et non un fils de l'`init` de l'arbre global. processus, et non un fils de l'`init` de l'arbre global.
@ -89,7 +89,7 @@ processus, et non un fils de l'`init` de l'arbre global.
Depuis Linux 2.6.29. Depuis Linux 2.6.29.
Cet espace de noms fournit une isolation pour toutes les ressources associées Cet espace de noms fournit une isolation pour toutes les ressources associées
aux réseaux : les interfaces, les piles protocolaires IPv4 et IPv6, les tables aux réseaux : les interfaces, les piles protocolaires IPv4 et IPv6, les tables
de routage, règles pare-feu, ports numérotés, etc. de routage, règles pare-feu, ports numérotés, etc.
Une interface réseau (`eth0`, `wlan0`, ...) ne peut se trouver que dans un seul Une interface réseau (`eth0`, `wlan0`, ...) ne peut se trouver que dans un seul
@ -126,7 +126,7 @@ correspond en fait à un sous-groupe de l'arborescence globale.
Ainsi, un processus dans un *CGroup* *namespace* ne peut pas voir le contenu Ainsi, un processus dans un *CGroup* *namespace* ne peut pas voir le contenu
des sous-groupes parents (pouvant laisser fuiter des informations sur le reste des sous-groupes parents (pouvant laisser fuiter des informations sur le reste
du système). Cela peut également permettre de faciliter la migration de du système). Cela peut également permettre de faciliter la migration de
processus (d'un système à un autre) : l'arborescence des *cgroups* n'a alors processus (d'un système à un autre) : l'arborescence des *cgroups* n'a alors
plus d'importance car le processus ne voit que son groupe. plus d'importance car le processus ne voit que son groupe.

View file

@ -11,7 +11,7 @@ de processus qui l'utilisent. C'est-à-dire que, la plupart du temps, le
termine. termine.
Lorsque l'on a besoin de référencer un *namespace* (par exemple pour le faire Lorsque l'on a besoin de référencer un *namespace* (par exemple pour le faire
persister après le dernier processus), on peut utiliser un `mount bind` : persister après le dernier processus), on peut utiliser un `mount bind` :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -29,7 +29,7 @@ obtenir un descripteur de fichier valide vers le *namespace* (pour passer à
::::: {.question} ::::: {.question}
#### Faire persister un *namespace* ? {-} #### Faire persister un *namespace* ? {-}
\ \
Il n'est pas possible de faire persister un espace de noms d'un reboot à Il n'est pas possible de faire persister un espace de noms d'un reboot à

View file

@ -6,7 +6,7 @@ Le *namespace* `mount`
L'espace de noms `mount` permet d'isoler la vision du système de fichiers L'espace de noms `mount` permet d'isoler la vision du système de fichiers
qu'ont un processus et ses fils. qu'ont un processus et ses fils.
Peut-être que l'on peut trouver avec ça, un moyen de faire un `chroot` plus sûr ? Peut-être que l'on peut trouver avec ça, un moyen de faire un `chroot` plus sûr ?
::::: {.warning} ::::: {.warning}
Attention il convient de prendre garde aux types de liaison existant entre vos Attention il convient de prendre garde aux types de liaison existant entre vos
@ -33,7 +33,7 @@ Nous allons essayer de changer la racine de notre système de fichier. À la
différence d'un `chroot(2)`, changer de racine est quelque chose d'un peu plus différence d'un `chroot(2)`, changer de racine est quelque chose d'un peu plus
sportif car il s'agit de ne plus avoir aucune trace de l'ancienne racine. Au sportif car il s'agit de ne plus avoir aucune trace de l'ancienne racine. Au
moins ici, il ne sera certainement pas possible de revenir en arrière dans moins ici, il ne sera certainement pas possible de revenir en arrière dans
l'arborescence\ ! l'arborescence !
Pour l'instant, votre système utilise sans doute la partition d'un disque Pour l'instant, votre système utilise sans doute la partition d'un disque
physique comme racine de son système de fichier. Le changement de racine, va physique comme racine de son système de fichier. Le changement de racine, va
@ -52,7 +52,7 @@ la racine d'un point de montage, comme l'explique `pivot_root(2)`. En effet, il
serait encore possible hypothétiquement de remonter dans l'arborescence si l'on serait encore possible hypothétiquement de remonter dans l'arborescence si l'on
ne se trouvait pas à la racine d'une partition au moment du basculement. ne se trouvait pas à la racine d'une partition au moment du basculement.
Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs` : Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs` :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -61,32 +61,31 @@ Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs`
``` ```
</div> </div>
Placez ensuite dans cette nouvelle racine le système de votre choix (cf. le TP Placez ensuite dans cette nouvelle racine le système de votre choix.
précédent pour les différentes méthodes et liens).
### Exercice : Changer de racine -- `myswitch_root.sh` ### Exercice : Changer de racine -- `myswitch_root.sh`
Voici les grandes étapes du changement de racine : Voici les grandes étapes du changement de racine :
1. S'isoler dans les *namespaces* adéquats ; 1. S'isoler dans les *namespaces* adéquats ;
2. Démonter ou déplacer toutes les partitions de l'ancienne racine vers la 2. Démonter ou déplacer toutes les partitions de l'ancienne racine vers la
nouvelle racine ; nouvelle racine ;
3. `pivot_root` ! 3. `pivot_root` !
#### S'isoler\ #### S'isoler\
Notre but étant de démonter toutes les partitions superflues, nous allons Notre but étant de démonter toutes les partitions superflues, nous allons
devoir nous isoler sur : devoir nous isoler sur :
* les points de montages, ça semble évident ; * les points de montages, ça semble évident ;
* les PIDs : car on ne pourra pas démonter une partition en cours * les PIDs : car on ne pourra pas démonter une partition en cours
d'utilisation. S'il n'y a pas de processus, il n'y a personne pour nous d'utilisation. S'il n'y a pas de processus, il n'y a personne pour nous
empêcher de démonter une partition ! empêcher de démonter une partition !
* les autres *namespaces* ne sont pas forcément nécessaires. * les autres *namespaces* ne sont pas forcément nécessaires.
Isolons-nous : Isolons-nous :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -97,12 +96,12 @@ Isolons-nous :
#### Dissocier la propagation des démontages\ #### Dissocier la propagation des démontages\
Attention ! avant de pouvoir commencer à démonter les partitions, il faut Attention ! avant de pouvoir commencer à démonter les partitions, il faut
s'assurer que les démontages ne se propagent pas via une politique de *shared s'assurer que les démontages ne se propagent pas via une politique de *shared
mount*. mount*.
Commençons donc par étiqueter tous nos points de montage (de ce *namespace*), Commençons donc par étiqueter tous nos points de montage (de ce *namespace*),
comme esclaves : comme esclaves :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -111,15 +110,15 @@ comme esclaves :
</div> </div>
#### Démonter tout !\ #### Démonter tout !\
À vous maintenant de démonter vos points d'attache. Il ne devrait vous rester À vous maintenant de démonter vos points d'attache. Il ne devrait vous rester
après cette étape que : `/`, `/dev`, `/sys`, `/proc`, `/run` et leurs fils. après cette étape que : `/`, `/dev`, `/sys`, `/proc`, `/run` et leurs fils.
#### Switch !\ #### Switch !\
À ce stade, dans votre console, vous avez plusieurs solutions : utiliser À ce stade, dans votre console, vous avez plusieurs solutions : utiliser
`switch_root(8)` ou `pivot_root(8)`. La première abstrait plus de choses que la `switch_root(8)` ou `pivot_root(8)`. La première abstrait plus de choses que la
seconde. seconde.
@ -136,7 +135,7 @@ Cette commande, plus proche du fonctionnement de l'appel système
`pivot_root(2)`, requiert de notre part que nous ayons préalablement déplacé `pivot_root(2)`, requiert de notre part que nous ayons préalablement déplacé
les partitions systèmes à leur place dans la nouvelle racine. les partitions systèmes à leur place dans la nouvelle racine.
L'appel de la commande sert à intervertir les deux racines ; elle prend en argument : L'appel de la commande sert à intervertir les deux racines ; elle prend en argument :
* le chemin de la nouvelle racine, * le chemin de la nouvelle racine,
* le chemin dans la nouvelle racine où placer l'ancienne. * le chemin dans la nouvelle racine où placer l'ancienne.
@ -144,7 +143,7 @@ L'appel de la commande sert à intervertir les deux racines ; elle prend en argu
Une fois le pivot effectué, on peut démonter l'ancienne racine. Une fois le pivot effectué, on peut démonter l'ancienne racine.
Pour lancer la première commande dans la nouvelle racine, on passe généralement Pour lancer la première commande dans la nouvelle racine, on passe généralement
par : par :
<div lang="en-US"> <div lang="en-US">
```bash ```bash

View file

@ -4,7 +4,7 @@ Je vous recommande la lecture du *man* `namespaces(7)` introduisant et
énumérant les *namespaces*. énumérant les *namespaces*.
Pour tout connaître en détails, [la série d'articles de Michael Kerrisk sur les Pour tout connaître en détails, [la série d'articles de Michael Kerrisk sur les
*namespaces*](https://lwn.net/Articles/531114/) est excellente ! Auquel il faut *namespaces*](https://lwn.net/Articles/531114/) est excellente ! Auquel il faut
ajouter [l'article sur le plus récent `cgroup` ajouter [l'article sur le plus récent `cgroup`
*namespace*](https://lwn.net/Articles/621006/) et [le petit dernier sur le *namespace*](https://lwn.net/Articles/621006/) et [le petit dernier sur le
*namespace* `time`](https://lwn.net/Articles/766089/). *namespace* `time`](https://lwn.net/Articles/766089/).

View file

@ -6,11 +6,11 @@ Le *namespace* `network` {#net-ns}
### Introduction ### Introduction
L'espace de noms `network`, comme son nom l'indique permet de virtualiser tout L'espace de noms `network`, comme son nom l'indique permet de virtualiser tout
ce qui est en lien avec le réseau : les interfaces, les ports, les routes, les ce qui est en lien avec le réseau : les interfaces, les ports, les routes, les
règles de filtrage, etc. règles de filtrage, etc.
En entrant dans un nouvel espace de noms `network`, on se retrouve dans un En entrant dans un nouvel espace de noms `network`, on se retrouve dans un
environnement qui n'a plus qu'une interface de *loopback* : environnement qui n'a plus qu'une interface de *loopback* :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -25,7 +25,7 @@ environnement principal, il s'agit bien de deux interfaces isolées l'une de
l'autre. l'autre.
Qui dit nouvelle pile réseau, dit également que les ports qui sont assignés Qui dit nouvelle pile réseau, dit également que les ports qui sont assignés
dans l'espace principal, ne le sont plus dans le conteneur : il est donc dans l'espace principal, ne le sont plus dans le conteneur : il est donc
possible de lancer un serveur web sans qu'il n'entre en conflit avec celui d'un possible de lancer un serveur web sans qu'il n'entre en conflit avec celui d'un
autre espace de noms. autre espace de noms.
@ -33,9 +33,9 @@ autre espace de noms.
### Premiers pas avec `ip netns` ### Premiers pas avec `ip netns`
La suite d'outils `iproute2` propose une interface simplifiée pour utiliser le La suite d'outils `iproute2` propose une interface simplifiée pour utiliser le
*namespace* `network` : `ip netns`. *namespace* `network` : `ip netns`.
Nous pouvons tout d'abord créer un nouvel espace de noms : Nous pouvons tout d'abord créer un nouvel espace de noms :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -45,17 +45,17 @@ Nous pouvons tout d'abord créer un nouvel espace de noms :
La technique utilisée ici pour avoir des *namespaces* nommés est la même que La technique utilisée ici pour avoir des *namespaces* nommés est la même que
celle que nous avons vue dans celle que nous avons vue dans
[la première partie sur les *namespaces*](#ns-lifetime) : via un `mount --bind` [la première partie sur les *namespaces*](#ns-lifetime) : via un `mount --bind`
dans le dossier `/var/run/netns/`. Cela permet de faire persister le namespace dans le dossier `/var/run/netns/`. Cela permet de faire persister le namespace
malgré le fait que plus aucun processus ne s'y exécute. malgré le fait que plus aucun processus ne s'y exécute.
Maintenant que notre *namespace* est créé, nous pouvons regarder s'il contient Maintenant que notre *namespace* est créé, nous pouvons regarder s'il contient
des interfaces : des interfaces :
<div lang="en-US"> <div lang="en-US">
``` ```
42sh# ip netns exec virli ip link 42sh# ip netns exec virli ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1 1: lo: <LOOPBACK> mut 65536 qdisc noop state DOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
``` ```
</div> </div>
@ -64,7 +64,7 @@ Cette commande ne nous montre que l'interface de *loopback*, car nous n'avons
pour l'instant pas encore attaché la moindre interface. pour l'instant pas encore attaché la moindre interface.
D'ailleurs, cette interface est rapportée comme étant désactivée, activons-là D'ailleurs, cette interface est rapportée comme étant désactivée, activons-là
via la commande : via la commande :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -92,7 +92,7 @@ interface physique par conteneur, d'autant plus si l'on a plusieurs
centaines de conteneurs à gérer. centaines de conteneurs à gérer.
Une technique couramment employée consiste à créer une interface virtuelle de Une technique couramment employée consiste à créer une interface virtuelle de
type `veth` : type `veth` :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -100,16 +100,16 @@ type `veth` :
``` ```
</div> </div>
Une interface `veth` se comporte comme un tube bidirectionnel : tout ce qui Une interface `veth` se comporte comme un tube bidirectionnel : tout ce qui
entre d'un côté sort de l'autre et inversement. La commande précédente a donc entre d'un côté sort de l'autre et inversement. La commande précédente a donc
créé deux interfaces `veth0` et `veth1` : les paquets envoyés sur `veth0` sont créé deux interfaces `veth0` et `veth1` : les paquets envoyés sur `veth0` sont
donc reçus par `veth1` et les paquets envoyés à `veth1` sont reçus par `veth0`. donc reçus par `veth1` et les paquets envoyés à `veth1` sont reçus par `veth0`.
Dans cette configuration, ces deux interfaces ne sont pas très utiles, mais si Dans cette configuration, ces deux interfaces ne sont pas très utiles, mais si
l'on place l'une des deux extrémités dans un autre *namespace* `network`, il l'on place l'une des deux extrémités dans un autre *namespace* `network`, il
devient alors possible de réaliser un échange de paquets entre les deux. devient alors possible de réaliser un échange de paquets entre les deux.
Pour déplacer `veth1` dans notre *namespace* `virli` : Pour déplacer `veth1` dans notre *namespace* `virli` :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -117,7 +117,7 @@ Pour déplacer `veth1` dans notre *namespace* `virli` :
``` ```
</div> </div>
Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces : Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -126,7 +126,7 @@ Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces :
``` ```
</div> </div>
Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité : Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité :
[^linkdown]: Il peut être nécessaire d'activer chaque lien, via `ip link set [^linkdown]: Il peut être nécessaire d'activer chaque lien, via `ip link set
vethX up`. vethX up`.
@ -140,7 +140,7 @@ Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité :
</div> </div>
Il ne reste donc pas grand chose à faire pour fournir Internet à notre Il ne reste donc pas grand chose à faire pour fournir Internet à notre
conteneur : via un peu de NAT ou grâce à un pont Ethernet. conteneur : via un peu de NAT ou grâce à un pont Ethernet.
### Les autres types d'interfaces ### Les autres types d'interfaces
@ -171,9 +171,9 @@ derrière notre machine.
<!-- https://hicu.be/bridge-vs-macvlan --> <!-- https://hicu.be/bridge-vs-macvlan -->
Lorsque l'on n'a pas assez de carte ethernet et que le switch ne supporte pas Lorsque l'on n'a pas assez de carte ethernet et que le switch ne supporte pas
les VLAN, le noyau met à disposition un routage basé sur les adresses MAC : le les VLAN, le noyau met à disposition un routage basé sur les adresses MAC : le
MACVLAN. S'il est activé dans votre noyau, vous allez avoir le choix entre l'un MACVLAN. S'il est activé dans votre noyau, vous allez avoir le choix entre l'un
des quatre modes : *private*, VEPA, *bridge* ou *passthru*. des quatre modes : *private*, VEPA, *bridge* ou *passthru*.
Quel que soit le mode choisi, les paquets en provenance d'autres machines et à Quel que soit le mode choisi, les paquets en provenance d'autres machines et à
destination d'un MAC seront délivrés à l'interface possédant la MAC. Les destination d'un MAC seront délivrés à l'interface possédant la MAC. Les
@ -189,7 +189,7 @@ la machine, c'est à l'équipement réseau derrière la machine de rerouter le
paquet vers la machine émettrice (par exemple un switch paquet vers la machine émettrice (par exemple un switch
[802.1Qbg](http://www.ieee802.org/1/pages/802.1bg.html)). [802.1Qbg](http://www.ieee802.org/1/pages/802.1bg.html)).
Pour construire une nouvelle interface de ce type : Pour construire une nouvelle interface de ce type :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -217,11 +217,11 @@ conteneur de la même machine.
##### *Bridge* ##### *Bridge*
À l'inverse des modes *VEPA* et *private*, les paquets sont routés selon leur À l'inverse des modes *VEPA* et *private*, les paquets sont routés selon leur
adresse MAC : si jamais une adresse MAC est connue, le paquet est délivré à adresse MAC : si jamais une adresse MAC est connue, le paquet est délivré à
l'interface MACVLAN correspondante ; dans le cas contraire, le paquet est l'interface MACVLAN correspondante ; dans le cas contraire, le paquet est
envoyé sur l'interface de sortie. envoyé sur l'interface de sortie.
Pour construire une nouvelle interface de ce type : Pour construire une nouvelle interface de ce type :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -233,9 +233,9 @@ Pour construire une nouvelle interface de ce type :
### Aller plus loin {-} ### Aller plus loin {-}
Pour approfondir les différentes techniques de routage, je vous Pour approfondir les différentes techniques de routage, je vous
recommande cet article : recommande cet article :
[Linux Containers and Networking](https://blog.flameeyes.eu/2010/09/linux-containers-and-networking). [Linux Containers and Networking](https://blog.flameeyes.eu/2010/09/linux-containers-and-networking).
Appliqué à Docker, vous apprécierez cet article : [Understanding Docker Appliqué à Docker, vous apprécierez cet article : [Understanding Docker
Networking Drivers and their use Networking Drivers and their use
cases](https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/). cases](https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/).

View file

@ -18,9 +18,9 @@ pas de PID en cours de route, puisqu'il dépend du *namespace* dans lequel il se
trouve. trouve.
### Isolons ! ### Isolons !
Première étape s'isoler : Première étape s'isoler :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -45,9 +45,9 @@ notre système initial. Pour s'en sortir, il est nécessaire de s'isoler dans un
*namespace* `mount` séparé. *namespace* `mount` séparé.
#### Double isolation : ajout du *namespace* `mount`\ #### Double isolation : ajout du *namespace* `mount`\
Voici la nouvelle ligne de commande que l'on va utiliser : Voici la nouvelle ligne de commande que l'on va utiliser :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -65,11 +65,11 @@ Cette fois, `top` et `ps` nous rapportent bien que l'on est seul dans notre
### Arborescence à l'extérieur du *namespace* ### Arborescence à l'extérieur du *namespace*
Lors de notre première tentative de `top`, lorsque `/proc` était encore monté Lors de notre première tentative de `top`, lorsque `/proc` était encore monté
sur le `procfs` de l'espace de noms initial : notre processus (au PID 1 dans sur le `procfs` de l'espace de noms initial : notre processus (au PID 1 dans
son nouveau *namespace*) était présent dans l'arborescence de l'espace initial son nouveau *namespace*) était présent dans l'arborescence de l'espace initial
avec un PID dans la continuité des autres processus, étonnant ! avec un PID dans la continuité des autres processus, étonnant !
En fait, l'isolation consiste en une virtualisation des numéros du processus : En fait, l'isolation consiste en une virtualisation des numéros du processus :
la plupart des processus du système initial ne sont pas accessibles, et ceux qui la plupart des processus du système initial ne sont pas accessibles, et ceux qui
font partie de l'espace de noms créé disposent d'une nouvelle numérotation. Et font partie de l'espace de noms créé disposent d'une nouvelle numérotation. Et
c'est cette nouvelle numérotation qui est montrée au processus. c'est cette nouvelle numérotation qui est montrée au processus.
@ -85,12 +85,12 @@ Au sein d'un *namespace*, le processus au PID 1 est considéré comme le
programme `init`, les mêmes propriétés s'appliquent donc. programme `init`, les mêmes propriétés s'appliquent donc.
Si un processus est orphelin, il est donc affiché comme étant fils du PID 1 Si un processus est orphelin, il est donc affiché comme étant fils du PID 1
dans son *namespace*[^PR_SET_CHILD_SUBREAPER] ; il n'est pas sorti de l'espace dans son *namespace*[^PR_SET_CHILD_SUBREAPER] ; il n'est pas sorti de l'espace
de noms. de noms.
[^PR_SET_CHILD_SUBREAPER]: en réalité, ce comportement est lié à la propriété [^PR_SET_CHILD_SUBREAPER]: en réalité, ce comportement est lié à la propriété
`PR_SET_CHILD_SUBREAPER`, qui peut être définie pour n'importe quel processus `PR_SET_CHILD_SUBREAPER`, qui peut être définie pour n'importe quel processus
de l'arborescence. Le processus au PID 1 hérite forcément de cette propriété\ ; de l'arborescence. Le processus au PID 1 hérite forcément de cette propriété\ ;
il va donc récupérer tous les orphelins, si aucun de leurs parents n'ont la il va donc récupérer tous les orphelins, si aucun de leurs parents n'ont la
propriété définie. propriété définie.
@ -104,4 +104,4 @@ l'intérieur pour conserver un comportement cohérent.
### Aller plus loin {-} ### Aller plus loin {-}
N'hésitez pas à jeter un œil à la page de manuel consacrée à cet espace de N'hésitez pas à jeter un œil à la page de manuel consacrée à cet espace de
noms : `pid_namespaces(7)`. noms : `pid_namespaces(7)`.

View file

@ -9,7 +9,7 @@ Projet et rendu
notation de ce cours.** notation de ce cours.**
Vous allez continuer aujourd'hui le projet qui s'étendra depuis le TP précédent Vous allez continuer aujourd'hui le projet qui s'étendra depuis le TP précédent
et qui consistera à réaliser la partie d'isolation de la moulinette des ACUs ! et qui consistera à réaliser la partie d'isolation de la moulinette des ACUs !
Cette semaine, il faudra faire en sorte de restreindre un groupe de processus Cette semaine, il faudra faire en sorte de restreindre un groupe de processus
pour qu'il s'exécute indépendemment de votre système. pour qu'il s'exécute indépendemment de votre système.
@ -17,8 +17,8 @@ pour qu'il s'exécute indépendemment de votre système.
Il n'y a pas de restriction sur le langage utilisé, vous pouvez tout aussi bien Il n'y a pas de restriction sur le langage utilisé, vous pouvez tout aussi bien
utiliser du C, du C++, du Python, du shell, etc. utiliser du C, du C++, du Python, du shell, etc.
L'usage de bibliothèques **non relatives** au projet est autorisé : le but de L'usage de bibliothèques **non relatives** au projet est autorisé : le but de
ce sujet est d'évaluer votre compréhension et votre utilisation de la ce sujet est d'évaluer votre compréhension et votre utilisation de la
tuyauterie bas-niveau du noyau liée à la virtualisation légère. À partir du tuyauterie bas-niveau du noyau liée à la virtualisation légère. À partir du
moment où vous n'utilisez pas une bibliothèque qui abstrait complètement cette moment où vous n'utilisez pas une bibliothèque qui abstrait complètement cette
plomberie, n'hésitez pas à l'utiliser ! plomberie, n'hésitez pas à l'utiliser !

View file

@ -3,9 +3,9 @@
Projet et rendu Projet et rendu
=============== ===============
Est attendu d'ici le TP suivant : Est attendu d'ici le TP suivant :
- le rendu des exercice de ce TP ; - le rendu des exercice de ce TP ;
- vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/15). - vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/15).
Pour les GISTRE (et en bonus pour les SRS), [un Pour les GISTRE (et en bonus pour les SRS), [un
@ -40,7 +40,7 @@ RAR, ...).
Voici une arborescence type (adaptez les extensions et les éventuels Voici une arborescence type (adaptez les extensions et les éventuels
fichiers supplémentaires associés au langage que vous aurez choisi fichiers supplémentaires associés au langage que vous aurez choisi
pour chaque exercice) : pour chaque exercice) :
<div lang="en-US"> <div lang="en-US">
``` ```

View file

@ -1,6 +1,6 @@
#### Exemple C\ #### Exemple C\
Voici un exemple de code C utilisant `setns(2)` : Voici un exemple de code C utilisant `setns(2)` :
<div lang="en-US"> <div lang="en-US">
```c ```c
@ -38,7 +38,7 @@ main(int argc, char *argv[])
#### Exemple shell\ #### Exemple shell\
Dans un shell, on utilisera la commande `nsenter(1)` : Dans un shell, on utilisera la commande `nsenter(1)` :
<div lang="en-US"> <div lang="en-US">
```bash ```bash

View file

@ -23,7 +23,7 @@ l'autre, d'une version du noyau à l'autre, il est normal d'avoir une liste de
aurons les mêmes. aurons les mêmes.
Ces fichiers sont en fait des liens symboliques un peu particuliers, car ils ne Ces fichiers sont en fait des liens symboliques un peu particuliers, car ils ne
pointent pas vers une destination valide : pointent pas vers une destination valide :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -52,7 +52,7 @@ On ne peut pas afficher tel quel les structures, mais on peut l'ouvrir avec
`setns(2)`. `setns(2)`.
Pour les commandes *shell*, il convient de donner en argument le chemin vers le Pour les commandes *shell*, il convient de donner en argument le chemin vers le
lien symbolique : la commande se chargera d'`open(2)` le fichier. lien symbolique : la commande se chargera d'`open(2)` le fichier.
#### `*_for_children`\ #### `*_for_children`\

View file

@ -5,7 +5,7 @@
Pour pouvoir suivre les exercices ci-après, vous devez disposez d'un noyau Pour pouvoir suivre les exercices ci-après, vous devez disposez d'un noyau
Linux, idéalement dans sa version 5.6 ou mieux. Il doit de plus être compilé Linux, idéalement dans sa version 5.6 ou mieux. Il doit de plus être compilé
avec les options suivantes (lorsqu'elles sont disponibles pour votre version) : avec les options suivantes (lorsqu'elles sont disponibles pour votre version) :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -28,7 +28,7 @@ Device Drivers --->
``` ```
</div> </div>
Les variables de configuration correspondantes sont : Les variables de configuration correspondantes sont :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -62,13 +62,13 @@ Nous allons utiliser des programmes issus des
[`procps-ng`](https://gitlab.com/procps-ng/procps) ainsi que ceux de la [`procps-ng`](https://gitlab.com/procps-ng/procps) ainsi que ceux de la
[`libcap`](https://sites.google.com/site/fullycapable/). [`libcap`](https://sites.google.com/site/fullycapable/).
Sous Debian et ses dérivés, ces paquets sont respectivement : Sous Debian et ses dérivés, ces paquets sont respectivement :
* `util-linux` * `util-linux`
* `procps` * `procps`
* `libcap2-bin` * `libcap2-bin`
Sous ArchLinux et ses dérivés, ces paquets sont respectivement : Sous ArchLinux et ses dérivés, ces paquets sont respectivement :
* `util-linux` * `util-linux`
* `procps-ng` * `procps-ng`
@ -79,17 +79,17 @@ Sous ArchLinux et ses dérivés, ces paquets sont respectivement :
La sécurité du *namespace* `user` a souvent été remise en cause par le passé, La sécurité du *namespace* `user` a souvent été remise en cause par le passé,
on lui attribue de nombreuses vulnérabilités. Vous devriez notamment consulter on lui attribue de nombreuses vulnérabilités. Vous devriez notamment consulter
à ce sujet : à ce sujet :
* [Security Implications of User Namespaces](https://blog.araj.me/security-implications-of-user-namespaces/) ; * [Security Implications of User Namespaces](https://blog.araj.me/security-implications-of-user-namespaces/) ;
* [Anatomy of a user namespaces vulnerability](https://lwn.net/Articles/543273/) ; * [Anatomy of a user namespaces vulnerability](https://lwn.net/Articles/543273/) ;
* <http://marc.info/?l=linux-kernel&m=135543612731939&w=2> ; * <http://marc.info/?l=linux-kernel&m=135543612731939&w=2> ;
* <http://marc.info/?l=linux-kernel&m=135545831607095&w=2>. * <http://marc.info/?l=linux-kernel&m=135545831607095&w=2>.
De nombreux projets ont choisi de ne pas autoriser l'utilisation de cet espace De nombreux projets ont choisi de ne pas autoriser l'utilisation de cet espace
de noms sans disposer de certaines *capabilities*[^userns-caps]. de noms sans disposer de certaines *capabilities*[^userns-caps].
[^userns-caps]: Sont nécessaires, conjointement : `CAP_SYS_ADMIN`, `CAP_SETUID` et `CAP_SETGID`. [^userns-caps]: Sont nécessaires, conjointement : `CAP_SYS_ADMIN`, `CAP_SETUID` et `CAP_SETGID`.
De nombreuses distributions ont choisi d'utiliser un paramètre du noyau pour De nombreuses distributions ont choisi d'utiliser un paramètre du noyau pour
adapter le comportement. adapter le comportement.
@ -99,7 +99,7 @@ adapter le comportement.
##### Debian et ses dérivées {.unnumbered} ##### Debian et ses dérivées {.unnumbered}
Si vous utilisez Debian ou l'un de ses dérivés, vous devrez autoriser Si vous utilisez Debian ou l'un de ses dérivés, vous devrez autoriser
explicitement cette utilisation non-privilégiée : explicitement cette utilisation non-privilégiée :
<div lang="en-US"> <div lang="en-US">
```bash ```bash

View file

@ -23,7 +23,7 @@ utilisateur, on obtient les privilèges requis pour créer tous les autres types
de *namespaces*. de *namespaces*.
Grâce à cette technique, il est possible de lancer des conteneurs en tant que Grâce à cette technique, il est possible de lancer des conteneurs en tant que
simple utilisateur ; le projet [Singularity](https://sylabs.io/) repose simple utilisateur ; le projet [Singularity](https://sylabs.io/) repose
en grande partie sur cela. en grande partie sur cela.
@ -34,11 +34,11 @@ garder dans le nouvel espace, que les utilisateurs et les groupes utiles au
processus, en les renumérotant au passage si besoin. processus, en les renumérotant au passage si besoin.
#### L'utilisateur -2 : *nobody*\ #### L'utilisateur -2 : *nobody*\
Lorsque l'on arrive dans un nouvel espace, aucun utilisateur ni groupe n'est Lorsque l'on arrive dans un nouvel espace, aucun utilisateur ni groupe n'est
défini. Dans cette situation, tous les identifiants d'utilisateur et de groupe, défini. Dans cette situation, tous les identifiants d'utilisateur et de groupe,
renvoyés par le noyau sont à -2 ; valeur qui correspond par convention à renvoyés par le noyau sont à -2 ; valeur qui correspond par convention à
l'utilisateur *nobody* et au groupe *nogroup*. l'utilisateur *nobody* et au groupe *nogroup*.
-1 étant réservé pour indiquer une erreur dans le retour d'une commande, ou la -1 étant réservé pour indiquer une erreur dans le retour d'une commande, ou la
@ -53,7 +53,7 @@ Pour établir la correspondance, une fois que l'on a créé le nouveau
##### `uid_map`\ ##### `uid_map`\
Sur chaque ligne, on doit indiquer : Sur chaque ligne, on doit indiquer :
- L'identifiant marquant le début de la plage d'utilisateurs, pour le processus - L'identifiant marquant le début de la plage d'utilisateurs, pour le processus
en question. en question.
@ -62,7 +62,7 @@ Sur chaque ligne, on doit indiquer :
- La taille de la plage. - La taille de la plage.
Par exemple, le *namespace* `user` initial défini la correspondance suivante : Par exemple, le *namespace* `user` initial défini la correspondance suivante :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -75,7 +75,7 @@ Cela signifie que les utilisateurs dont l'identifiant court de 0 à `MAX_INT -
2` inclus, dans cet espace de noms, correspondent aux utilisateurs allant de 0 à 2` inclus, dans cet espace de noms, correspondent aux utilisateurs allant de 0 à
`MAX_INT - 1` inclus, pour le processus affichant ce fichier. `MAX_INT - 1` inclus, pour le processus affichant ce fichier.
Lorsque l'on crée un *namespace* `user`, généralement, la correspondance vaut : Lorsque l'on crée un *namespace* `user`, généralement, la correspondance vaut :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -99,18 +99,18 @@ des groupes au lieu des utilisateurs.
<div lang="en-US"> <div lang="en-US">
```bash ```bash
42sh$ unshare --mount --pid --mount-proc --fork --net --user --map-root-user /bin/bash 42sh$ unshare --mount --pid --mount-proc --fork --net --user --map-root-user bash
``` ```
</div> </div>
Un `capsh --print` nous montre que l'on est bien `root` et que l'on possède Un `capsh --print` nous montre que l'on est bien `root` et que l'on possède
toutes les *capabilities*. Cependant, cela ne signifie pas que l'on a tous les toutes les *capabilities*. Cependant, cela ne signifie pas que l'on a tous les
droits sur le système ; il y a plusieurs niveaux de validation qui entrent en droits sur le système ; il y a plusieurs niveaux de validation qui entrent en
jeu. L'idée étant que l'on a été désigné root dans son conteneur, on devrait jeu. L'idée étant que l'on a été désigné root dans son conteneur, on devrait
pouvoir y faire ce que l'on veut, tant que l'on n'agit pas en dehors. pouvoir y faire ce que l'on veut, tant que l'on n'agit pas en dehors.
### Aller plus loin {-} ### Aller plus loin {-}
N'hésitez pas à jeter un œil à la page du manuel consacrée à ce *namespace* : N'hésitez pas à jeter un œil à la page du manuel consacrée à ce *namespace* :
`user_namespaces(7)`. `user_namespaces(7)`.

View file

@ -2,7 +2,9 @@ include ../pandoc-opts.mk
SOURCES_SRS = tutorial-srs.md \ SOURCES_SRS = tutorial-srs.md \
../devops/devops.md \ ../devops/devops.md \
../devops/what.md \ ../devops/what-srs.md \
../devops/what-ansible.md \
../devops/what-hosts.md \
../devops/tools.md \ ../devops/tools.md \
../devops/tools-gitea.md \ ../devops/tools-gitea.md \
../devops/tools-gitea-ansible.md \ ../devops/tools-gitea-ansible.md \
@ -12,6 +14,7 @@ SOURCES_SRS = tutorial-srs.md \
../devops/tools-drone-oauth.md \ ../devops/tools-drone-oauth.md \
../devops/tools-drone-runner.md \ ../devops/tools-drone-runner.md \
../devops/tools-drone-runner-ansible.md \ ../devops/tools-drone-runner-ansible.md \
../devops/tools-drone-runner-end.md \
../devops/tools-end.md \ ../devops/tools-end.md \
../devops/ci.md \ ../devops/ci.md \
../devops/publish-docker.md \ ../devops/publish-docker.md \
@ -19,6 +22,8 @@ SOURCES_SRS = tutorial-srs.md \
SOURCES_GISTRE = tutorial-gistre.md \ SOURCES_GISTRE = tutorial-gistre.md \
../devops/what-gistre.md \ ../devops/what-gistre.md \
../devops/what-cmd.md \
../devops/what-hosts.md \
../devops/what-gistre-see-srs.md \ ../devops/what-gistre-see-srs.md \
../devops/tools.md \ ../devops/tools.md \
../devops/tools-gitea.md \ ../devops/tools-gitea.md \
@ -29,6 +34,7 @@ SOURCES_GISTRE = tutorial-gistre.md \
../devops/tools-drone-oauth.md \ ../devops/tools-drone-oauth.md \
../devops/tools-drone-runner.md \ ../devops/tools-drone-runner.md \
../devops/tools-drone-runner-cmd.md \ ../devops/tools-drone-runner-cmd.md \
../devops/tools-drone-runner-end.md \
../devops/tools-end.md \ ../devops/tools-end.md \
../devops/ci-gistre.md \ ../devops/ci-gistre.md \
../devops/run-gistre.md \ ../devops/run-gistre.md \

View file

@ -34,7 +34,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à
placer dans une tarball (pas d'archive ZIP, RAR, ...). placer dans une tarball (pas d'archive ZIP, RAR, ...).
Voici une arborescence type (vous pourriez avoir des fichiers Voici une arborescence type (vous pourriez avoir des fichiers
supplémentaires) : supplémentaires) :
<div lang="en-US"> <div lang="en-US">
``` ```

View file

@ -34,7 +34,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à
placer dans une tarball (pas d'archive ZIP, RAR, ...). placer dans une tarball (pas d'archive ZIP, RAR, ...).
Voici une arborescence type (vous pourriez avoir des fichiers Voici une arborescence type (vous pourriez avoir des fichiers
supplémentaires) : supplémentaires) :
<div lang="en-US"> <div lang="en-US">
``` ```

View file

@ -29,7 +29,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à
placer dans une tarball (pas d'archive ZIP, RAR, ...). placer dans une tarball (pas d'archive ZIP, RAR, ...).
Voici une arborescence type (vous pourriez avoir des fichiers Voici une arborescence type (vous pourriez avoir des fichiers
supplémentaires) : supplémentaires) :
<div lang="en-US"> <div lang="en-US">
``` ```

View file

@ -1,13 +1,13 @@
--- ---
title: Virtualisation légère -- TP n^o^ 5 title: Virtualisation légère -- TP n^o^ 5
subtitle: "Application des conteneurs : tests et intégration continue" subtitle: "Application des conteneurs : tests et intégration continue"
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps} author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
institute: EPITA institute: EPITA
date: Jeudi 4 novembre 2021 date: Jeudi 4 novembre 2021
abstract: | abstract: |
Durant ce nouveau TP, appréhenderons l'intégration continue et nous Durant ce nouveau TP, appréhenderons l'intégration continue et nous
plongerons dans l'IoT pour trouver une solution innovante à des problèmes de plongerons dans l'IoT pour trouver une solution innovante à des problèmes de
déploiement ! déploiement !
\vspace{1em} \vspace{1em}

View file

@ -6,7 +6,7 @@ institute: EPITA
date: Jeudi 4 novembre 2021 date: Jeudi 4 novembre 2021
abstract: | abstract: |
Durant ce nouveau TP, nous allons jouer les DevOps et déployer Durant ce nouveau TP, nous allons jouer les DevOps et déployer
automatiquement des services ! automatiquement des services !
\vspace{1em} \vspace{1em}

View file

@ -6,7 +6,7 @@ institute: EPITA
date: Jeudi 4 novembre 2021 date: Jeudi 4 novembre 2021
abstract: | abstract: |
Durant ce nouveau TP, nous allons jouer les DevOps et déployer Durant ce nouveau TP, nous allons jouer les DevOps et déployer
automatiquement des services ! automatiquement des services !
\vspace{1em} \vspace{1em}

View file

@ -4,7 +4,7 @@ function Div(el)
-- insert element in front -- insert element in front
table.insert( table.insert(
el.content, 1, el.content, 1,
pandoc.RawBlock("latex", "\\begin{alertbox}")) pandoc.RawBlock("latex", "\\noindent\\begin{alertbox}"))
-- insert element at the back -- insert element at the back
table.insert( table.insert(
el.content, el.content,
@ -15,7 +15,7 @@ function Div(el)
-- insert element in front -- insert element in front
table.insert( table.insert(
el.content, 1, el.content, 1,
pandoc.RawBlock("latex", "\\begin{codebox}")) pandoc.RawBlock("latex", "\\noindent\\begin{codebox}"))
-- insert element at the back -- insert element at the back
table.insert( table.insert(
el.content, el.content,
@ -26,7 +26,7 @@ function Div(el)
-- insert element in front -- insert element in front
table.insert( table.insert(
el.content, 1, el.content, 1,
pandoc.RawBlock("latex", "\\begin{questionbox}")) pandoc.RawBlock("latex", "\\noindent\\begin{questionbox}"))
-- insert element at the back -- insert element at the back
table.insert( table.insert(
el.content, el.content,

View file

@ -3,4 +3,4 @@
Déploiement Déploiement
=========== ===========
TODO il faudrait pouvoir cliquer sur le bouton pour mettre à jour l'image docker qui tourne localement ? en passant par Ansible ? TODO il faudrait pouvoir cliquer sur le bouton pour mettre à jour l'image docker qui tourne localement ? en passant par Ansible ?

View file

@ -21,11 +21,11 @@ configuration des dépôts.
::::: :::::
Une fois Gitea et Drone installés et configurés, nous allons pouvoir rentrer Une fois Gitea et Drone installés et configurés, nous allons pouvoir rentrer
dans le vif du sujet : faire de l'intégration continue sur notre premier projet ! dans le vif du sujet : faire de l'intégration continue sur notre premier projet !
### Créez un dépôt pour `linky2influx` ### Créez un dépôt pour `linky2influx`
Après avoir créé (ou migré pour les plus malins !) le dépôt Après avoir créé (ou migré pour les plus malins !) le dépôt
[`linky2influx`](https://git.nemunai.re/nemunaire/linky2influx) dans Drone, [`linky2influx`](https://git.nemunai.re/nemunaire/linky2influx) dans Drone,
synchronisez les dépôts, puis activez la surveillance de `linky2influx`. synchronisez les dépôts, puis activez la surveillance de `linky2influx`.
@ -57,33 +57,33 @@ Committons puis poussons notre travail. Dès qu'il sera reçu par Gitea, nous
devrions voir l'interface de Drone lancer les étapes décrites dans le fichier. devrions voir l'interface de Drone lancer les étapes décrites dans le fichier.
::::: {.warning} ::::: {.warning}
**IMPORTANT :** si vous avez l'impression que ça ne marche pas et que vous avez **IMPORTANT :** si vous avez l'impression que ça ne marche pas et que vous avez
réutilisé le fichier présent sur le dépôt au lieu de partir de l'exemple donné réutilisé le fichier présent sur le dépôt au lieu de partir de l'exemple donné
dans la documentation, **commencez en partant de l'exemple de la dans la documentation, **commencez en partant de l'exemple de la
documentation** ! Le fichier présent sur le dépôt **ne fonctionnera pas** dans documentation** ! Le fichier présent sur le dépôt **ne fonctionnera pas** dans
votre situation ! votre situation !
::::: :::::
![Drone en action](../devops/drone-run-linky.png){height=7.5cm} ![Drone en action](../devops/drone-run-linky.png){height=7.5cm}
Lorsqu'apparaît enfin la ligne `git.nemunai.re/linky2influx`, le projet est compilé ! Lorsqu'apparaît enfin la ligne `git.nemunai.re/linky2influx`, le projet est compilé !
### Publier le binaire correspondant aux tags/jalons ### Publier le binaire correspondant aux tags/jalons
Nous savons maintenant que notre projet compile bien dans un environnement Nous savons maintenant que notre projet compile bien dans un environnement
différent de celui du développeur ! Néanmoins, le binaire produit est perdu dès différent de celui du développeur ! Néanmoins, le binaire produit est perdu dès
lors que la compilation est terminée, car nous n'en faisons rien. lors que la compilation est terminée, car nous n'en faisons rien.
Ajoutons donc une nouvelle règle à notre `.droneci.yml` pour placer le binaire Ajoutons donc une nouvelle règle à notre `.droneci.yml` pour placer le binaire
au sein de la liste des fichiers téléchargeable aux côtés des tags. au sein de la liste des fichiers téléchargeable aux côtés des tags.
Vous aurez sans doute besoin de : Vous aurez sans doute besoin de :
- <https://docs.drone.io/pipeline/conditions/> - <https://docs.drone.io/pipeline/conditions/>
- <http://plugins.drone.io/drone-plugins/drone-gitea-release/> - <http://plugins.drone.io/drone-plugins/drone-gitea-release/>
Attention à ne pas stocker votre clef d'API dans le fichier YAML ! Attention à ne pas stocker votre clef d'API dans le fichier YAML !
![Binaire publié automatiquement sur Gitea](../devops/tag-released.png){height=8cm} ![Binaire publié automatiquement sur Gitea](../devops/tag-released.png){height=8cm}
@ -95,16 +95,16 @@ l'interface de Drone.
::::: :::::
### Publier pour plusieurs architectures ? ### Publier pour plusieurs architectures ?
Le compilateur Go est fourni avec l'ensemble des backends des différentes Le compilateur Go est fourni avec l'ensemble des backends des différentes
architectures matérielles qu'il supporte, nous pouvons donc aisément faire de architectures matérielles qu'il supporte, nous pouvons donc aisément faire de
la compilation croisée pour d'autres architectures. la compilation croisée pour d'autres architectures.
Essayons maintenant de compiler `linky2influx` pour plusieurs architectures afin de Essayons maintenant de compiler `linky2influx` pour plusieurs architectures afin de
vérifier que cela fonctionne bien ! vérifier que cela fonctionne bien !
Un exemple est donné tout en haut de cette page : Un exemple est donné tout en haut de cette page :
<https://docs.drone.io/pipeline/environment/syntax/>. <https://docs.drone.io/pipeline/environment/syntax/>.
En faisant varier `$GOARCH` en `mips`, `powerpc`, ... nous pouvons générer les En faisant varier `$GOARCH` en `mips`, `powerpc`, ... nous pouvons générer les

View file

@ -3,24 +3,26 @@
## Intégration continue ## Intégration continue
Une fois Gitea et Drone installés et configurés, nous allons pouvoir rentrer Une fois Gitea et Drone installés et configurés, nous allons pouvoir rentrer
dans le vif du sujet : faire de l'intégration continue sur notre premier projet ! dans le vif du sujet : faire de l'intégration continue sur notre premier projet !
### Créez un dépôt pour `youp0m` ### Créez un dépôt pour `youp0m`
Reprenez les travaux réalisés au TP précédent. Nous allons notamment avoir Reprenez les travaux déjà réalisés : nous allons notamment avoir besoin du
besoin du `Dockerfile` dans la section suivante. `Dockerfile` que nous avons réalisé pour ce projet `youp0m`.
Après avoir créé (ou migré pour les plus malins !) le dépôt Après avoir créé (ou migré pour les plus malins !) le dépôt
[`youp0m`](https://git.nemunai.re/nemunaire/youp0m) dans Drone, `youp0m`[^urlyoup0m] dans gitea, synchronisez les dépôts dans Drone, puis
synchronisez les dépôts, puis activez la surveillance de `youp0m`. activez la surveillance de `youp0m`.
Nous allons devoir rédiger un fichier `.drone.yml`, que l'on placera à la racine [^urlyoup0m]: <https://git.nemunai.re/nemunaire/youp0m>
Nous allons devoir rédiger un fichier `drone.yml`, que l'on placera à la racine
du dépôt. C'est ce fichier qui sera traité par DroneCI pour savoir comment du dépôt. C'est ce fichier qui sera traité par DroneCI pour savoir comment
compiler et tester le projet. compiler et tester le projet.
::::: {.warning} ::::: {.warning}
Un fichier `.drone.yml` existe déjà à la racine du dépôt. Celui-ci pourra vous Un fichier `drone.yml` existe déjà à la racine du dépôt. Celui-ci pourra vous
servir d'inspiration, mais il ne fonctionnera pas directement sur votre servir d'inspiration, mais il ne fonctionnera pas directement dans votre
installation. installation.
**Vous rencontrerez des problèmes inattendus si vous utilisez le fichier **Vous rencontrerez des problèmes inattendus si vous utilisez le fichier
@ -32,11 +34,11 @@ documentation pour obtenir un `.drone.yml` fonctionnel.
### Définir les étapes d'intégration ### Définir les étapes d'intégration
Toutes les informations nécessaires à l'écriture du fichier `.drone.yml` se Toutes les informations nécessaires à l'écriture du fichier `.drone.yml` se
trouvent dans [l'excellente documentation du trouvent dans l'excellente documentation du projet :\
projet](https://docs.drone.io/pipeline/docker/examples/languages/golang/). <https://docs.drone.io/pipeline/docker/examples/languages/golang/>.
Les étapes sont sensiblement les mêmes que dans le `Dockerfile` que nous avons Les étapes sont sensiblement les mêmes que dans le `Dockerfile` que nous avons
écrit lors du TP précédent. écrit précédemment.
Committons puis poussons notre travail. Dès qu'il sera reçu par Gitea, nous Committons puis poussons notre travail. Dès qu'il sera reçu par Gitea, nous
devrions voir l'interface de Drone lancer les étapes décrites dans le fichier. devrions voir l'interface de Drone lancer les étapes décrites dans le fichier.
@ -44,23 +46,22 @@ devrions voir l'interface de Drone lancer les étapes décrites dans le fichier.
![Drone en action](../devops/drone-run.png){height=6cm} ![Drone en action](../devops/drone-run.png){height=6cm}
::::: {.warning} ::::: {.warning}
**IMPORTANT :** si vous avez l'impression que ça ne marche pas et que vous avez **IMPORTANT :** si vous avez l'impression que ça ne marche pas et que vous avez
réutilisé le fichier présent sur le dépôt au lieu de partir de l'exemple donné réutilisé le fichier présent sur le dépôt au lieu de partir de l'exemple donné
dans la documentation, **commencez en partant de l'exemple de la dans la documentation, **commencez en partant de l'exemple de la
documentation** ! Le fichier présent sur le dépôt **ne fonctionnera pas** dans documentation** ! Le fichier présent sur le dépôt **ne fonctionnera pas** dans
votre situation ! votre situation !
::::: :::::
Lorsqu'apparaît enfin la ligne `git.nemunai.re/youp0m`, le projet est compilé ! Lorsqu'apparaît enfin la ligne `git.nemunai.re/youp0m`, le projet est compilé !
### Inspection qualité ### Inspection qualité
Nous n'avons pas encore de test à proprement parler. Nous allons utiliser Nous n'avons pas encore de test à proprement parler. Nous allons utiliser
[Sonarqube](https://www.sonarqube.org/) pour faire une revue qualité du code ! [Sonarqube](https://www.sonarqube.org/) pour faire une revue qualité du code !
Tout d'abord, il faut lancer le conteneur Sonarqube (SRS, pensez à l'ajouter à Tout d'abord, il faut lancer le conteneur Sonarqube :
votre playbook !) :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
@ -72,7 +73,7 @@ Le service met un bon moment avant de démarrer, dès qu'il se sera initialisé,
nous pourrons accéder à l'interface sur <http://localhost:9000>. nous pourrons accéder à l'interface sur <http://localhost:9000>.
En attendant qu'il démarre, nous pouvons commencer à ajouter le nécessaire à En attendant qu'il démarre, nous pouvons commencer à ajouter le nécessaire à
notre `.drone.yml` : <http://plugins.drone.io/aosapps/drone-sonar-plugin/>. notre `.drone.yml` : <http://plugins.drone.io/aosapps/drone-sonar-plugin/>.
Après s'être connecté à Sonarqube (`admin:admin`), nous pouvons aller générer Après s'être connecté à Sonarqube (`admin:admin`), nous pouvons aller générer
un token, tel que décrit dans la [documentation du plugin un token, tel que décrit dans la [documentation du plugin
@ -86,18 +87,18 @@ qui en fera une analyse minutieuse. Rendez-vous sur
### Publier le binaire correspondant aux tags/jalons ### Publier le binaire correspondant aux tags/jalons
Nous savons maintenant que notre projet compile bien dans un environnement Nous savons maintenant que notre projet compile bien dans un environnement
différent de celui du développeur ! Néanmoins, le binaire produit est perdu dès différent de celui du développeur ! Néanmoins, le binaire produit est perdu dès
lors que la compilation est terminée, car nous n'en faisons rien. lors que la compilation est terminée, car nous n'en faisons rien.
Ajoutons donc une nouvelle règle à notre `.droneci.yml` pour placer le binaire Ajoutons donc une nouvelle règle à notre `.droneci.yml` pour placer le binaire
au sein de la liste des fichiers téléchargeables aux côtés des tags. au sein de la liste des fichiers téléchargeables aux côtés des tags.
Vous aurez sans doute besoin de : Vous aurez sans doute besoin de :
- <https://docs.drone.io/pipeline/conditions/> - <https://docs.drone.io/pipeline/conditions/>
- <http://plugins.drone.io/drone-plugins/drone-gitea-release/> - <http://plugins.drone.io/drone-plugins/drone-gitea-release/>
Attention à ne pas stocker votre clef d'API dans le fichier YAML ! Attention à ne pas stocker votre clef d'API dans le fichier YAML !
![Binaire publié automatiquement sur Gitea](../devops/tag-released.png){height=8cm} ![Binaire publié automatiquement sur Gitea](../devops/tag-released.png){height=8cm}

View file

@ -4,13 +4,13 @@ Le mouvement DevOps
=================== ===================
Jusqu'à récemment, et encore dans de nombreuses entreprises, les développeurs Jusqu'à récemment, et encore dans de nombreuses entreprises, les développeurs
et les administrateurs système faisaient partie de deux équipes différentes : et les administrateurs système faisaient partie de deux équipes différentes :
les uns développant sur leurs machines avec les dernières bibliothèques, les uns développant sur leurs machines avec les dernières bibliothèques,
utilisant les derniers frameworks à la mode, sans se préoccuper de la sécurité utilisant les derniers frameworks à la mode, sans se préoccuper de la sécurité
(ils travaillent en `root` ou avec `sudo` ;)), tandis que les autres tentaient (ils travaillent en `root` ou avec `sudo` ;)), tandis que les autres tentaient
tant bien que mal de déployer ces services avec les contraintes opérationnelles tant bien que mal de déployer ces services avec les contraintes opérationnelles
en tête.\ en tête.\
Ces contraintes : tant liées à la **sécurité** (il faut s'assurer Ces contraintes : tant liées à la **sécurité** (il faut s'assurer
qu'un service n'utilise pas une bibliothèque vulnérable par exemple, donc soit qu'un service n'utilise pas une bibliothèque vulnérable par exemple, donc soit
utilisé sur un système à jour, et qu'il ne tourne pas en `root`), qu'à la utilisé sur un système à jour, et qu'il ne tourne pas en `root`), qu'à la
**disponibilité** (si le service est mal codé est contient beaucoup de fuites **disponibilité** (si le service est mal codé est contient beaucoup de fuites
@ -19,13 +19,13 @@ pâtissent).
Une guerre faisait donc rage entre les développeurs qui ne comprenaient pas que Une guerre faisait donc rage entre les développeurs qui ne comprenaient pas que
les administrateurs système ne pouvaient pas maintenir autant de versions d'une les administrateurs système ne pouvaient pas maintenir autant de versions d'une
bibliothèque qu'il y avait de services : par exemple dans le cas de plusieurs bibliothèque qu'il y avait de services : par exemple dans le cas de plusieurs
services en PHP, on pouvait leur demander de déployer des applications services en PHP, on pouvait leur demander de déployer des applications
utilisant la version 5.6, et la 7.2 pour d'autres, ... lorsqu'il y avait des utilisant la version 5.6, et la 7.2 pour d'autres, ... lorsqu'il y avait des
incompatibilités mineures et plus personne pour s'occuper de la maintenance incompatibilités mineures et plus personne pour s'occuper de la maintenance
d'un vieux service toujours utilisé. d'un vieux service toujours utilisé.
Le même principe est aussi valable pour Python, Ruby, ... : les développeurs Le même principe est aussi valable pour Python, Ruby, ... : les développeurs
ont toujours eu tendance à vouloir utiliser les dernières améliorations d'un ont toujours eu tendance à vouloir utiliser les dernières améliorations d'un
langage, mais les administrateurs système n'ont alors pas de paquets stables langage, mais les administrateurs système n'ont alors pas de paquets stables
dans la distribution. En effet, les distributions stables telles que Debian, dans la distribution. En effet, les distributions stables telles que Debian,
@ -64,10 +64,10 @@ charges, les pannes, ...
::::: {.warning} ::::: {.warning}
Attention par contre aux entreprises qui recrutent un profil DevOps, car cela a Attention par contre aux entreprises qui recrutent un profil DevOps, car cela a
autant de sens que recruter un développeur Scrum ou un développeur cycle en V : autant de sens que recruter un développeur Scrum ou un développeur cycle en V :
DevOps est une méthodologie. Les entreprises qui recrutent un DevOps DevOps est une méthodologie. Les entreprises qui recrutent un DevOps
recherchent généralement quelqu'un qui fera à la fois du développement logiciel recherchent généralement quelqu'un qui fera à la fois du développement logiciel
d'un côté et de l'administration système de l'autre : une situation d'un côté et de l'administration système de l'autre : une situation
généralement assez difficile à vivre. Alors qu'au contraire, la mouvance DevOps généralement assez difficile à vivre. Alors qu'au contraire, la mouvance DevOps
doit être prise au sérieux par l'ensemble des développeurs. Lors d'un entretien doit être prise au sérieux par l'ensemble des développeurs. Lors d'un entretien
d'embauche pour ce genre de poste, assurez-vous bien de ne pas être le seul à d'embauche pour ce genre de poste, assurez-vous bien de ne pas être le seul à
@ -77,14 +77,14 @@ faire du DevOps.
## Intégration continue ## Intégration continue
L'**intégration continue** est la première brique à mettre en place : le but L'**intégration continue** est la première brique à mettre en place : le but
est de compiler automatiquement chaque commit dans un environnement proche de est de compiler automatiquement chaque commit dans un environnement proche de
celui de production, puis de lancer les suites de tests du logiciel. celui de production, puis de lancer les suites de tests du logiciel.
Cela permet de détecter les problèmes au plus tôt dans le cycle de Cela permet de détecter les problèmes au plus tôt dans le cycle de
développement, mais cela permet également d'améliorer la qualité du code sur le développement, mais cela permet également d'améliorer la qualité du code sur le
long terme, car on peut y ajouter facilement des outils qui vont se charger long terme, car on peut y ajouter facilement des outils qui vont se charger
automatiquement de réaliser des analyses : cela peut aller de la couverture des automatiquement de réaliser des analyses : cela peut aller de la couverture des
tests, à de l'analyse statique ou dynamique de binaire, en passant par la tests, à de l'analyse statique ou dynamique de binaire, en passant par la
recherche de vulnérabilités ou de mauvaises pratiques de programmation. recherche de vulnérabilités ou de mauvaises pratiques de programmation.
@ -101,7 +101,7 @@ les développeurs considéreront avoir atteint un jalon, une version stable.
## Déploiement continu ## Déploiement continu
Une fois tous les tests passés et les objets produits (on parle d'*artifact* ou Une fois tous les tests passés et les objets produits (on parle d'*artifact* ou
d'*assets*), il est possible de déclencher un déploiement : il s'agit de rendre d'*assets*), il est possible de déclencher un déploiement : il s'agit de rendre
accessible aux utilisateurs finaux le service ou les objets. accessible aux utilisateurs finaux le service ou les objets.
Dans le cas d'un programme à télécharger Dans le cas d'un programme à télécharger
@ -113,15 +113,15 @@ vers la dernière version (pour que les utilisateurs aient la notifications).
Ou bien dans le cas d'un service en ligne (GitHub, Netflix, GMail, ...), il Ou bien dans le cas d'un service en ligne (GitHub, Netflix, GMail, ...), il
s'agira de mettre à jour le service. s'agira de mettre à jour le service.
Parfois les deux seront à faire : à la fois publier un paquet ou un Parfois les deux seront à faire : à la fois publier un paquet ou un
conteneur et mettre à jour un service en ligne : par exemple, [le conteneur et mettre à jour un service en ligne : par exemple, [le
serveur Synapse](https://buildkite.com/matrix-dot-org/synapse) du serveur Synapse](https://buildkite.com/matrix-dot-org/synapse) du
protocole de messagerie Matrix ou encore protocole de messagerie Matrix ou encore
[Gitlab](https://gitlab.com/gitlab-org/gitlab/-/pipelines), tous deux [Gitlab](https://gitlab.com/gitlab-org/gitlab/-/pipelines), tous deux
publient des paquets à destination de leurs communautés, et mettent à publient des paquets à destination de leurs communautés, et mettent à
jour leur service en ligne.\ jour leur service en ligne.\
Il existe pour cela de très nombreuses stratégies : lorsque l'on n'a pas Il existe pour cela de très nombreuses stratégies : lorsque l'on n'a pas
beaucoup de trafic ni beaucoup de machines, on peut simplement éteindre beaucoup de trafic ni beaucoup de machines, on peut simplement éteindre
l'ancien service et démarrer le nouveau, si ça prend quelques millisecondes en l'ancien service et démarrer le nouveau, si ça prend quelques millisecondes en
étant automatisé, cela peut être suffisant compte tenu du faible étant automatisé, cela peut être suffisant compte tenu du faible
@ -133,11 +133,11 @@ de tout rallumer. Déjà parce que trop de visiteurs vont se retrouver avec des
pages d'erreur, et aussi parce qu'en cas de bug logiciel qui n'aurait pas été pages d'erreur, et aussi parce qu'en cas de bug logiciel qui n'aurait pas été
vu malgré les étapes précédentes, cela pourrait créer une situation vu malgré les étapes précédentes, cela pourrait créer une situation
catastrophique (imaginez qu'on ne puisse plus valider une commande sur Amazon à catastrophique (imaginez qu'on ne puisse plus valider une commande sur Amazon à
cause d'une ligne commentée par erreur !).\ cause d'une ligne commentée par erreur !).\
On va donc privilégier un déploiement progressif de la nouvelle version (que On va donc privilégier un déploiement progressif de la nouvelle version (que
l'on va étendre sur plusieurs minutes, heures ou mêmes jours), en éteignant l'on va étendre sur plusieurs minutes, heures ou mêmes jours), en éteignant
tour à tour les instances, et en veillant à ce que les métriques (voir la tour à tour les instances, et en veillant à ce que les métriques (voir la
section suivante !) soient constantes. section suivante !) soient constantes.
## Monitoring et supervision ## Monitoring et supervision
@ -145,16 +145,16 @@ section suivante !) soient constantes.
Une fois déployé, le service peut avoir des ratés, alors il convient de le Une fois déployé, le service peut avoir des ratés, alors il convient de le
surveiller afin d'être le plus proactif possible dans la résolution des surveiller afin d'être le plus proactif possible dans la résolution des
problèmes. La pire situation est celle dans laquelle c'est un utilisateur qui problèmes. La pire situation est celle dans laquelle c'est un utilisateur qui
nous informe d'un problème... (sur Twitter !?) nous informe d'un problème... (sur Twitter !?)
Nous avons réalisé précédemment une partie collecte de métriques, avec nos Nous avons réalisé précédemment une partie collecte de métriques, avec nos
conteneurs TICK. Nous n'allons donc pas nous en occuper aujourd'hui. conteneurs TICK. Nous n'allons donc pas nous en occuper aujourd'hui.
\ \