Save tuto corrections
This commit is contained in:
parent
f5ee6b8534
commit
10448a6c8d
115 changed files with 1425 additions and 1291 deletions
|
@ -3,7 +3,7 @@ include ../pandoc-opts.mk
|
|||
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/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/security.md \
|
||||
rendu.md
|
||||
|
|
|
@ -6,7 +6,7 @@ institute: EPITA
|
|||
date: Jeudi 16 septembre 2021
|
||||
abstract: |
|
||||
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}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Rendu
|
||||
=====
|
||||
|
||||
Est attendu d'ici le TP suivant :
|
||||
Est attendu d'ici le TP suivant :
|
||||
|
||||
- le rendu des exercice de ce TP ;
|
||||
- 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, ...).
|
||||
|
||||
Voici une arborescence type (vous pourriez avoir des fichiers
|
||||
supplémentaires) :
|
||||
supplémentaires) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
@ -7,7 +7,7 @@ date: Jeudi 23 septembre 2021
|
|||
abstract: |
|
||||
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
|
||||
connues !
|
||||
connues !
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ On trouve par exemple :
|
|||
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
|
||||
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
|
||||
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`.\
|
||||
|
||||
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">
|
||||
```
|
||||
|
@ -83,7 +83,7 @@ depuis un conteneur, par exemple :
|
|||
</div>
|
||||
|
||||
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">
|
||||
```
|
||||
|
@ -94,7 +94,7 @@ tests en retirant le *setuid* :
|
|||
```
|
||||
</div>
|
||||
|
||||
Puis en ajoutant la *capability* :
|
||||
Puis en ajoutant la *capability* :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
### Exercice (obligatoire pour les SRS -- optionnel pour les GISTRE)
|
||||
|
||||
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\
|
||||
|
||||
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">
|
||||
```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
|
||||
métriques. Voici comment on s'était débrouillé précédemment pour interagir avec
|
||||
InfluxDB :
|
||||
InfluxDB :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -33,7 +33,7 @@ Vérifiez que la base de données `metrics` a bien été créée.
|
|||
#### Monitoring vers InfluxDB\
|
||||
|
||||
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">
|
||||
```bash
|
||||
|
@ -43,7 +43,7 @@ curl -i -XPOST 'http://localhost:8086/write?db=metrics' --data-binary \
|
|||
</div>
|
||||
|
||||
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">
|
||||
```sql
|
||||
|
@ -54,15 +54,15 @@ SELECT * from "$my_cgroup_name";
|
|||
|
||||
#### 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'octets lus/écrits sur les disques ;
|
||||
* temps de calcul utilisé (`userspace`, `system`, tout confondu) ;
|
||||
* Nombre d'IOs effectué ;
|
||||
* nobre d'octets lus/écrits sur les disques ;
|
||||
* temps de calcul utilisé (`userspace`, `system`, tout confondu) ;
|
||||
* ...
|
||||
|
||||
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>
|
||||
- v2 : <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
|
||||
|
|
|
@ -4,40 +4,40 @@ Les *cgroup*s
|
|||
-------------
|
||||
|
||||
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
|
||||
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, ...
|
||||
|
||||
Apparue dès [Linux
|
||||
2.6.24](https://kernelnewbies.org/Linux_2_6_24#Task_Control_Groups)
|
||||
(en 2008 !), les *cgroup*s sont répartis en différents sous-systèmes
|
||||
(en 2008 !), les *cgroup*s sont répartis en différents sous-systèmes
|
||||
(*subsystem*), chacun étant responsable d'un type de ressources
|
||||
spécifique :
|
||||
spécifique :
|
||||
|
||||
- [`blkio` (`io` dans la v2)
|
||||
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/blkio-controller.html)
|
||||
limites et statistiques de bande passante sur les disques ;
|
||||
- `cpu` : cycles CPU minimum garantis ;
|
||||
limites et statistiques de bande passante sur les disques ;
|
||||
- `cpu` : cycles CPU minimum garantis ;
|
||||
- [`cpuacct` (inclus dans `cpu` dans la v2)
|
||||
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpuacct.html)
|
||||
statistiques du temps CPU utilisé ;
|
||||
statistiques du temps CPU utilisé ;
|
||||
- [`cpuset`
|
||||
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpusets.html)
|
||||
associe des tâches à un/des CPU particuliers (par exemple pour dédier un cœur
|
||||
du CPU à un programme, qui ne pourra alors utiliser que ce CPU et pas les
|
||||
autres) ;
|
||||
autres) ;
|
||||
- [`devices`
|
||||
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/devices.html)
|
||||
règles de contrôle de création (`mknod`) et d'accès aux périphériques ;
|
||||
règles de contrôle de création (`mknod`) et d'accès aux périphériques ;
|
||||
- [`freezer`
|
||||
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/freezer-subsystem.html)
|
||||
pour suspendre et reprendre l'exécution d'un groupe de tâches ;
|
||||
- [`hugetlb` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/hugetlb.html) statistiques et limitation de l'usage de la fonctionnalité `HugeTLB` (permettant d'obtenir des pages mémoires plus grande que 4 kB) ;
|
||||
- [`memory` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html) statistiques et limitation d'usage de la mémoire vive et de la *swap* ;
|
||||
- [`net_cls` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_cls.html) applique un `classid` à tous les paquets émis par les tâches du *cgroup*, pour filtrage par le pare-feu en sortie ;
|
||||
- [`net_prio` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_prio.html) surcharge la valeur de l'option de priorité `SO_PRIORITY`, ordonant la file d'attente des paquets sortants ;
|
||||
- [`pids` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/pids.html) statistiques et limitation du nombre de processus ;
|
||||
pour suspendre et reprendre l'exécution d'un groupe de tâches ;
|
||||
- [`hugetlb` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/hugetlb.html) statistiques et limitation de l'usage de la fonctionnalité `HugeTLB` (permettant d'obtenir des pages mémoires plus grande que 4 kB) ;
|
||||
- [`memory` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html) statistiques et limitation d'usage de la mémoire vive et de la *swap* ;
|
||||
- [`net_cls` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_cls.html) applique un `classid` à tous les paquets émis par les tâches du *cgroup*, pour filtrage par le pare-feu en sortie ;
|
||||
- [`net_prio` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_prio.html) surcharge la valeur de l'option de priorité `SO_PRIORITY`, ordonant la file d'attente des paquets sortants ;
|
||||
- [`pids` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/pids.html) statistiques et limitation du nombre de processus ;
|
||||
- ...
|
||||
|
||||
Nous allons commencer par faire quelques tests avec le *cgroup* *freezer*, qui
|
||||
|
@ -48,19 +48,19 @@ lorsqu'on le décide.
|
|||
### Montage du *freezer*
|
||||
|
||||
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
|
||||
é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.
|
||||
|
||||
- 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
|
||||
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">
|
||||
```bash
|
||||
|
@ -70,7 +70,7 @@ l'une de ces trois situations :
|
|||
</div>
|
||||
|
||||
|
||||
Pour utiliser la v2 :
|
||||
Pour utiliser la v2 :
|
||||
|
||||
<div lang="en-US">
|
||||
```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,
|
||||
par exemple la racine.
|
||||
|
||||
On commence par se rendre à la racine :
|
||||
On commence par se rendre à la racine :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -112,7 +112,7 @@ cd /sys/fs/cgroup/ # v2
|
|||
```
|
||||
</div>
|
||||
|
||||
Puis on crée notre groupe :
|
||||
Puis on crée notre groupe :
|
||||
|
||||
<div lang="en-US">
|
||||
```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).
|
||||
|
||||
Pour activer le contrôleur *memory* dans notre groupe `virli`, nous utilisons
|
||||
la commande suivante :
|
||||
la commande suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -163,9 +163,9 @@ le fichier `cgroup.procs` de notre groupe. Ce fichier contient la liste des
|
|||
processus rattachés à notre *cgroup*.
|
||||
|
||||
Ouvrons un nouveau terminal (c'est lui que l'on va geler), et récupérons son
|
||||
PID : `echo $$`.
|
||||
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">
|
||||
```bash
|
||||
|
@ -190,7 +190,7 @@ adaptés.
|
|||
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
|
||||
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
|
||||
fichier\
|
||||
|
@ -204,7 +204,7 @@ consultez
|
|||
### Changement d'état
|
||||
|
||||
Faisons exécuter à notre interpréteur une commande pour voir effectivement
|
||||
l'exécution s'arrêter. Si vous manquez d'inspiration, utilisez :
|
||||
l'exécution s'arrêter. Si vous manquez d'inspiration, utilisez :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -213,7 +213,7 @@ for i in $(seq 9999); do echo -n $i; sleep .1; echo -n " - "; sleep .1; done
|
|||
</div>
|
||||
|
||||
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">
|
||||
```bash
|
||||
|
@ -223,7 +223,7 @@ echo 1 > /sys/fs/cgroup/virli/cgroup.freeze # v2
|
|||
</div>
|
||||
|
||||
À cet instant, vous devriez voir votre compteur s'arrêter. Pour reprendre
|
||||
l'exécution :
|
||||
l'exécution :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -233,7 +233,7 @@ echo 0 > /sys/fs/cgroup/virli/cgroup.freeze # v2
|
|||
</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
|
||||
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
|
||||
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">
|
||||
```bash
|
||||
|
@ -275,7 +275,7 @@ Il s'utilise de la manière suivante :
|
|||
```
|
||||
</div>
|
||||
|
||||
Où :
|
||||
Où :
|
||||
|
||||
- `group_name` correspond au nom du/des *cgroup*(s) à créer/rejoindre.
|
||||
- `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
|
||||
correspondant à une valeur limite, comme par exemple
|
||||
`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">
|
||||
```
|
||||
|
@ -330,7 +330,7 @@ limiteurs, n'hésitez pas à consulter la documentation associée à chaque
|
|||
*cgroup*.
|
||||
|
||||
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">
|
||||
```
|
||||
|
@ -352,5 +352,5 @@ limites que vous avez définies :
|
|||
### Pour aller plus loin {-}
|
||||
|
||||
Pour tout connaître en détails, [la série d'articles de Neil Brown sur les
|
||||
Control groups](https://lwn.net/Articles/604609/) est excellente ! Plus [cet
|
||||
Control groups](https://lwn.net/Articles/604609/) est excellente ! Plus [cet
|
||||
article sur la version 2](https://lwn.net/Articles/679786/).
|
||||
|
|
|
@ -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
|
||||
|
@ -83,7 +83,7 @@ pacstrap newroot/
|
|||
</div>
|
||||
|
||||
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">
|
||||
```bash
|
||||
|
@ -100,9 +100,10 @@ sous forme de tarball :
|
|||
|
||||
#### 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">
|
||||
```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/
|
||||
```
|
||||
</div>
|
||||
|
@ -113,7 +114,7 @@ environnement qui tient dans 200 MB.
|
|||
:::::
|
||||
|
||||
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">
|
||||
```bash
|
||||
|
@ -124,15 +125,16 @@ chroot newroot/ bash
|
|||
|
||||
#### 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">
|
||||
```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/
|
||||
```
|
||||
</div>
|
||||
|
||||
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">
|
||||
```bash
|
||||
|
|
|
@ -8,5 +8,5 @@ allons tâcher d'apprendre comment il fonctionne en nous penchant sur un certain
|
|||
nombre de fonctionnalités de 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.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
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
|
||||
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
|
||||
|
@ -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*.
|
||||
|
||||
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*.
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ jusqu'à ce que le système retrouve sa sérénité.
|
|||
[^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
|
||||
`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
|
||||
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
|
||||
mémoire autorisée dans le `cgroup` ?
|
||||
mémoire autorisée dans le `cgroup` ?
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../subject/2/project-part1.md
|
115
tutorial/3/project-body.md
Normal file
115
tutorial/3/project-body.md
Normal 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)`, ...
|
|
@ -6,7 +6,7 @@ Projet et rendu
|
|||
## Sujet
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
principalement question de faire des appels systèmes.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Rendu
|
||||
=====
|
||||
|
||||
Est attendu d'ici le TP suivant :
|
||||
Est attendu d'ici le TP suivant :
|
||||
|
||||
- le rendu des exercice de ce TP ;
|
||||
- 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
|
||||
fichiers supplémentaires associés au langage que vous aurez choisi
|
||||
pour chaque exercice) :
|
||||
pour chaque exercice) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
@ -41,13 +41,13 @@ apporter des modifications.
|
|||
Linux emploie de nombreux systèmes de fichiers virtuels :
|
||||
|
||||
- `/proc` : contient, principalement, la liste des processus (`top` et ses
|
||||
dérivés se contentent de lire les fichiers de ce point de montage) ;
|
||||
- `/proc/sys` : contient la configuration du noyau ;
|
||||
dérivés se contentent de lire les fichiers de ce point de montage) ;
|
||||
- `/proc/sys` : contient la configuration du noyau ;
|
||||
- `/sys` : contient des informations à propos du matériel (utilisées notamment
|
||||
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
|
||||
l'UEFI ;
|
||||
l'UEFI ;
|
||||
- ...
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
##### `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
|
||||
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.
|
||||
|
||||
##### `rev_kdb_leds.sh`\
|
||||
|
@ -203,7 +203,7 @@ Si vous avez :
|
|||
|
||||
* numlock On,
|
||||
* capslock Off,
|
||||
* scrolllock Off ;
|
||||
* scrolllock Off ;
|
||||
|
||||
Après avoir exécuté le script, nous devrions avoir :
|
||||
|
||||
|
@ -242,7 +242,8 @@ Voici un exemple d'utilisation :
|
|||
</div>
|
||||
|
||||
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}
|
||||
Attention au fuseau horaire utilisé par votre RTC, si votre système principal
|
||||
|
|
|
@ -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
|
||||
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
|
||||
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.
|
||||
|
||||
*Seccomp* est particulièrement utile lorsqu'un processus a terminé son
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
|
@ -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)`.
|
||||
|
||||
Historiquement, avant la création de l'appel système `seccomp(2)`, on activait
|
||||
ce mode via :
|
||||
ce mode via :
|
||||
|
||||
<div lang="en-US">
|
||||
```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
|
||||
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">
|
||||
```c
|
||||
|
@ -79,7 +79,7 @@ seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
|
|||
|
||||
### 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">
|
||||
```
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
\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
|
||||
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
|
||||
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">
|
||||
```
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
\newpage
|
||||
|
||||
Exercice : `docker exec`
|
||||
Exercice : `docker exec`
|
||||
------------------------
|
||||
|
||||
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)`.
|
||||
|
||||
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` ;
|
||||
- `hostname` ;
|
||||
- `mount` ;
|
||||
- `pa -aux` ;
|
||||
- `ip address` ;
|
||||
- `hostname` ;
|
||||
- `mount` ;
|
||||
- `ps -aux` ;
|
||||
- ...
|
||||
|
||||
|
||||
|
@ -27,11 +27,11 @@ d63ceae863956f8312aca60b7a57fbcc1fdf679ae4c90c5d9455405005d4980a
|
|||
234269
|
||||
|
||||
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
|
||||
inet 127.0.0.1/8 scope host lo
|
||||
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
|
||||
inet 172.17.0.1/16 scope global eth0
|
||||
valid_lft forever preferred_lft forever
|
||||
|
|
|
@ -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.
|
||||
|
||||
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">
|
||||
```
|
||||
|
@ -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
|
||||
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
|
||||
sont passés :
|
||||
sont passés :
|
||||
|
||||
* `CLONE_NEWNS`,
|
||||
* `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
|
||||
noms réseau et dans un nouveau *namespace* `cgroup`, on écrirait un code C
|
||||
semblable à :
|
||||
semblable à :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
|
@ -118,7 +118,7 @@ dans un nouvel espace de noms. Dans ce cas, on utilisera l'appel système
|
|||
|
||||
::::: {.warning}
|
||||
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
|
||||
son *namespace* *Time* ou *PID* d'origine, seuls ses enfants (après un appel à
|
||||
|
|
|
@ -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
|
||||
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`.
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
é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.
|
||||
|
||||
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
|
||||
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, 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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
des sous-groupes parents (pouvant laisser fuiter des informations sur le reste
|
||||
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.
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ de processus qui l'utilisent. C'est-à-dire que, la plupart du temps, le
|
|||
termine.
|
||||
|
||||
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">
|
||||
```bash
|
||||
|
@ -29,7 +29,7 @@ obtenir un descripteur de fichier valide vers le *namespace* (pour passer à
|
|||
|
||||
|
||||
::::: {.question}
|
||||
#### Faire persister un *namespace* ? {-}
|
||||
#### Faire persister un *namespace* ? {-}
|
||||
\
|
||||
|
||||
Il n'est pas possible de faire persister un espace de noms d'un reboot à
|
||||
|
|
|
@ -6,7 +6,7 @@ Le *namespace* `mount`
|
|||
L'espace de noms `mount` permet d'isoler la vision du système de fichiers
|
||||
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}
|
||||
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
|
||||
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
|
||||
l'arborescence\ !
|
||||
l'arborescence !
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
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">
|
||||
```bash
|
||||
|
@ -61,32 +61,31 @@ Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs`
|
|||
```
|
||||
</div>
|
||||
|
||||
Placez ensuite dans cette nouvelle racine le système de votre choix (cf. le TP
|
||||
précédent pour les différentes méthodes et liens).
|
||||
Placez ensuite dans cette nouvelle racine le système de votre choix.
|
||||
|
||||
|
||||
### 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
|
||||
nouvelle racine ;
|
||||
3. `pivot_root` !
|
||||
nouvelle racine ;
|
||||
3. `pivot_root` !
|
||||
|
||||
|
||||
#### S'isoler\
|
||||
|
||||
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 PIDs : car on ne pourra pas démonter une partition en cours
|
||||
* les points de montages, ça semble évident ;
|
||||
* 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
|
||||
empêcher de démonter une partition !
|
||||
empêcher de démonter une partition !
|
||||
* les autres *namespaces* ne sont pas forcément nécessaires.
|
||||
|
||||
Isolons-nous :
|
||||
Isolons-nous :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -97,12 +96,12 @@ Isolons-nous :
|
|||
|
||||
#### 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
|
||||
mount*.
|
||||
|
||||
Commençons donc par étiqueter tous nos points de montage (de ce *namespace*),
|
||||
comme esclaves :
|
||||
comme esclaves :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -111,15 +110,15 @@ comme esclaves :
|
|||
</div>
|
||||
|
||||
|
||||
#### Démonter tout !\
|
||||
#### Démonter tout !\
|
||||
|
||||
À 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
|
||||
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é
|
||||
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 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.
|
||||
|
||||
Pour lancer la première commande dans la nouvelle racine, on passe généralement
|
||||
par :
|
||||
par :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
|
@ -4,7 +4,7 @@ Je vous recommande la lecture du *man* `namespaces(7)` introduisant et
|
|||
énumérant les *namespaces*.
|
||||
|
||||
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`
|
||||
*namespace*](https://lwn.net/Articles/621006/) et [le petit dernier sur le
|
||||
*namespace* `time`](https://lwn.net/Articles/766089/).
|
||||
|
|
|
@ -6,11 +6,11 @@ Le *namespace* `network` {#net-ns}
|
|||
### Introduction
|
||||
|
||||
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.
|
||||
|
||||
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">
|
||||
```
|
||||
|
@ -25,7 +25,7 @@ environnement principal, il s'agit bien de deux interfaces isolées l'une de
|
|||
l'autre.
|
||||
|
||||
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
|
||||
autre espace de noms.
|
||||
|
||||
|
@ -33,9 +33,9 @@ autre espace de noms.
|
|||
### Premiers pas avec `ip netns`
|
||||
|
||||
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">
|
||||
```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
|
||||
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
|
||||
malgré le fait que plus aucun processus ne s'y exécute.
|
||||
|
||||
Maintenant que notre *namespace* est créé, nous pouvons regarder s'il contient
|
||||
des interfaces :
|
||||
des interfaces :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
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
|
||||
```
|
||||
</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.
|
||||
|
||||
D'ailleurs, cette interface est rapportée comme étant désactivée, activons-là
|
||||
via la commande :
|
||||
via la commande :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -92,7 +92,7 @@ interface physique par conteneur, d'autant plus si l'on a plusieurs
|
|||
centaines de conteneurs à gérer.
|
||||
|
||||
Une technique couramment employée consiste à créer une interface virtuelle de
|
||||
type `veth` :
|
||||
type `veth` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -100,16 +100,16 @@ type `veth` :
|
|||
```
|
||||
</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
|
||||
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`.
|
||||
|
||||
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
|
||||
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">
|
||||
```bash
|
||||
|
@ -117,7 +117,7 @@ Pour déplacer `veth1` dans notre *namespace* `virli` :
|
|||
```
|
||||
</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">
|
||||
```bash
|
||||
|
@ -126,7 +126,7 @@ Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces :
|
|||
```
|
||||
</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
|
||||
vethX up`.
|
||||
|
@ -140,7 +140,7 @@ Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité :
|
|||
</div>
|
||||
|
||||
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
|
||||
|
@ -171,9 +171,9 @@ derrière notre machine.
|
|||
<!-- https://hicu.be/bridge-vs-macvlan -->
|
||||
|
||||
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
|
||||
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 à
|
||||
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
|
||||
[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">
|
||||
```
|
||||
|
@ -217,11 +217,11 @@ conteneur de la même machine.
|
|||
##### *Bridge*
|
||||
|
||||
À 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é à
|
||||
l'interface MACVLAN correspondante ; dans le cas contraire, le paquet est
|
||||
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
|
||||
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">
|
||||
```
|
||||
|
@ -233,9 +233,9 @@ Pour construire une nouvelle interface de ce type :
|
|||
### Aller plus loin {-}
|
||||
|
||||
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).
|
||||
|
||||
Appliqué à Docker, vous apprécierez cet article : [Understanding Docker
|
||||
Appliqué à Docker, vous apprécierez cet article : [Understanding Docker
|
||||
Networking Drivers and their use
|
||||
cases](https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/).
|
||||
|
|
|
@ -18,9 +18,9 @@ pas de PID en cours de route, puisqu'il dépend du *namespace* dans lequel il se
|
|||
trouve.
|
||||
|
||||
|
||||
### Isolons !
|
||||
### Isolons !
|
||||
|
||||
Première étape s'isoler :
|
||||
Première étape s'isoler :
|
||||
|
||||
<div lang="en-US">
|
||||
```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é.
|
||||
|
||||
|
||||
#### 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">
|
||||
```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*
|
||||
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
@ -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.
|
||||
|
||||
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.
|
||||
|
||||
[^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
|
||||
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
|
||||
propriété définie.
|
||||
|
||||
|
@ -104,4 +104,4 @@ l'intérieur pour conserver un comportement cohérent.
|
|||
### Aller plus loin {-}
|
||||
|
||||
N'hésitez pas à jeter un œil à la page de manuel consacrée à cet espace de
|
||||
noms : `pid_namespaces(7)`.
|
||||
noms : `pid_namespaces(7)`.
|
||||
|
|
|
@ -9,7 +9,7 @@ Projet et rendu
|
|||
notation de ce cours.**
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
plomberie, n'hésitez pas à l'utiliser !
|
||||
plomberie, n'hésitez pas à l'utiliser !
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
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).
|
||||
|
||||
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
|
||||
fichiers supplémentaires associés au langage que vous aurez choisi
|
||||
pour chaque exercice) :
|
||||
pour chaque exercice) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#### Exemple C\
|
||||
|
||||
Voici un exemple de code C utilisant `setns(2)` :
|
||||
Voici un exemple de code C utilisant `setns(2)` :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
|
@ -38,7 +38,7 @@ main(int argc, char *argv[])
|
|||
|
||||
#### Exemple shell\
|
||||
|
||||
Dans un shell, on utilisera la commande `nsenter(1)` :
|
||||
Dans un shell, on utilisera la commande `nsenter(1)` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
|
@ -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.
|
||||
|
||||
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">
|
||||
```bash
|
||||
|
@ -52,7 +52,7 @@ On ne peut pas afficher tel quel les structures, mais on peut l'ouvrir avec
|
|||
`setns(2)`.
|
||||
|
||||
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`\
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
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é
|
||||
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">
|
||||
```
|
||||
|
@ -28,7 +28,7 @@ Device Drivers --->
|
|||
```
|
||||
</div>
|
||||
|
||||
Les variables de configuration correspondantes sont :
|
||||
Les variables de configuration correspondantes sont :
|
||||
|
||||
<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
|
||||
[`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`
|
||||
* `procps`
|
||||
* `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`
|
||||
* `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é,
|
||||
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/) ;
|
||||
* [Anatomy of a user namespaces vulnerability](https://lwn.net/Articles/543273/) ;
|
||||
* <http://marc.info/?l=linux-kernel&m=135543612731939&w=2> ;
|
||||
* [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/) ;
|
||||
* <http://marc.info/?l=linux-kernel&m=135543612731939&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 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
|
||||
adapter le comportement.
|
||||
|
@ -99,7 +99,7 @@ adapter le comportement.
|
|||
##### Debian et ses dérivées {.unnumbered}
|
||||
|
||||
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">
|
||||
```bash
|
||||
|
|
|
@ -23,7 +23,7 @@ utilisateur, on obtient les privilèges requis pour créer tous les autres types
|
|||
de *namespaces*.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
||||
#### L'utilisateur -2 : *nobody*\
|
||||
#### L'utilisateur -2 : *nobody*\
|
||||
|
||||
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,
|
||||
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*.
|
||||
|
||||
-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`\
|
||||
|
||||
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
|
||||
en question.
|
||||
|
@ -62,7 +62,7 @@ Sur chaque ligne, on doit indiquer :
|
|||
- 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">
|
||||
```
|
||||
|
@ -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 à
|
||||
`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">
|
||||
```
|
||||
|
@ -99,18 +99,18 @@ des groupes au lieu des utilisateurs.
|
|||
|
||||
<div lang="en-US">
|
||||
```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>
|
||||
|
||||
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
|
||||
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
|
||||
pouvoir y faire ce que l'on veut, tant que l'on n'agit pas en dehors.
|
||||
|
||||
|
||||
### 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)`.
|
||||
|
|
|
@ -2,7 +2,9 @@ include ../pandoc-opts.mk
|
|||
|
||||
SOURCES_SRS = tutorial-srs.md \
|
||||
../devops/devops.md \
|
||||
../devops/what.md \
|
||||
../devops/what-srs.md \
|
||||
../devops/what-ansible.md \
|
||||
../devops/what-hosts.md \
|
||||
../devops/tools.md \
|
||||
../devops/tools-gitea.md \
|
||||
../devops/tools-gitea-ansible.md \
|
||||
|
@ -12,6 +14,7 @@ SOURCES_SRS = tutorial-srs.md \
|
|||
../devops/tools-drone-oauth.md \
|
||||
../devops/tools-drone-runner.md \
|
||||
../devops/tools-drone-runner-ansible.md \
|
||||
../devops/tools-drone-runner-end.md \
|
||||
../devops/tools-end.md \
|
||||
../devops/ci.md \
|
||||
../devops/publish-docker.md \
|
||||
|
@ -19,6 +22,8 @@ SOURCES_SRS = tutorial-srs.md \
|
|||
|
||||
SOURCES_GISTRE = tutorial-gistre.md \
|
||||
../devops/what-gistre.md \
|
||||
../devops/what-cmd.md \
|
||||
../devops/what-hosts.md \
|
||||
../devops/what-gistre-see-srs.md \
|
||||
../devops/tools.md \
|
||||
../devops/tools-gitea.md \
|
||||
|
@ -29,6 +34,7 @@ SOURCES_GISTRE = tutorial-gistre.md \
|
|||
../devops/tools-drone-oauth.md \
|
||||
../devops/tools-drone-runner.md \
|
||||
../devops/tools-drone-runner-cmd.md \
|
||||
../devops/tools-drone-runner-end.md \
|
||||
../devops/tools-end.md \
|
||||
../devops/ci-gistre.md \
|
||||
../devops/run-gistre.md \
|
||||
|
|
|
@ -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, ...).
|
||||
|
||||
Voici une arborescence type (vous pourriez avoir des fichiers
|
||||
supplémentaires) :
|
||||
supplémentaires) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
@ -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, ...).
|
||||
|
||||
Voici une arborescence type (vous pourriez avoir des fichiers
|
||||
supplémentaires) :
|
||||
supplémentaires) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
@ -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, ...).
|
||||
|
||||
Voici une arborescence type (vous pourriez avoir des fichiers
|
||||
supplémentaires) :
|
||||
supplémentaires) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
---
|
||||
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}
|
||||
institute: EPITA
|
||||
date: Jeudi 4 novembre 2021
|
||||
abstract: |
|
||||
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
|
||||
déploiement !
|
||||
déploiement !
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ institute: EPITA
|
|||
date: Jeudi 4 novembre 2021
|
||||
abstract: |
|
||||
Durant ce nouveau TP, nous allons jouer les DevOps et déployer
|
||||
automatiquement des services !
|
||||
automatiquement des services !
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ institute: EPITA
|
|||
date: Jeudi 4 novembre 2021
|
||||
abstract: |
|
||||
Durant ce nouveau TP, nous allons jouer les DevOps et déployer
|
||||
automatiquement des services !
|
||||
automatiquement des services !
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ function Div(el)
|
|||
-- insert element in front
|
||||
table.insert(
|
||||
el.content, 1,
|
||||
pandoc.RawBlock("latex", "\\begin{alertbox}"))
|
||||
pandoc.RawBlock("latex", "\\noindent\\begin{alertbox}"))
|
||||
-- insert element at the back
|
||||
table.insert(
|
||||
el.content,
|
||||
|
@ -15,7 +15,7 @@ function Div(el)
|
|||
-- insert element in front
|
||||
table.insert(
|
||||
el.content, 1,
|
||||
pandoc.RawBlock("latex", "\\begin{codebox}"))
|
||||
pandoc.RawBlock("latex", "\\noindent\\begin{codebox}"))
|
||||
-- insert element at the back
|
||||
table.insert(
|
||||
el.content,
|
||||
|
@ -26,7 +26,7 @@ function Div(el)
|
|||
-- insert element in front
|
||||
table.insert(
|
||||
el.content, 1,
|
||||
pandoc.RawBlock("latex", "\\begin{questionbox}"))
|
||||
pandoc.RawBlock("latex", "\\noindent\\begin{questionbox}"))
|
||||
-- insert element at the back
|
||||
table.insert(
|
||||
el.content,
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
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 ?
|
||||
|
|
|
@ -21,11 +21,11 @@ configuration des dépôts.
|
|||
:::::
|
||||
|
||||
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`
|
||||
|
||||
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,
|
||||
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.
|
||||
|
||||
::::: {.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é
|
||||
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
|
||||
votre situation !
|
||||
documentation** ! Le fichier présent sur le dépôt **ne fonctionnera pas** dans
|
||||
votre situation !
|
||||
:::::
|
||||
|
||||
{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
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Vous aurez sans doute besoin de :
|
||||
Vous aurez sans doute besoin de :
|
||||
|
||||
- <https://docs.drone.io/pipeline/conditions/>
|
||||
- <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 !
|
||||
|
||||
{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
|
||||
architectures matérielles qu'il supporte, nous pouvons donc aisément faire de
|
||||
la compilation croisée pour d'autres architectures.
|
||||
|
||||
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/>.
|
||||
|
||||
En faisant varier `$GOARCH` en `mips`, `powerpc`, ... nous pouvons générer les
|
||||
|
|
|
@ -3,24 +3,26 @@
|
|||
## Intégration continue
|
||||
|
||||
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`
|
||||
|
||||
Reprenez les travaux réalisés au TP précédent. Nous allons notamment avoir
|
||||
besoin du `Dockerfile` dans la section suivante.
|
||||
Reprenez les travaux déjà réalisés : nous allons notamment avoir besoin du
|
||||
`Dockerfile` que nous avons réalisé pour ce projet `youp0m`.
|
||||
|
||||
Après avoir créé (ou migré pour les plus malins !) le dépôt
|
||||
[`youp0m`](https://git.nemunai.re/nemunaire/youp0m) dans Drone,
|
||||
synchronisez les dépôts, puis activez la surveillance de `youp0m`.
|
||||
Après avoir créé (ou migré pour les plus malins !) le dépôt
|
||||
`youp0m`[^urlyoup0m] dans gitea, synchronisez les dépôts dans Drone, puis
|
||||
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
|
||||
compiler et tester le projet.
|
||||
|
||||
::::: {.warning}
|
||||
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
|
||||
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 dans votre
|
||||
installation.
|
||||
|
||||
**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
|
||||
|
||||
Toutes les informations nécessaires à l'écriture du fichier `.drone.yml` se
|
||||
trouvent dans [l'excellente documentation du
|
||||
projet](https://docs.drone.io/pipeline/docker/examples/languages/golang/).
|
||||
trouvent dans l'excellente documentation du projet :\
|
||||
<https://docs.drone.io/pipeline/docker/examples/languages/golang/>.
|
||||
|
||||
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
|
||||
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.
|
|||
{height=6cm}
|
||||
|
||||
::::: {.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é
|
||||
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
|
||||
votre situation !
|
||||
documentation** ! Le fichier présent sur le dépôt **ne fonctionnera pas** dans
|
||||
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é
|
||||
|
||||
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 à
|
||||
votre playbook !) :
|
||||
Tout d'abord, il faut lancer le conteneur Sonarqube :
|
||||
|
||||
<div lang="en-US">
|
||||
```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>.
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Vous aurez sans doute besoin de :
|
||||
Vous aurez sans doute besoin de :
|
||||
|
||||
- <https://docs.drone.io/pipeline/conditions/>
|
||||
- <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 !
|
||||
|
||||
{height=8cm}
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@ Le mouvement DevOps
|
|||
===================
|
||||
|
||||
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,
|
||||
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
|
||||
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
|
||||
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
|
||||
|
@ -19,13 +19,13 @@ pâtissent).
|
|||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
langage, mais les administrateurs système n'ont alors pas de paquets stables
|
||||
dans la distribution. En effet, les distributions stables telles que Debian,
|
||||
|
@ -64,10 +64,10 @@ charges, les pannes, ...
|
|||
|
||||
::::: {.warning}
|
||||
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
|
||||
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
|
||||
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 à
|
||||
|
@ -77,14 +77,14 @@ faire du DevOps.
|
|||
|
||||
## 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
s'agira de mettre à jour le service.
|
||||
|
||||
Parfois les deux seront à faire : à la fois publier un paquet ou un
|
||||
conteneur et mettre à jour un service en ligne : par exemple, [le
|
||||
Parfois les deux seront à faire : à la fois publier un paquet ou un
|
||||
conteneur et mettre à jour un service en ligne : par exemple, [le
|
||||
serveur Synapse](https://buildkite.com/matrix-dot-org/synapse) du
|
||||
protocole de messagerie Matrix ou encore
|
||||
[Gitlab](https://gitlab.com/gitlab-org/gitlab/-/pipelines), tous deux
|
||||
publient des paquets à destination de leurs communautés, et mettent à
|
||||
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
|
||||
l'ancien service et démarrer le nouveau, si ça prend quelques millisecondes en
|
||||
é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é
|
||||
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 à
|
||||
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
|
||||
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
|
||||
section suivante !) soient constantes.
|
||||
section suivante !) soient constantes.
|
||||
|
||||
|
||||
## 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
|
||||
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
|
||||
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
|
||||
conteneurs TICK. Nous n'allons donc pas nous en occuper aujourd'hui.
|
||||
\
|
||||
|
||||
Notez tout de même qu'il y a deux grandes catégories de logiciels de
|
||||
supervision :
|
||||
supervision :
|
||||
|
||||
**Basée sur des états** comme Nagios, Zabbix, ... : ces logiciels vont
|
||||
**Basée sur des états** comme Nagios, Zabbix, ... : ces logiciels vont
|
||||
simplement réaliser des séries de tests définis, à intervalles réguliers et
|
||||
contacter l'administrateur d'astreinte dès qu'un test ne passe plus de manière
|
||||
persistante.
|
||||
|
@ -163,8 +163,8 @@ Il y a rarement beaucoup d'intelligence ou d'anticipation automatique dans ces
|
|||
outils.
|
||||
\
|
||||
|
||||
**Basée sur les métriques** comme ELK, Prometheus, InfluxDB, ... : dans la
|
||||
stack TICK que nous avons mis en place au précédent TP, nous avions placé un
|
||||
**Basée sur les métriques** comme ELK, Prometheus, InfluxDB, ... : dans la
|
||||
stack TICK que nous avons mis en place précédemment, nous avions placé un
|
||||
agent sur la machine que nous souhaitions analyser. Outre les graphiques
|
||||
présenté dans Chronograf, le dernier outil que l'on n'avait pas configuré était
|
||||
Kapacitor, qui permet après avoir analysé les données, d'alerter en fonction
|
||||
|
@ -196,4 +196,4 @@ des pannes, des latences, ... à n'importe quel niveau du produit, afin d'en
|
|||
tester (brulatement certes) sa résilience. Cela oblige les développeurs, les
|
||||
opérationnels et les architectes à concevoir des services hautement tolérant
|
||||
aux pannes, ce qui fait que le jour où une véritable panne survient, elle n'a
|
||||
aucun impact sur la production (enfin on espère !).
|
||||
aucun impact sur la production (enfin on espère !).
|
||||
|
|
|
@ -7,13 +7,12 @@ Toutes les tâches de publication peuvent s'assimiler à des tâches de
|
|||
déploiement continu. C'est en particulier le cas lorsque le produit de
|
||||
compilation sera simplement publié et qu'il n'y a pas de service à mettre à
|
||||
jour ensuite (par exemple, dans le cas de Firefox ou de LibreOffice, une fois
|
||||
testés, les paquets sont envoyés sur le serveur d'où ils seront distribués ; il
|
||||
testés, les paquets sont envoyés sur le serveur d'où ils seront distribués ; il
|
||||
n'y a pas de service/docker à relancer).
|
||||
|
||||
À l'inverse, `youp0m` ou `linky2influx` sont à la fois des programmes que l'on
|
||||
peut télécharger et des services qu'il faut déployer pour les mettre à
|
||||
jour. Pour simplifier le déploiement, nous utilisons des images Docker. Il faut
|
||||
cependant les générer ...
|
||||
À l'inverse, `youp0m` est à la fois un programme que l'on peut télécharger et
|
||||
un service qu'il faut déployer pour le mettre à jour. Pour simplifier le
|
||||
déploiement, nous utilisons une image Docker. Il faut cependant la générer ...
|
||||
|
||||
|
||||
## Mise en place du registre
|
||||
|
@ -25,7 +24,7 @@ Docker intégré. Si vous utilisez Gitea, continuez cette section.
|
|||
|
||||
Afin de disposer de notre propre registre Docker sur lequel publier nos images,
|
||||
nous allons utiliser l'image de registre fournie par Docker. Elle se lance
|
||||
comme suit :
|
||||
comme suit :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -37,7 +36,7 @@ Vous trouverez davantage d'informations pour le déploiement
|
|||
[ici](https://docs.docker.com/registry/deploying/).
|
||||
|
||||
Nous pouvons tester le bon fonctionnement de notre registre avec la commande
|
||||
suivante :
|
||||
suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -50,7 +49,7 @@ suivante :
|
|||
## Publication de l'image
|
||||
|
||||
Une fois le registre démarré, il ne nous reste plus qu'à ajouter une étape de
|
||||
publication de l'image Docker. Cela se fait au moyen du plugin suivant :
|
||||
publication de l'image Docker. Cela se fait au moyen du plugin suivant :\
|
||||
<http://plugins.drone.io/drone-plugins/drone-docker/>.
|
||||
|
||||
Sans plus de configuration, le registre que nous avons démarré
|
||||
|
@ -62,7 +61,7 @@ pour utiliser `https`, il est nécessaire de définir l'option
|
|||
## Test de l'image
|
||||
|
||||
Sur l'hôte, nous pouvons tester que l'image a bien été publiée grâce à la
|
||||
commande suivante :
|
||||
commande suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -92,8 +91,8 @@ une machine virtuelle avec une connexion SSH. N'hésitez pas à l'ajouter à vot
|
|||
`.droneci.yml`.
|
||||
|
||||
|
||||
## Profitons !
|
||||
## Profitons !
|
||||
|
||||
Sonarqube a repéré quelques erreurs dans le code de `youp0m`, essayez de les
|
||||
corriger, et publiez une nouvelle version, pour observer toute la chaîne en
|
||||
action !
|
||||
action !
|
||||
|
|
|
@ -6,7 +6,7 @@ Mettons de côté le déploiement continu, pour nous concentrer sur la manière
|
|||
dont nous allons pouvoir exécuter notre module de relevé de compteur Linky.
|
||||
\
|
||||
|
||||
Le binaire de notre module se lance de la manière suivante :
|
||||
Le binaire de notre module se lance de la manière suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
|
@ -35,7 +35,7 @@ retient votre attention.
|
|||
Vous êtes tenu de retenir au minimum 2 solutions distinctes (on considère que
|
||||
les technologies listées sur la même lignes sont similaires).
|
||||
|
||||
La liste de technologies proposées est à la suivante :
|
||||
La liste de technologies proposées est à la suivante :
|
||||
|
||||
- conteneur Docker ou podman,
|
||||
- conteneur LXC (avec base alpine ou nu),
|
||||
|
@ -83,7 +83,7 @@ login_x-TP5/lxc/run.sh
|
|||
</div>
|
||||
|
||||
En complément, vous pouvez inclure au dépôt de `linky2influx` le modèle
|
||||
permettant de créer le conteneur LXC, ainsi qu'un exemple de configuration :
|
||||
permettant de créer le conteneur LXC, ainsi qu'un exemple de configuration :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -107,7 +107,7 @@ vous pourriez écrire le script `systemd` et profiter de l'utiliser dans votre
|
|||
recette `bitbake`.
|
||||
|
||||
Un service basé sur `nspawn` peut par contre être potentiellement intéressant,
|
||||
il pourra être intégré au dépôt :
|
||||
il pourra être intégré au dépôt :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -121,7 +121,7 @@ login_x-TP5/linky2influx/systemd/linky2influx.nspawn
|
|||
Vous pourriez vouloir écrire une recette Bitbake pour créer et déployer le
|
||||
module via un paquet `.ipk` ou similaire en fonction de votre configuration.
|
||||
|
||||
Écrivez la recette au sein de `meta-electropcool` :
|
||||
Écrivez la recette au sein de `meta-electropcool` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -146,7 +146,7 @@ utiliser le package Nix ensuite.
|
|||
|
||||
### Snap, Flatpack, AppImage
|
||||
|
||||
Intégrez au dépôt le fichier de description, par exemple :
|
||||
Intégrez au dépôt le fichier de description, par exemple :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -155,7 +155,7 @@ login_x-TP5/linky2influx/snapcraft.yaml
|
|||
</div>
|
||||
|
||||
Il faudra également préciser avec un fichier `run.sh` la manière dont lancer
|
||||
votre conteneur :
|
||||
votre conteneur :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -168,7 +168,7 @@ login_x-TP5/{snap,flatpack}/run.sh
|
|||
### k3s
|
||||
|
||||
Nous en apprendrons davantage sur Kubernetes au prochain TP, mais si vous
|
||||
connaissez déjà, vous pourriez vouloir écrire un *Chart* Helm :
|
||||
connaissez déjà, vous pourriez vouloir écrire un *Chart* Helm :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -176,7 +176,7 @@ login_x-TP5/k3s/linky2influx.yaml
|
|||
```
|
||||
</div>
|
||||
|
||||
Inutile de vous casser la tête avec ça si vous ne connaissez pas !
|
||||
Inutile de vous casser la tête avec ça si vous ne connaissez pas !
|
||||
|
||||
|
||||
### Votre solution
|
||||
|
@ -191,4 +191,4 @@ login_x-TP5/k3s/linky2influx.yaml
|
|||
</div>
|
||||
\
|
||||
|
||||
À vous de jouer !
|
||||
À vous de jouer !
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Voici à quoi pourrait ressembler le playbook Ansible démarrant notre conteneur
|
||||
Drone :
|
||||
Drone :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
|
|
|
@ -1,26 +1,36 @@
|
|||
Voici à quoi pourrait ressembler la ligne de commande démarrant notre conteneur
|
||||
Drone :
|
||||
Tout comme Gitea, Drone tire un certain nombre de paramètres depuis son
|
||||
environnement. Nous allons donc commencer par indiquer l'identifiant et le
|
||||
secret de l'application que l'on a créé précédemment dans Gitea :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
export DRONE_GITEA_CLIENT_ID=#FIXME
|
||||
export DRONE_GITEA_CLIENT_SECRET=#FIXME
|
||||
export DRONE_RPC_SECRET=$(openssl rand -base64 30)
|
||||
|
||||
docker container run --name droneci -d \
|
||||
-v /var/lib/drone:/data \
|
||||
--network gitea -p 80:80 \
|
||||
-e DRONE_GITEA_CLIENT_ID -e DRONE_GITEA_CLIENT_SECRET -e DRONE_GITEA_SERVER=http://gitea:3000 \
|
||||
-e DRONE_RPC_SECRET -e DRONE_SERVER_HOST=droneci -e DRONE_SERVER_PROTO=http \
|
||||
drone/drone:1
|
||||
|
||||
docker network connect drone droneci
|
||||
```
|
||||
</div>
|
||||
|
||||
La dernière commande permet à notre conteneur Drone d'être à la fois présent
|
||||
dans le réseau `gitea` et `drone`, ce qui permet de garder les deux réseaux
|
||||
distincts.
|
||||
Puis, tout comme pour Gitea, nous allons générer un secret. Ce secret est
|
||||
utilisé par les différents *worker*s pour s'authentifier :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
export DRONE_RPC_SECRET=$(openssl rand -base64 30)
|
||||
```
|
||||
</div>
|
||||
|
||||
Lançons enfin Drone avec les deux commandes suivantes :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
docker volume create drone_data
|
||||
|
||||
docker container run --name droneci -d -v drone_data:/data --network my_ci_net
|
||||
-p 80:80 -e DRONE_GITEA_CLIENT_ID -e DRONE_GITEA_CLIENT_SECRET \
|
||||
-e DRONE_GITEA_SERVER=http://gitea:3000 -e DRONE_SERVER_PROTO=http \
|
||||
-e DRONE_RPC_SECRET -e DRONE_SERVER_HOST=droneci \
|
||||
drone/drone:2
|
||||
```
|
||||
</div>
|
||||
|
||||
Gardez la variable d'environnement `DRONE_RPC_SECRET` dans un coin, nous en
|
||||
aurons encore besoin juste après.
|
||||
|
|
|
@ -1,15 +1,7 @@
|
|||
::::: {.question}
|
||||
|
||||
La version 2 de Drone, encore plus pratique et sympathique est disponible en
|
||||
test. Vous pouvez tout à fait l'utiliser pour la suite du TP. Cela ne change
|
||||
pas la version des *runners* à utiliser.
|
||||
|
||||
:::::
|
||||
|
||||
Une fois lancé, rendez-vous sur l'interface de DroneCI : <http://droneci/>
|
||||
Une fois lancé, rendez-vous sur l'interface de DroneCI : <http://droneci/>
|
||||
|
||||
Vous serez automatiquement redirigé vers la page d'authentification de Gitea,
|
||||
puis vers l'autorisation OAuth d'accès de Drone à Gitea. Il faut bien
|
||||
évidemment valider cette demande, afin que Drone ait accès à nos dépôts.
|
||||
|
||||
{width=9cm}
|
||||
{width=9cm}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Voici à quoi pourrait ressembler le playbook Ansible démarrant notre agent Drone :
|
||||
Voici à quoi pourrait ressembler le playbook Ansible démarrant notre agent Drone :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
Voici à quoi pourrait ressembler la ligne de commande démarrant notre agent Drone :
|
||||
\
|
||||
|
||||
Voici La ligne de commande permettant de démarrer notre agent :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
docker container run --name droneci-runner -d \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock --network drone \
|
||||
-e DRONE_RPC_PROTO=http -e DRONE_RPC_HOST=droneci -e DRONE_RPC_SECRET \
|
||||
-e DRONE_RUNNER_CAPACITY=2 -e DRONE_RUNNER_NAME=my-runner -e DRONE_RUNNER_NETWORKS=drone,gitea \
|
||||
docker container run --name droneci-runner -d --network my_ci_net \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock -e DRONE_RPC_PROTO=http
|
||||
-e DRONE_RPC_HOST=droneci -e DRONE_RPC_SECRET -e DRONE_RUNNER_CAPACITY=2 \
|
||||
-e DRONE_RUNNER_NAME=my-runner -e DRONE_RUNNER_NETWORKS=my_ci_net \
|
||||
drone/drone-runner-docker:1
|
||||
```
|
||||
</div>
|
||||
|
|
9
tutorial/devops/tools-drone-runner-end.md
Normal file
9
tutorial/devops/tools-drone-runner-end.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
::::: {.more}
|
||||
|
||||
On remarquera que l'on partage notre socket Docker : l'exécution de code
|
||||
arbitraire n'aura pas lieu directement dans le conteneur, en fait il s'agit
|
||||
d'un petit orchetrateur qui lancera d'autres conteneurs en fonction des tâches
|
||||
qu'on lui demandera. Le code arbitraire sera donc toujours exécuté dans un
|
||||
conteneur moins privilégié.
|
||||
|
||||
:::::
|
|
@ -2,14 +2,13 @@
|
|||
|
||||
Notre conteneur `droneci` est uniquement une interface graphique qui va
|
||||
centraliser d'un côté les nouveaux commits à traiter, et de l'autre les
|
||||
résultats retournés par les agents chargés d'exécuter le code.
|
||||
résultats retournés par les agents chargés d'exécuter les tâches.
|
||||
|
||||
Il serait impensable d'exécuter arbitrairement du code en parallèle d'une
|
||||
application privilégiée (ici, notre conteneur `droneci` a accès aux dépôts
|
||||
potentiellement privés de Gitea). Les agents qui sont amenés à traiter du code
|
||||
arbitraire s'exécutent à part et peuvent être de différents types. Dans le
|
||||
vocabulaire de Drone, on les appelle des ~~blade~~*runners*.
|
||||
arbitraire s'exécutent à part et peuvent être de différents types.
|
||||
|
||||
Nous allons lancer un *runner* Docker : il s'agit d'un type d'agent qui va
|
||||
Nous allons lancer un *runner* Docker : il s'agit d'un type d'agent qui va
|
||||
exécuter nos étapes de compilation dans des conteneurs Docker (oui, quand on
|
||||
disait que Drone était conçu autour de Docker, c'était pas pour rire !)
|
||||
disait que Drone était conçu autour de Docker, c'était pas pour rire !)
|
||||
|
|
|
@ -8,6 +8,10 @@ Mais nous allons déployer notre propre solution, en utilisant [Drone
|
|||
CI](https://drone.io/). C'est une solution d'intégration continue libre et
|
||||
moderne, conçue tout autour de Docker. Idéale pour nous !
|
||||
|
||||
Deux conteneurs sont à lancer : nous aurons d'un côté l'interface de contrôle
|
||||
et de l'autre un agent (*runner* dans le vocabulaire de Drone) chargé
|
||||
d'exécuter les tests. Dans un environnement de production, on aura généralement
|
||||
plusieurs agents, et ceux-ci seront situé sur des machines distinctes.
|
||||
|
||||
### Interface de contrôle et de dispatch des tâches
|
||||
|
||||
|
@ -19,6 +23,8 @@ Drone va avoir besoin d'authentifier les utilisateurs afin d'accéder aux dépô
|
|||
privés (avec l'autorisation des utilisateurs). Pour cela, comme l'indique la
|
||||
documentation de Drone, on va utiliser OAuth2 : dans Gitea, il va falloir créer
|
||||
une *application OAuth2*. Le formulaire de création se trouve dans la
|
||||
configuration du compte utilisateur, sous l'onglet *Applications*. Drone aura
|
||||
également besoin d'une URL de redirection. Dans notre cas, ce sera :
|
||||
configuration du compte utilisateur, sous l'onglet *Applications*.
|
||||
|
||||
Drone aura également besoin d'une URL de redirection. Dans notre cas,
|
||||
ce sera :\
|
||||
`http://droneci/login`.
|
||||
|
|
|
@ -1 +1 @@
|
|||
L'environnement étant prêt, il ne reste plus qu'à nous lancer dans nos projets !
|
||||
L'environnement étant prêt, il ne reste plus qu'à nous lancer dans nos projets !
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
Votre playbook ressemblera à quelque chose comme ça :
|
||||
Votre playbook ressemblera à quelque chose comme ça :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
- name: Launch gitea container
|
||||
- name: Create a volume for storing repositories
|
||||
docker_volume:
|
||||
name: gitea-data
|
||||
|
||||
- name: launch gitea container
|
||||
docker_container:
|
||||
name: gitea
|
||||
image: "gitea/gitea:{{ version }}"
|
||||
volumes:
|
||||
- /var/lib/gitea:/data
|
||||
- gitea-data:/data
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
state: started
|
||||
|
@ -27,3 +31,5 @@ Votre playbook ressemblera à quelque chose comme ça :
|
|||
SECRET_KEY: "{{ secret_key }}"
|
||||
```
|
||||
</div>
|
||||
|
||||
Plus d'infos sur cette page : <https://docs.gitea.io/en-us/install-with-docker/>.
|
||||
|
|
|
@ -1,13 +1,33 @@
|
|||
La ligne de commande pour lancer Gitea ressemblera à quelque chose comme ça :
|
||||
Commençons par créer un nouveau volume `gitea-data`, celui-ci contiendra
|
||||
les données de `gitea` (nos dépôts Git, mais également la configuration propre
|
||||
à `gitea`) :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
docker volume create gitea-data
|
||||
```
|
||||
</div>
|
||||
|
||||
Afin de simplifier l'installation de notre conteneur, nous allons utiliser un
|
||||
maximum de paramètres par défaut. Il faudra toutefois générer une clef secrète
|
||||
propre à l'installation. Puisque c'est temporaire, on peut se contenter de ne
|
||||
pas la stocker (elle sera perdue si on ferme notre terminal) :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
export SECRET_KEY=$(openssl rand -base64 30)
|
||||
```
|
||||
</div>
|
||||
|
||||
docker container run --name gitea -d \
|
||||
-v /var/lib/gitea:/data -v /etc/timezone:/etc/timezone:ro -v /etc/localtime:/etc/localtime:ro \
|
||||
--network gitea -p 2222:22 -p 3000:3000 \
|
||||
-e RUN_MODE=prod -e DOMAIN=gitea -e SSH_DOMAIN=gitea -e INSTALL_LOCK=true -e SECRET_KEY \
|
||||
Pour finir, lançons notre conteneur `gitea` :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
docker container run --name gitea --network my_ci_net -p 2222:22 -p 3000:3000 \
|
||||
-v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro \
|
||||
-v gitea-data:/data \
|
||||
-e RUN_MODE=prod -e DOMAIN=gitea -e SSH_DOMAIN=gitea -e INSTALL_LOCK=true \
|
||||
-e SECRET_KEY -d \
|
||||
gitea/gitea:1
|
||||
```
|
||||
</div>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
Plus d'infos sur cette page : <https://docs.gitea.io/en-us/install-with-docker/>.
|
||||
Une fois le conteneur lancé, vous pouvez accéder à l'interface de votre
|
||||
gestionnaire de versions sur le port 3000 de votre machine (à moins que vous
|
||||
n'ayez opté pour un autre port).
|
||||
\
|
||||
|
||||
Une fois le conteneur lancé, vous pouvez accéder à l'interface de gitea sur le
|
||||
port 3000 de votre machine (à moins que vous n'ayez opté pour un autre port).
|
||||
|
||||
Vous pouvez ajouter un nouvel administrateur avec la commande suivante :
|
||||
Vous pouvez ajouter un nouvel administrateur avec la commande suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker exec gitea gitea admin user create --username "${USER}" --random-password \
|
||||
--must-change-password=false --admin --email "${USER}@epita.fr"
|
||||
docker exec gitea gitea admin user create --username "${USER}" --admin \
|
||||
--must-change-password=false --random-password --email "${USER}@example.com"
|
||||
```
|
||||
</div>
|
||||
|
||||
Notez le mot de passe généré pour [vous y connecter](http://localhost:3000/user/login).
|
||||
Notez le mot de passe généré pour ensuite vous y connecter.
|
||||
|
|
|
@ -21,7 +21,7 @@ que l'on peut lier avec ses dépôts. Une fonctionnalité que GitLab propose
|
|||
En effet, la problématique du stockage des produits de compilation est
|
||||
vaste. Si au début on peut se satisfaire d'un simple serveur web/FTP/SSH pour
|
||||
les récupérer manuellement, on a vite envie de pouvoir utiliser les outils
|
||||
standards directement : `docker pull ...`, `npm install ...`, ...
|
||||
standards directement : `docker pull ...`, `npm install ...`, ...
|
||||
|
||||
Des programmes et services se sont spécialisés là-dedans, citons notamment
|
||||
[Artifactory](https://jfrog.com/artifactory/) ou [Nexus
|
||||
|
@ -33,11 +33,11 @@ Dans un premier temps, nous allons nous contenter de publier un binaire associé
|
|||
|
||||
### Installation et configuration
|
||||
|
||||
Allez c'est parti ! première chose à faire : installer et configurer
|
||||
Allez c'est parti ! première chose à faire : installer et configurer
|
||||
[Gitea](https://gitea.io/) (ceux qui le souhaitent peuvent choisir
|
||||
[gitlab](https://gitlab.org/) ou une autre plate-forme, mais la suite sera
|
||||
moins guidée).
|
||||
|
||||
Nous allons utiliser l'image :
|
||||
Nous allons utiliser l'image :
|
||||
[`gitea/gitea`](https://hub.docker.com/r/gitea/gitea) (ou
|
||||
[`gitlab/gitlab-ce`](https://hub.docker.com/r/gitlab/gitlab-ce)).
|
||||
|
|
16
tutorial/devops/what-ansible.md
Normal file
16
tutorial/devops/what-ansible.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
## Préparer le terrain
|
||||
|
||||
Tous les déploiements sont à faire sur votre machine en utilisant des
|
||||
conteneurs Docker, qui seront regroupés au sein de réseaux
|
||||
Docker. Cela vous permettra d’utiliser la résolution de noms entre vos
|
||||
conteneurs.
|
||||
|
||||
Dans votre playbook Ansible, vous pourrez procéder ainsi :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
- name: Create virli network
|
||||
docker_network:
|
||||
name: virli3
|
||||
```
|
||||
</div>
|
15
tutorial/devops/what-cmd.md
Normal file
15
tutorial/devops/what-cmd.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
## Préparer le terrain
|
||||
|
||||
Tous les déploiements sont à faire sur votre machine ; la plate-forme de CI
|
||||
utilisera massivement les conteneurs Docker, qui seront regroupés au sein de
|
||||
réseaux Docker : cela nous permettra de profiter de la résolution de noms entre
|
||||
les conteneurs.
|
||||
|
||||
Dès à présent, nous pouvons commencer par créer un réseau, dans lequel nous
|
||||
placerons tous nos conteneurs de CI/CD :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
docker network create my_ci_net
|
||||
```
|
||||
</div>
|
|
@ -3,7 +3,7 @@
|
|||
Électropcool
|
||||
============
|
||||
|
||||
Bienvenue dans la société Électropcool !
|
||||
Bienvenue dans la société Électropcool !
|
||||
|
||||
Électropcool est une société française spécialisée dans
|
||||
l'[immotique](https://fr.wikipedia.org/wiki/Immotique), elle vend des
|
||||
|
@ -20,14 +20,14 @@ en combustible (liés à la météo)[^HOMEASSISTANT].
|
|||
|
||||
[^HOMEASSISTANT]: Si ça vous met l'eau à la bouche, jettez un œil du côté du
|
||||
projet <https://www.home-assistant.io/> qui fait un peu moins de
|
||||
*bullshit*, mais est bien réel !
|
||||
*bullshit*, mais est bien réel !
|
||||
|
||||
La principale difficulté que rencontre Électropcool est qu'aucun bâtiment ne
|
||||
dispose des mêmes références de pièces et qu'en dehors des nouveaux bâtiments
|
||||
pour lesquels la société peut imposer des équipements électroniques
|
||||
spécifiquement supportés et compatibles avec la plate-forme qu'elle vend, il lui
|
||||
est bien souvent nécessaire de faire des développements spécifiques pour
|
||||
s'interfacer avec de l'électronique existant : c'est notamment le cas pour les
|
||||
s'interfacer avec de l'électronique existant : c'est notamment le cas pour les
|
||||
chaudières et les
|
||||
[VMC](https://fr.wikipedia.org/wiki/Ventilation_m%C3%A9canique_contr%C3%B4l%C3%A9e),
|
||||
qui, compte tenu de leur coût de remplacement prohibitif, nécessitent souvent
|
||||
|
@ -74,7 +74,7 @@ retiendrez.)
|
|||
\
|
||||
|
||||
Le projet qui vous servira de base pour vos tests sera
|
||||
[`linky2influx`](https://git.nemunai.re/nemunaire/linky2influx) : à partir d'un
|
||||
[`linky2influx`](https://git.nemunai.re/nemunaire/linky2influx) : à partir d'un
|
||||
compteur [Linky](https://fr.wikipedia.org/wiki/Linky), branché sur les bornes
|
||||
de [téléinformation client du
|
||||
compteur](https://hallard.me/demystifier-la-teleinfo/) et [lisant le
|
||||
|
@ -92,36 +92,3 @@ gestionnaire de versions.
|
|||
|
||||
Nous testerons enfin différentes solution pour déployer notre binaire, afin
|
||||
d'établir quelle est la solution adéquate.
|
||||
|
||||
|
||||
## Préparer le terrain
|
||||
|
||||
Tous les déploiements sont à faire sur votre machine et la plate-forme de CI
|
||||
utilisera massivement les conteneurs Docker, qui seront regroupés au sein de
|
||||
réseaux Docker. Cela vous permettra d'utiliser la résolution de noms entre vos
|
||||
conteneurs.
|
||||
|
||||
Vous devriez dès maintenant créer les deux réseaux suivants sur votre machines :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
docker network create gitea
|
||||
docker network create drone
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
Étant donné que votre machine ne dispose pas de domaine sur Internet et que
|
||||
l'on va essayer de simplifier au maximum l'installation, vous devriez ajouter
|
||||
cette ligne à votre fichier `/etc/hosts` (ou
|
||||
`\Windows\System32\drivers\etc\hosts`) :
|
||||
|
||||
<div lang="en-US">
|
||||
```conf
|
||||
127.0.0.1 gitea droneci
|
||||
```
|
||||
</div>
|
||||
|
||||
Cette ligne va vous permettre de résoudre les noms des conteneurs. Cela
|
||||
permettra aux requêtes OAuth de se faire de manière transparente pour vous
|
||||
lorsque vous serez dans votre navigateur.
|
||||
|
|
14
tutorial/devops/what-hosts.md
Normal file
14
tutorial/devops/what-hosts.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
Étant donné que votre machine ne dispose pas de domaine sur Internet et que
|
||||
l'on va essayer de simplifier au maximum l'installation, vous devriez ajouter
|
||||
cette ligne à votre fichier `/etc/hosts` (ou
|
||||
`\Windows\System32\drivers\etc\hosts`) :
|
||||
|
||||
<div lang="en-US">
|
||||
```conf
|
||||
127.0.0.1 gitea droneci
|
||||
```
|
||||
</div>
|
||||
|
||||
Cette ligne va vous permettre de résoudre les noms des conteneurs. Cela
|
||||
permettra aux requêtes OAuth de se faire de manière transparente pour vous
|
||||
lorsque vous serez dans votre navigateur.
|
32
tutorial/devops/what-srs.md
Normal file
32
tutorial/devops/what-srs.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
\newpage
|
||||
|
||||
But du TP
|
||||
=========
|
||||
|
||||
Nous allons nous mettre aujourd’hui dans la peau d’une équipe DevOps et
|
||||
réaliser une solution complète d’intégration/déploiement continu (le fameux
|
||||
CI/CD, pour *Continuous Integration* et *Continuous Delivery*).
|
||||
|
||||
Le résultat attendu d’ici la fin de cette partie sera de mettre en place toutes
|
||||
les briques décrites dans la section précédente.
|
||||
\
|
||||
|
||||
Nous allons commencer par automatiser le projet `youp0m`, plus simple, ~~puis
|
||||
la plate-forme du FIC dans son ensemble, ce qui représente un petit challenge~~
|
||||
(merci Nabih !).
|
||||
|
||||
Il est également attendu que vous rendiez un playbook Ansible, permettant de
|
||||
retrouver un environnement similaire. Car on pourra s’en resservir par la
|
||||
suite.
|
||||
\
|
||||
|
||||
Dans un premier temps, on voudra juste compiler notre projet, pour s’assurer
|
||||
que chaque commit poussé ne contient pas d’erreur de compilation, dans
|
||||
l’environnement défini comme étant celui de production. Ensuite, on ajoutera
|
||||
quelques tests automatiques. Puis nous publierons automatiquement le binaire
|
||||
`youp0m` comme fichier associé à un tag au sein de l’interface web du
|
||||
gestionnaire de versions.
|
||||
|
||||
Enfin, nous mettrons en place un registre Docker qui nous permettra de publier
|
||||
automatiquement l’image Docker associée. C’est à partir de cette image Docker
|
||||
que l’on va commencer à déployer automatiquement...
|
|
@ -1,64 +1,25 @@
|
|||
\newpage
|
||||
|
||||
But du TP
|
||||
=========
|
||||
La journée DevOps
|
||||
=================
|
||||
|
||||
Nous allons nous mettre aujourd'hui dans la peau d'une équipe DevOps et
|
||||
Nous allons maintenant nous mettre dans la peau d'une équipe DevOps et
|
||||
réaliser une solution complète d'intégration/déploiement continu (le fameux
|
||||
CI/CD, pour *Continuous Integration* et *Continuous Delivery*).
|
||||
|
||||
Le résultat attendu d'ici la fin de cette partie sera de mettre en place toutes
|
||||
les briques décrites dans la section précédente.
|
||||
\
|
||||
|
||||
Nous allons commencer par automatiser le projet `youp0m`, plus simple, ~~puis
|
||||
la plate-forme du FIC dans son ensemble, ce qui représente un petit challenge~~
|
||||
(merci Nabih !).
|
||||
|
||||
Il est également attendu que vous rendiez un playbook Ansible, permettant de
|
||||
retrouver un environnement similaire. Car on pourra s'en resservir par la suite.
|
||||
les briques décrites au chapitre précédent. Nous allons pour cela automatiser
|
||||
le projet `youp0m`, que l'on connaît déjà bien.
|
||||
\
|
||||
|
||||
Dans un premier temps, on voudra juste compiler notre projet, pour s'assurer
|
||||
que chaque commit poussé ne contient pas d'erreur de compilation, dans
|
||||
l'environnement défini comme étant celui de production. Ensuite, on ajoutera
|
||||
quelques tests automatiques. Puis nous publierons automatiquement le binaire
|
||||
`youp0m` comme fichier associé à un tag au sein de l'interface web du
|
||||
gestionnaire de versions.
|
||||
que chaque *commmit* poussé ne contient pas d'erreur de compilation (dans
|
||||
l'environnement défini comme étant celui de production, donc avec une version
|
||||
précise des outils de compilation). Ensuite, nous ajouterons quelques tests
|
||||
automatiques, puis nous publierons automatiquement le binaire `youp0m` comme
|
||||
fichier associé à un tag au sein de l'interface web d'un gestionnaire de
|
||||
versions.
|
||||
|
||||
Enfin, nous mettrons en place un registre Docker qui nous permettra de publier
|
||||
automatiquement l'image Docker associée. C'est à partir de cette image Docker
|
||||
que l'on va commencer à déployer automatiquement...
|
||||
|
||||
|
||||
## Préparer le terrain
|
||||
|
||||
Tous les déploiements sont à faire sur votre machine en utilisant des
|
||||
conteneurs Docker, qui seront regroupés au sein de réseaux Docker. Cela vous
|
||||
permettra d'utiliser la résolution de noms entre vos conteneurs.
|
||||
|
||||
Dans votre playbook Ansible, vous pourrez procéder ainsi :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
- name: Create virli network
|
||||
docker_network:
|
||||
name: virli3
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
Étant donné que votre machine ne dispose pas de domaine sur Internet et que
|
||||
l'on va essayer de simplifier au maximum l'installation, vous devriez ajouter
|
||||
cette ligne à votre fichier `/etc/hosts` (ou
|
||||
`\Windows\System32\drivers\etc\hosts`) :
|
||||
|
||||
<div lang="en-US">
|
||||
```conf
|
||||
127.0.0.1 gitea droneci
|
||||
```
|
||||
</div>
|
||||
|
||||
Cette ligne va vous permettre de résoudre les noms des conteneurs. Cela
|
||||
permettra aux requêtes OAuth de se faire de manière transparente pour vous
|
||||
lorsque vous serez dans votre navigateur.
|
||||
|
|
|
@ -57,7 +57,7 @@ run`.
|
|||
Cette section est le pendant de la commandes `docker volume`.
|
||||
|
||||
On déclare les volumes simplement en leur donnant un nom et un driver comme
|
||||
suit :
|
||||
suit :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
|
@ -68,7 +68,7 @@ volumes:
|
|||
</div>
|
||||
|
||||
Pour les utiliser avec un conteneur, on référence le nom ainsi que
|
||||
l'emplacement à partager :
|
||||
l'emplacement à partager :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
|
@ -87,10 +87,10 @@ Cette section est le pendant de la commandes `docker network`.
|
|||
|
||||
Par défaut, Docker relie tous les conteneurs sur un bridge et fait du NAT pour
|
||||
que les conteneurs puissent accéder à l'Internet. Mais ce n'est pas le seul
|
||||
mode possible !
|
||||
mode possible !
|
||||
|
||||
De la même manière que pour les `volumes`, cette section déclare les réseaux
|
||||
qui pourront être utilisés par les `services`. On pourrait donc avoir :
|
||||
qui pourront être utilisés par les `services`. On pourrait donc avoir :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
|
@ -133,12 +133,14 @@ lié, même après que l'on ait démarré. La résolution se fera dynamiquement.
|
|||
|
||||
#### Utiliser le `docker-compose.yml`
|
||||
|
||||
Consultez
|
||||
[la documentation](https://docs.docker.com/compose/compose-file/) pour
|
||||
une liste exhaustive des options que nous pouvons utiliser.
|
||||
Consultez la documentation[^COMPOSEDOC] pour une liste exhaustive des options
|
||||
que nous pouvons utiliser.
|
||||
|
||||
[^COMPOSEDOC]: La documentation des `docker-compose.yml` :
|
||||
<https://docs.docker.com/compose/compose-file/>
|
||||
|
||||
Une fois que notre `docker-compose.yml` est prêt, nous pouvons lancer
|
||||
la commande suivante et admirer le résultat :
|
||||
la commande suivante et admirer le résultat :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
|
@ -6,9 +6,8 @@ Lier des conteneurs
|
|||
Avant de voir des méthodes plus automatiques pour déployer toute notre pile
|
||||
logicielle TICK, nous allons commencer par mettre en place et lier les
|
||||
conteneurs manuellement, de la même manière que nous avons pu le faire avec
|
||||
l'interface d'administration du FIC et MySQL. Cela nous permettra de voir les
|
||||
subtilités de chaque image, ce qui nous fera gagner du temps pour ensuite
|
||||
en faire la description.
|
||||
MySQL. Cela nous permettra de voir les subtilités de chaque image, ce qui nous
|
||||
fera gagner du temps pour ensuite en faire la description.
|
||||
|
||||
|
||||
### Conteneur central : la base de données
|
||||
|
@ -58,7 +57,8 @@ le client officiel (le binaire s'appelle `influx`) :
|
|||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ docker container run --rm -it --link mytsdb:influxdb influxdb:1.8 influx -host influxdb
|
||||
42sh$ docker container run --rm -it --link mytsdb:influxdb influxdb:1.8 \
|
||||
influx -host influxdb
|
||||
Connected to http://influxdb:8086 version 1.8.9
|
||||
InfluxDB shell version: 1.8.9
|
||||
> show databases
|
||||
|
@ -69,10 +69,10 @@ _internal
|
|||
```
|
||||
</div>
|
||||
|
||||
Si vous aussi vous voyez la table `_internal`, bravo ! vous pouvez passer à la
|
||||
Si vous aussi vous voyez la table `_internal`, bravo ! vous pouvez passer à la
|
||||
suite.
|
||||
|
||||
#### Mais quelle était cette commande magique ? {-}
|
||||
#### Mais quelle était cette commande magique ? {-}
|
||||
|
||||
Oui, prenons quelques minutes pour l'analyser ...
|
||||
|
||||
|
@ -132,7 +132,9 @@ système. Pour cela, on commence par télécharger *Telegraf* :
|
|||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
curl https://dl.influxdata.com/telegraf/releases/telegraf-1.19.2_linux_amd64.tar.gz | \
|
||||
V=1.19.2
|
||||
P=telegraf-${V}_linux_$(uname -m)
|
||||
curl https://dl.influxdata.com/telegraf/releases/${P}.tar.gz | \
|
||||
tar xzv -C /tmp
|
||||
```
|
||||
</div>
|
||||
|
@ -157,7 +159,8 @@ Et observons ensuite :
|
|||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ docker container run --rm -it --link mytsdb:zelda influxdb:1.8 influx -host zelda
|
||||
42sh$ docker container run --rm -it --link mytsdb:zelda influxdb:1.8 \
|
||||
influx -host zelda
|
||||
InfluxDB shell version: 1.8.9
|
||||
> show databases
|
||||
name: databases
|
||||
|
@ -205,6 +208,6 @@ si besoin.
|
|||
la page d'accueil est vide au démarrage, pour savoir si vous avez réussi,
|
||||
rendez-vous sous l'onglet *Hosts*, le nom de votre machine devrait y
|
||||
apparaître. En cliquant dessus, vous obtiendrez des graphiques similaires à
|
||||
ceux ci-dessous :
|
||||
ceux ci-après :
|
||||
|
||||

|
||||
|
|
|
@ -7,7 +7,7 @@ Projet
|
|||
------
|
||||
|
||||
Réalisez le `docker-compose.yml` permettant de lancer toute notre stack de
|
||||
monitoring, d'un simple :
|
||||
monitoring, d'un simple :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -49,10 +49,10 @@ Tarball
|
|||
-------
|
||||
|
||||
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 supplémentaires,
|
||||
cela dépendra de votre avancée dans le projet) :
|
||||
cela dépendra de votre avancée dans le projet) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -66,7 +66,7 @@ login_x-TP1/...
|
|||
|
||||
## Signature du rendu
|
||||
|
||||
Deux méthodes sont utilisables pour signer votre rendu :
|
||||
Deux méthodes sont utilisables pour signer votre rendu :
|
||||
|
||||
* signature du courriel ;
|
||||
* signature de la tarball.
|
||||
|
@ -93,7 +93,7 @@ signature.
|
|||
|
||||
#### No public key
|
||||
|
||||
Si vous recevez un rapport avec l'erreur suivante :
|
||||
Si vous recevez un rapport avec l'erreur suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -116,7 +116,7 @@ rendu.
|
|||
|
||||
#### Not explicit username
|
||||
|
||||
Si vous recevez un rapport avec l'erreur suivante :
|
||||
Si vous recevez un rapport avec l'erreur suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -131,7 +131,7 @@ données.
|
|||
|
||||
#### I've decided to skip your e-mail
|
||||
|
||||
Si vous recevez un rapport concluant ainsi :
|
||||
Si vous recevez un rapport concluant ainsi :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
@ -5,7 +5,7 @@ Contenir les applications pour éviter les fuites
|
|||
|
||||
Lorsque l'on gère un environnement de production, on souhaite bien
|
||||
évidemment éviter tout déni de service. Ou parfois, contenir un
|
||||
programme métier avec une fuite mémoire, dans certaines limites : il
|
||||
programme métier avec une fuite mémoire, dans certaines limites : il
|
||||
vaut parfois mieux le tuer et le relancer automatiquement, plutôt que
|
||||
d'attendre que potentiellement un autre processus se fasse tuer à sa
|
||||
place.
|
||||
|
@ -44,7 +44,7 @@ l'ordonnanceur privilégiant alors les autres processus du système.
|
|||
|
||||
Par défaut, le taux maximal (1024 = 100%) d'utilisation CPU est donné
|
||||
aux nouveaux conteneurs, on peut le réduire en utilisant l'option
|
||||
`-c`/`--cpu-shares` : 512 = 50%, par exemple.
|
||||
`-c`/`--cpu-shares` : 512 = 50%, par exemple.
|
||||
|
||||
|
||||
## Sécuriser l'exécution
|
||||
|
@ -76,14 +76,14 @@ du noyau, seccomp est un filtre que l'on peut définir pour chaque
|
|||
appel système. Liste blanche, liste noire, tout est possible.
|
||||
|
||||
Docker filtre notamment tous les appels systèmes qui pourraient
|
||||
déborder à l'extérieur du conteneur : il n'est par exemple pas
|
||||
déborder à l'extérieur du conteneur : il n'est par exemple pas
|
||||
possible de changer l'heure dans un conteneur, car il n'y a
|
||||
aujourd'hui aucun mécanisme pour isoler les visions des dates d'un
|
||||
conteneur à l'autre.
|
||||
|
||||
Voici par exemple un fichier de profil seccomp, interdisant
|
||||
l'utilisation de l'appel système `nanosleep(2)` (utilisé notamment par
|
||||
`sleep(1)`) :
|
||||
`sleep(1)`) :
|
||||
|
||||
<div lang="en-US">
|
||||
```js
|
||||
|
@ -105,11 +105,11 @@ l'utilisation de l'appel système `nanosleep(2)` (utilisé notamment par
|
|||
```
|
||||
</div>
|
||||
|
||||
On peut ensuite l'appliquer à un conteneur Docker :
|
||||
On peut ensuite l'appliquer à un conteneur Docker :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ docker container run -it --security-opt seccomp=nanosleep.json ubuntu /bin/bash
|
||||
42sh$ docker run -it --security-opt seccomp=nanosleep.json ubuntu /bin/bash
|
||||
(cntnr)$ sleep 42
|
||||
sleep: cannot read realtime clock: Operation not permitted
|
||||
```
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
Mise en place
|
||||
-------------
|
||||
|
||||
Dans la première partie du TP, nous avons installé l'environnement Docker
|
||||
principal, qui inclut le client, le daemon et toute sa machinerie. Mais le
|
||||
projet Docker propose de nombreuses autres ressources, souvent directement
|
||||
trouvées dans les usages de la communauté, et parfois même appropriées par
|
||||
Docker.
|
||||
Jusqu'ici, nous avons utilisé l'environnement Docker principal, qui inclut le
|
||||
client, le daemon et toute sa machinerie. Mais le projet Docker propose de
|
||||
nombreuses extensions, souvent directement trouvées dans les usages de la
|
||||
communauté, et parfois même appropriées par Docker.
|
||||
|
||||
|
||||
### `docker-compose`
|
||||
|
@ -16,8 +15,8 @@ Dans cette partie, nous allons avoir besoin de `docker-compose`.
|
|||
|
||||
Ce projet ne bénéficie pas d'une intégration au sein du projet Docker et doit
|
||||
être téléchargé séparément, car originellement, le projet était développé par
|
||||
une équipe indépendante. Il constitue aujourd'hui une brique de l'écosystème
|
||||
Docker, presque indispensable !
|
||||
une équipe indépendante (et en Python). Il constitue aujourd'hui une brique de
|
||||
l'écosystème Docker, presque indispensable !
|
||||
|
||||
#### Par le gestionnaire de paquets
|
||||
|
||||
|
@ -26,28 +25,17 @@ fonctionnera avec la version de Docker qu'ils fournissent.
|
|||
|
||||
#### Par la distribution binaire
|
||||
|
||||
L'équipe en charge de Docker compose met à disposition un exécutable contenant
|
||||
tous les scripts. Nous pouvons l'installer en suivant la procédure suivante :
|
||||
L'équipe en charge du projet met à disposition un exécutable que nous pouvons
|
||||
téléchargeant depuis <https://github.com/docker/compose/releases>.
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64 \
|
||||
> /usr/bin/docker-compose
|
||||
chmod +x /usr/bin/docker-compose
|
||||
```
|
||||
</div>
|
||||
|
||||
#### `pip`
|
||||
|
||||
Le projet étant écrit en Python, il est également disponible via `pip`, si vous
|
||||
préférez cette méthode. N'oubliez pas de préciser une version compatible avec
|
||||
votre version de Docker.
|
||||
Ajoutez l'exécutable dans le dossier des plugins : `$HOME/.docker/cli-plugins`
|
||||
(sans oublier de `chmod +x` !).
|
||||
|
||||
|
||||
#### Vérification du fonctionnement
|
||||
|
||||
Comme avec Docker, nous pouvons vérifier le bon fonctionnement de
|
||||
`docker-compose` en exécutant la commande :
|
||||
`docker-compose` en exécutant la commande :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -56,13 +44,13 @@ docker-compose version: 1.29.2
|
|||
```
|
||||
</div>
|
||||
|
||||
Si vous obtenez une réponse similaire, c'est que vous êtes prêt à commencer le
|
||||
TP ! Alors n'attendons pas, partons à l'aventure !
|
||||
Si vous obtenez une réponse similaire, c'est que vous êtes prêt à continuer !
|
||||
Alors n'attendons pas, partons à l'aventure !
|
||||
|
||||
|
||||
### Play With Docker
|
||||
|
||||
Tout comme pour la partie précédente, si vous avez des difficultés pour
|
||||
réaliser les exercices sur vos machines, vous pouvez utiliser le projet [Play
|
||||
réaliser les exercices sur votre machine, vous pouvez utiliser le projet [Play
|
||||
With Docker](https://play-with-docker.com/) qui vous donnera accès à un bac à
|
||||
sable avec lequel vous pourrez réaliser tous les exercices de ce TP.
|
||||
sable avec lequel vous pourrez réaliser tous les exercices.
|
||||
|
|
|
@ -6,7 +6,7 @@ institute: EPITA
|
|||
date: Mercredi 2 octobre 2019
|
||||
abstract: |
|
||||
Dans cette deuxième partie du TP, nous allons apprendre à déployer
|
||||
un groupe de conteneurs !
|
||||
un groupe de conteneurs !
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@ Orchestrer un groupe de conteneurs
|
|||
Maintenant que nous savons démarrer individuellement des conteneurs et les lier
|
||||
entre-eux, nous allons voir une première manière d'automatiser cela.
|
||||
|
||||
Plutôt que de lancer les commandes `docker` comme nous l'avons fait jusque là :
|
||||
Plutôt que de lancer les commandes `docker` comme nous l'avons fait jusque là :
|
||||
soit directement dans un terminal, soit via un script, nous allons décrire
|
||||
l'état que nous souhaitons atteindre : quels images lancer, quels volumes
|
||||
l'état que nous souhaitons atteindre : quels images lancer, quels volumes
|
||||
créer, quels réseaux, etc. Cette description peut s'utiliser pour lancer un
|
||||
conteneur seul, mais elle prend tout son sens lorsqu'il faut démarrer tout un
|
||||
groupe de conteneurs qui fonctionnent de concert, parfois avec des dépendances
|
||||
|
@ -16,7 +16,7 @@ groupe de conteneurs qui fonctionnent de concert, parfois avec des dépendances
|
|||
démarrer).
|
||||
|
||||
On parle d'orchestration, car nous allons utiliser Docker comme un chef
|
||||
d'orchestre : il va ordonner les créations des différents objets (volumes,
|
||||
d'orchestre : il va ordonner les créations des différents objets (volumes,
|
||||
réseaux, conteneurs, ...) afin d'arriver au résultat attendu, puis il va faire
|
||||
en sorte de maintenir ce résultat selon les événements qui pourront survenir.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
include ../pandoc-opts.mk
|
||||
|
||||
SOURCES = tutorial.md installation.md what.md first.md cleaning.md ex-flask.md volumes.md linking.md
|
||||
SOURCES = tutorial.md installation.md what.md first.md cleaning.md ex-flask.md volumes.md linking.md linking-ex-fic.md linking-ex-help.md
|
||||
|
||||
|
||||
all: tutorial.pdf
|
||||
|
|
|
@ -17,19 +17,19 @@ l'option `--rm`.
|
|||
### Conteneurs
|
||||
|
||||
Nous pouvons afficher l'ensemble des conteneurs, quel que soit leur état (en
|
||||
cours d'exécution, arrêtés,\ ...) avec la commande suivante :
|
||||
cours d'exécution, arrêtés, ...) avec la commande suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ docker container ls -a
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
|
||||
552d71619723 hello-world "/hello" 4 days ago Exited (0) 4 days ago dreamy_gates
|
||||
0e8bbff6d500 debian "/bin/bash" 2 weeks ago Exited (0) 2 weeks ago cranky_jones
|
||||
552d71619723 hello-world "/hello" 4 days ago Exited (0) 4 days ago dreamy_g
|
||||
0e8bbff6d500 debian "/bin/bash" 2 weeks ago Exited (0) 2 weeks ago cranky_j
|
||||
```
|
||||
</div>
|
||||
|
||||
Il y a de fortes chances pour que vous n'ayez plus besoin de ces vieux
|
||||
conteneurs. Pour les supprimer, utilisez la commande :
|
||||
conteneurs. Pour les supprimer, utilisez la commande :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -37,7 +37,7 @@ docker container rm 0e8bbff6d500 552d71619723
|
|||
```
|
||||
</div>
|
||||
|
||||
ou encore :
|
||||
ou encore :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -57,7 +57,7 @@ de la même manière que les conteneurs, avec les sous-commandes `docker image`.
|
|||
### `prune`
|
||||
|
||||
Dans la plupart des menus permettant de gérer les objets Docker, vous trouverez
|
||||
une commande `prune` qui supprimera les objets inutilisés :
|
||||
une commande `prune` qui supprimera les objets inutilisés :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -65,7 +65,7 @@ docker container prune
|
|||
```
|
||||
</div>
|
||||
|
||||
On aura tendance à vouloir supprimer tous les objets inutiles d'un seul coup, via :
|
||||
On aura tendance à vouloir supprimer tous les objets inutiles d'un seul coup, via :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
|
@ -2,3 +2,15 @@
|
|||
|
||||
Découvrons Docker
|
||||
=================
|
||||
|
||||
Entrons sans plus attendre dans le vif du sujet : Docker.
|
||||
|
||||
Ce projet, dont les sources ont été rendues libres en 2013, a tout de
|
||||
suite remporté un engouement indéniable. Le projet a énormément grossi
|
||||
depuis, et il s'est aussi bien stabilisé. Aujourd'hui de nombreuses
|
||||
entreprises n'hésitent plus à l'utiliser en production.
|
||||
|
||||
Dans ce chapitre, nous allons partir à la découverte de cet outil :
|
||||
après l'avoir installé, nous apprendrons d'abord les concepts clefs puis
|
||||
nous lancerons notre premier conteneur et nous irons jusqu'à déployer
|
||||
un premier service web avec lequel nous pourrons interagir.
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
Mon premier webservice
|
||||
----------------------
|
||||
|
||||
C'est parti, nous allons déployer notre premier service !
|
||||
C'est parti, nous allons déployer notre premier service !
|
||||
|
||||
Il s'agit d'un service montrant une image aléatoire à chaque chargement de
|
||||
page : <https://you.p0m.fr/>.
|
||||
page : <https://you.p0m.fr/>.
|
||||
|
||||
|
||||
Nous pouvons télécharger et lancer le service grâce à :
|
||||
Nous pouvons télécharger et lancer le service grâce à :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -17,22 +17,22 @@ docker container run -i nemunaire/youp0m
|
|||
```
|
||||
</div>
|
||||
|
||||
Cette fois-ci, ce n'est pas un shell que nous obtenons[^defaultcmd] : il semblerait que le
|
||||
service soit lancé et écoute sur le port 8080. Est-ce le cas ?
|
||||
Cette fois-ci, ce n'est pas un shell que nous obtenons[^defaultcmd] : il semblerait que le
|
||||
service soit lancé et écoute sur le port 8080. Est-ce le cas ?
|
||||
|
||||
<http://localhost:8080>
|
||||
|
||||
[^defaultcmd]: Chaque conteneur dispose d'une commande par défaut : les images
|
||||
[^defaultcmd]: Chaque conteneur dispose d'une commande par défaut : les images
|
||||
de base telles que les distributions vont lancer un shell, tandis que les
|
||||
conteneurs de service vont lancer leur service directement.
|
||||
|
||||
Non ! Car le service est contenerisé ! Il s'exécute dans son coin, sans
|
||||
Non ! Car le service est contenerisé ! Il s'exécute dans son coin, sans
|
||||
interférer avec son hôte.
|
||||
|
||||
|
||||
### Redirection de ports
|
||||
|
||||
Nous pouvons rediriger le port avec l'argument <span lang="en-US">`-p dst_host:src_cntr`</span> :
|
||||
Nous pouvons rediriger le port avec l'argument <span lang="en-US">`-p dst_host:src_cntr`</span> :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -43,7 +43,7 @@ docker container run -i -p 8080:8080 nemunaire/youp0m
|
|||
Cette fois, nous pouvons accéder au service.
|
||||
|
||||
Pour le moment, le service ne dispose d'aucune image à afficher, vous pouvez
|
||||
utiliser cette syntaxe pour ajouter une image :
|
||||
utiliser cette syntaxe pour ajouter une image :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -51,7 +51,7 @@ base64 monimage.jpg | curl --data @- http://localhost:8080/api/images/monimage
|
|||
```
|
||||
</div>
|
||||
|
||||
Si vous n'êtes pas particulièrement inspiré, vous pouvez ajouter ces images :
|
||||
Si vous n'êtes pas particulièrement inspiré, vous pouvez ajouter ces images :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -63,13 +63,13 @@ done
|
|||
</div>
|
||||
|
||||
|
||||
### Prêt pour la production ?
|
||||
### Prêt pour la production ?
|
||||
|
||||
Avec l'option `-i`, nous pouvons encore transmettre les signaux de terminaison
|
||||
au conteneur. C'est pratique lorsque l'on développe, mais en production, notre
|
||||
service ne s'exécutera pas dans notre terminal !
|
||||
service ne s'exécutera pas dans notre terminal !
|
||||
|
||||
On utilise l'option `-d` pour lancer le conteneur en tâche de fond :
|
||||
On utilise l'option `-d` pour lancer le conteneur en tâche de fond :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -79,7 +79,7 @@ docker container run -d -p 8080:8080 nemunaire/youp0m
|
|||
|
||||
À partir de l'identifiant renvoyé par cette commande (que l'on peut également
|
||||
obtenir avec un `docker container ls`), nous pouvons consulter les logs du
|
||||
service (en fait, les sorties standard et d'erreur) :
|
||||
service (en fait, les sorties standard et d'erreur) :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -88,15 +88,15 @@ docker container logs 0123456789abcdef
|
|||
</div>
|
||||
|
||||
|
||||
### Une autre instance ?
|
||||
### Une autre instance ?
|
||||
|
||||
Maintenant que nous avons un clone de <https://you.p0m.fr/>, nous voulons
|
||||
absolument un clone de <https://food.p0m.fr/> !
|
||||
absolument un clone de <https://food.p0m.fr/> !
|
||||
|
||||
Il s'agit du même service, mais ce ne sont pas les mêmes images.
|
||||
|
||||
On ne peut pas utiliser le même port sur la machine hôte, mais pour le reste,
|
||||
il s'agit des mêmes options\ :
|
||||
il s'agit des mêmes options\ :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -104,10 +104,10 @@ docker container run -d -p 8081:8080 nemunaire/youp0m
|
|||
```
|
||||
</div>
|
||||
|
||||
Voyons le résultat : <http://localhost:8081>
|
||||
Voyons le résultat : <http://localhost:8081>
|
||||
|
||||
Nous avons réussi à lancer deux conteneurs à partir de la même image, et on
|
||||
voit bien que ceux-ci ne partagent pas leur système de fichiers : notre
|
||||
voit bien que ceux-ci ne partagent pas leur système de fichiers : notre
|
||||
nouvelle instance est encore immaculée.
|
||||
|
||||
|
||||
|
@ -123,18 +123,19 @@ Outre les arguments que l'on peut passer au premier processus du conteneur, la
|
|||
plupart des images peuvent adapter leur comportement en fonction de variables
|
||||
d'environnement que l'on passe en paramètre.
|
||||
|
||||
Cette bonne pratique est recommandée par <https://12factor.net/>, qui détaille
|
||||
les raisons qui devraient pousser les développeurs à privilégier les variables
|
||||
d'environnements aux arguments sur la ligne de commande.
|
||||
Cette bonne pratique est recommandée par
|
||||
[`12factor.net`](https://12factor.net/), qui détaille les raisons qui devraient
|
||||
pousser les développeurs à privilégier les variables d'environnements aux
|
||||
arguments sur la ligne de commande.
|
||||
|
||||
Il se trouve que les conteneurs `youp0m` peuvent créer le fichier `htpasswd`,
|
||||
s'ils sont démarrés avec les variables d'environnement :
|
||||
s'ils sont démarrés avec les variables d'environnement :
|
||||
|
||||
- `YOUP0M_USERNAME` : nom d'utilisateur pour l'administrateur (par défaut admin) ;
|
||||
- `YOUP0M_PASSWORD` : mot de passe de l'utilisateur.
|
||||
- `YOUP0M_USERNAME` : nom d'utilisateur pour l'administrateur (par défaut admin) ;
|
||||
- `YOUP0M_PASSWORD` : mot de passe de l'utilisateur.
|
||||
|
||||
Pour ajouter une variable d'environnement, cela se passe dans la commande
|
||||
`run`, en ajoutant une ou plusieurs options `-e` :
|
||||
`run`, en ajoutant une ou plusieurs options `-e` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -143,13 +144,14 @@ docker container run -e YOUP0M_PASSWORD=foobar -p 8080:8080 nemunaire/youp0m
|
|||
</div>
|
||||
|
||||
Une fois lancé, ce conteneur exposera une interface d'administration à cette
|
||||
adresse : <http://localhost:8080/admin/>.
|
||||
adresse :\
|
||||
<http://localhost:8080/admin/>.
|
||||
|
||||
|
||||
### Arrêt des conteneurs et persistance des données
|
||||
|
||||
Lorsque l'on souhaite stopper un conteneur lancé en tâche de fond, on utilise
|
||||
son identifiant dans la commande suivante :
|
||||
son identifiant dans la commande suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
\newpage
|
||||
|
||||
Exercice
|
||||
========
|
||||
Exercice {-}
|
||||
--------
|
||||
|
||||
Pour mettre en pratiques toutes les notions que l'on a vu jusque là, écrivez un
|
||||
script `mycloud-run.sh` pour automatiser le lancement de votre instance
|
||||
|
@ -16,25 +14,26 @@ pour se rendre sur la page de connexion. Une autre machine de votre réseau
|
|||
local devrait également pouvoir accéder à la plate-forme, simplement en
|
||||
renseignant l'IP de votre machine et en ajoutant éventuellement des règles de
|
||||
pare-feu (mais cette dernière partie n'est pas demandée, gardez simplement en
|
||||
tête que cela doit pouvoir être fait manuellement au cas par cas : sur une
|
||||
tête que cela doit pouvoir être fait manuellement au cas par cas : sur une
|
||||
machine sans pare-feu configurée, cela ne demande pas d'étape supplémentaire).
|
||||
|
||||
Votre script devra se limiter aux notions vues durant cette partie du TP
|
||||
(ie. sans utiliser `docker-compose` ou `docker stack` que l'on verra dans la
|
||||
seconde partie). Il pourra cependant faire usage des commandes `docker OBJECT
|
||||
inspect` pour ne pas avoir à faire d'analyse syntaxique sur les retours des
|
||||
commandes lisibles par les humains.
|
||||
(ie. sans utiliser `docker-compose` ou `docker stack` que l'on verra par la
|
||||
suite). Il pourra cependant faire usage des commandes `docker OBJECT inspect`
|
||||
pour ne pas avoir à faire d'analyse syntaxique sur les retours des commandes
|
||||
lisibles par les humains.
|
||||
|
||||
Cette instance devra utiliser une base de données MySQL (lancée par vos soins
|
||||
dans un autre conteneur) et contenir ses données dans un ou plusieurs volumes
|
||||
(afin qu'elles persistent à une mise à jour des conteneurs par exemple).
|
||||
Cette instance devra utiliser une base de données MySQL (lancée par votre
|
||||
script dans un autre conteneur) et contenir ses données dans un ou plusieurs
|
||||
volumes (afin qu'elles persistent à une mise à jour des conteneurs par
|
||||
exemple).
|
||||
|
||||
L'exécution doit être la plus sécurisée possible (pas de port MySQL exposé sur
|
||||
l'hôte par exemple, etc.) et la plus respectueuse des bonnes pratiques que l'on
|
||||
a pu voir durant ce premier cours.
|
||||
a pu voir jusque là.
|
||||
|
||||
|
||||
### Exemple d'exécution
|
||||
### Exemple d'exécution {-}
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
|
@ -4,7 +4,7 @@ Mon premier conteneur
|
|||
---------------------
|
||||
|
||||
Afin de tester la bonne marche de notre installation, lançons notre premier
|
||||
conteneur avec la commande\ :
|
||||
conteneur avec la commande :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -13,7 +13,7 @@ docker container run hello-world
|
|||
</div>
|
||||
|
||||
Cette commande va automatiquement exécuter une série d'actions pour nous,
|
||||
comme indiqué dans le message affiché en retour :
|
||||
comme indiqué dans le message affiché en retour :
|
||||
|
||||
D'abord, le daemon va rechercher s'il possède localement l'image
|
||||
*hello-world*. Si ce n'est pas le cas, il va aller récupérer les différentes
|
||||
|
@ -23,7 +23,7 @@ conteneur. Enfin, il lance la commande par défaut, telle que définie dans les
|
|||
métadonnées de l'image.
|
||||
|
||||
Nous pouvons directement utiliser le client pour rechercher une image sur le
|
||||
registre, en utilisant la commande `search` :
|
||||
registre, en utilisant la commande `search` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -32,7 +32,7 @@ docker search mariadb
|
|||
</div>
|
||||
|
||||
Il est possible de mettre à jour les images locales, ou télécharger les couches
|
||||
d'images qui nous intéressent, en utilisant la commande `pull` :
|
||||
d'images qui nous intéressent, en utilisant la commande `pull` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -41,40 +41,42 @@ docker image pull ubuntu
|
|||
</div>
|
||||
|
||||
|
||||
#### Attention {-}
|
||||
::::: {.warning}
|
||||
|
||||
Les registres publics tels quel le Docker Hub mettent à disposition des images
|
||||
officielles, mais aussi des images créés par la communauté. Chaque utilisateur
|
||||
est libre d'envoyer une image qu'il a lui-même créée : soit car l'éditeur ne
|
||||
officielles, mais aussi des images créées par la communauté. Chaque utilisateur
|
||||
est libre d'envoyer une image qu'il a lui-même créé : soit car l'éditeur ne
|
||||
proposait pas d'image et que quelqu'un s'est dévoué pour la faire, soit parce
|
||||
qu'il avait des besoins plus spécifiques qui n'étaient pas couvert par l'image
|
||||
originale. Il est important de garder en tête que vous téléchargez des
|
||||
exécutables, et bien qu'ils s'exécutent dans un environnement isolé, ils
|
||||
peuvent contenir du code malveillant. **De la même manière que vous devez être
|
||||
attentif aux binaires que vous exécutez sur votre machine et au contexte de
|
||||
leurs téléchargements, ici assurez-vous d'avoir confiance dans la personne
|
||||
affiliée à l'image.**
|
||||
peuvent contenir du code malveillant.
|
||||
|
||||
**De la même manière que vous devez être attentif aux binaires que vous
|
||||
exécutez sur votre machine et au contexte de leurs téléchargements, ici
|
||||
assurez-vous d'avoir confiance dans la personne affiliée à l'image.**
|
||||
|
||||
:::::
|
||||
|
||||
### Arguments de la ligne de commande
|
||||
|
||||
Remarquez comment on interagit avec chaque *objet Docker* : dans la ligne de
|
||||
Remarquez comment on interagit avec chaque *objet Docker* : dans la ligne de
|
||||
commande, le premier mot clef est le type d'objet (`container`, `image`,
|
||||
`service`, `network`, `volume`, ...) ; ensuite, vient l'action que l'on
|
||||
`service`, `network`, `volume`, ...) ; ensuite, vient l'action que l'on
|
||||
souhaite faire dans ce cadre.[^oldcall]
|
||||
|
||||
[^oldcall]: cela n'a pas toujours été aussi simple, cette syntaxe n'existe que
|
||||
depuis la version 1.13 (janvier 2017). C'est pourquoi, lorsque vous ferez
|
||||
des recherches sur internet, vous trouverez de nombreux articles utilisant
|
||||
l'ancienne syntaxe, sans le type d'objets : `docker images` au lieu de
|
||||
`docker image ls`, `docker run` au lieu de `docker container run`, ...
|
||||
l'ancienne syntaxe, sans le type d'objets : `docker images` au lieu de
|
||||
`docker image ls`, `docker run` au lieu de `docker container run`, ...
|
||||
|
||||
L'ancienne syntaxe est dépréciée, mais il reste actuellement possible de
|
||||
l'utiliser.
|
||||
|
||||
Par exemple, pour consulter la liste des images dont nous disposons localement
|
||||
(soit parce qu'on les a téléchargées, soit parce que nous les avons créées
|
||||
nous-même), on utilise la commande `ls` sous le type d'objets `image` :
|
||||
nous-même), on utilise la commande `ls` sous le type d'objets `image` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -85,24 +87,26 @@ docker image ls
|
|||
|
||||
### *Image ID*, nom, tag
|
||||
|
||||
Chaque image est identifiable par son *Image ID* : il s'agit d'un long
|
||||
Chaque image est identifiable par son *Image ID* : il s'agit d'un long
|
||||
identifiant unique. Chaque modification qui est apportée à l'image
|
||||
générera un *Image ID* différent. Un peu comme un identifiant de
|
||||
commit dans Git.
|
||||
|
||||
Pour s'y retrouver, on utilise habituellement les noms des images :
|
||||
Pour s'y retrouver, on utilise habituellement les noms des images :
|
||||
`hello-world` est ainsi le nom de l'image
|
||||
`1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792`.
|
||||
|
||||
Lorsque, comme dans le cas d'Ubuntu, il y a plusieurs *versions*
|
||||
disponibles, il est possible de préciser la version au moyen d'un
|
||||
*tag*. En consultant [la
|
||||
documentation](https://hub.docker.com/_/ubuntu) qui accompagne chaque
|
||||
conteneur, nous pouvons constater la présence de plusieurs versions
|
||||
d'Ubuntu : `trusty`, `xenial`, `focal` ou `bionic`.
|
||||
Lorsque, comme dans le cas d'Ubuntu, il y a plusieurs *versions* disponibles,
|
||||
il est possible de préciser la version au moyen d'un *tag*. En consultant la
|
||||
documentation[^hubDocUbuntu] qui accompagne chaque conteneur, nous pouvons
|
||||
constater la présence de plusieurs versions d'Ubuntu : `trusty`, `xenial`,
|
||||
`focal` ou `bionic`.
|
||||
|
||||
[^hubDocUbuntu]: Pour voir la documentation des images d'Ubuntu, consultez
|
||||
<https://hub.docker.com/_/ubuntu>
|
||||
|
||||
Par convention, lorsque l'on souhaite désigner un tag en particulier,
|
||||
on utilise la syntaxe suivante :
|
||||
on utilise la syntaxe suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -110,7 +114,7 @@ ubuntu:focal
|
|||
```
|
||||
</div>
|
||||
|
||||
Par exemple, pour lancer un conteneur Ubuntu Focal, on utilisera :
|
||||
Par exemple, pour lancer un conteneur Ubuntu Focal, on utilisera :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -119,7 +123,7 @@ docker container run ubuntu:focal
|
|||
</div>
|
||||
|
||||
|
||||
Chaque nom d'image possède au moins un tag associé par défaut : *latest*. C'est
|
||||
Chaque nom d'image possède au moins un tag associé par défaut : *latest*. C'est
|
||||
le tag qui est automatiquement recherché lorsque l'on ne le précise pas en
|
||||
lançant l'image.
|
||||
|
||||
|
@ -127,11 +131,11 @@ lançant l'image.
|
|||
### Exécuter un programme dans un conteneur
|
||||
|
||||
Maintenant que nous avons à notre disposition l'image d'un conteneur Ubuntu,
|
||||
nous allons pouvoir jouer avec !
|
||||
nous allons pouvoir jouer avec !
|
||||
|
||||
La commande `run` de Docker prend comme derniers arguments le programme à
|
||||
lancer dans le conteneur ainsi que ses éventuels arguments. Essayons d'afficher
|
||||
un Hello World :
|
||||
un Hello World :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -146,7 +150,7 @@ transféré dans le conteneur.
|
|||
Pour nous en convaincre, nous pouvons tenter d'exécuter un programme qui n'est
|
||||
pas présent sur notre machine, mais bien uniquement dans le conteneur. Si vous
|
||||
n'utilisez pas [Alpine Linux](https://www.alpinelinux.org), vous pourriez
|
||||
tenter d'utiliser son gestionnaire de paquet `apk`, via :
|
||||
tenter d'utiliser son gestionnaire de paquet `apk`, via :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -184,7 +188,7 @@ programme à exécuter par défaut si l'on ne le précise pas dans la ligne de
|
|||
commande.
|
||||
|
||||
C'est grâce à cela que vous n'avez pas eu besoin de préciser de programme
|
||||
lorsque vous avez lancé l'image `hello-world` :
|
||||
lorsque vous avez lancé l'image `hello-world` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -193,7 +197,7 @@ docker container run hello-world
|
|||
</div>
|
||||
|
||||
Il est commun que le programme le plus attendu/approprié soit lancé par défaut,
|
||||
il est donc tout naturel que pour l'image `hello-world`, ce soit `/hello` :
|
||||
il est donc tout naturel que pour l'image `hello-world`, ce soit `/hello` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -201,20 +205,21 @@ docker container run hello-world /hello
|
|||
```
|
||||
</div>
|
||||
|
||||
L'image ne contenant que ce programme, vous ne pourrez pas y lancer de shell :
|
||||
L'image ne contenant que ce programme, vous ne pourrez pas y lancer de shell :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
```
|
||||
42sh$ docker container run hello-world /bin/sh
|
||||
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349:
|
||||
starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory": unknown.
|
||||
docker: Error response from daemon: OCI runtime create failed:
|
||||
container_linux.go:349: starting container process caused
|
||||
"exec: \"/bin/sh\": stat /bin/sh: no such file or directory"
|
||||
```
|
||||
</div>
|
||||
|
||||
Pour les images `alpine` et `ubuntu`, le programme par défaut est un shell
|
||||
(`/bin/ash` pour `alpine` et `/bin/bash` pour `ubuntu`), mais il y a une
|
||||
subtilité : il faut ajouter les options `--interactive` et `--tty` pour ne pas
|
||||
que `docker` nous rende la main tout de suite :
|
||||
subtilité : il faut ajouter les options `--interactive` et `--tty` pour ne pas
|
||||
que `docker` nous rende la main tout de suite :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -239,7 +244,7 @@ s'assure que l'entrée standard ne sera pas fermée (`close(2)`). Nous demandons
|
|||
interractif[^bashnointer].
|
||||
|
||||
[^bashnointer]: Mais il sera possible de l'utiliser sans allouer de TTY, comme
|
||||
dans cet exemple :
|
||||
dans cet exemple :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -253,7 +258,7 @@ interractif[^bashnointer].
|
|||
L'option `-i` reste néanmoins nécessaire pour que l'entrée standard soit
|
||||
transmise au conteneur.
|
||||
|
||||
Rassurez-vous, on peut les abbréger en `-i` et `-t` :
|
||||
Rassurez-vous, on peut les abréger en `-i` et `-t` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -265,22 +270,22 @@ Rassurez-vous, on peut les abbréger en `-i` et `-t` :
|
|||
|
||||
### Les paramètres
|
||||
|
||||
Vous avez remarqué le placement des options `--tty` et `--interactive` ? Avant
|
||||
Vous avez remarqué le placement des options `--tty` et `--interactive` ? Avant
|
||||
le nom de l'image, elles sont utilisées par Docker pour modifier le comportement
|
||||
du `run`. En fait, tout comme `git(1)` et ses sous-commandes, chaque niveau de
|
||||
commande peut prendre des paramètres :
|
||||
commande peut prendre des paramètres :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker DOCKER_PARAMS container run RUN_OPTS image IMAGE_CMD IMAGE_ARGS ...
|
||||
docker DOCKER_PARAMS container run RUN_OPTS image IMAGE_CMD IMAGE_ARGS …
|
||||
```
|
||||
</div>
|
||||
|
||||
Par exemple :
|
||||
Par exemple :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker -H unix:///var/run/docker.sock container run -it alpine /bin/ash -c "echo foo"
|
||||
docker -H unix:///run/docker.sock container run -it alpine /bin/ash -c "echo foo"
|
||||
```
|
||||
</div>
|
||||
|
||||
|
@ -295,13 +300,13 @@ conteneur.
|
|||
|
||||
Avant de quitter notre conteneur, regardons, à l'aide d'un autre terminal,
|
||||
l'état de notre conteneur. La commande suivante permet d'obtenir la liste des
|
||||
conteneurs en cours d'exécution :
|
||||
conteneurs en cours d'exécution :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ docker container ls
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
4c39fc049cd1 ubuntu "/bin/bash" 6 minutes ago Up 5 minutes suspicious_galileo
|
||||
4c39fc049cd1 ubuntu "/bin/bash" 6 minutes ago Up 5 minutes bold_gates
|
||||
```
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,24 +1,16 @@
|
|||
\newpage
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Avant de voir de quoi il s'agit, afin de gagner du temps, nous allons commencer
|
||||
par installer Docker.
|
||||
|
||||
### Prérequis
|
||||
|
||||
Docker repose sur plusieurs techniques implémentées dans les récents noyaux
|
||||
Linux (et plus marginalement, Windows). Nous consacrerons les prochains cours à
|
||||
comprendre leur fonctionnement. Ces techniques, contrairement aux instructions
|
||||
de virtualisation qui rendent les hyperviseurs attractifs, ne sont pas limitées
|
||||
à une architecture de microprocesseur spécifique ; cependant la communauté
|
||||
autour de Docker utilise principalement l'architecture `amd64`, c'est sur cette
|
||||
dernière que Docker pourra être exploité à son plein potentiel, suivi de près
|
||||
par l'architecture `arm64`.
|
||||
Docker repose sur plusieurs techniques implémentées dans les noyaux Linux
|
||||
récents (et plus marginalement, Windows). Ces techniques, contrairement aux
|
||||
instructions de virtualisation qui rendent les hyperviseurs attractifs, ne sont
|
||||
pas limitées à une architecture de microprocesseur spécifique ; cependant la
|
||||
communauté autour de Docker utilise principalement l'architecture `amd64`,
|
||||
c'est sur cette dernière que Docker pourra être exploité à son plein potentiel,
|
||||
suivi de près par l'architecture `arm64`.
|
||||
|
||||
Avant de continuer, assurez-vous que votre machine a bien démarré sur un noyau
|
||||
64 bits. Le retour de la commande `uname -m` doit vous indiquer :
|
||||
64 bits. Le retour de la commande `uname -m` doit vous indiquer :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -26,7 +18,7 @@ x86_64
|
|||
```
|
||||
</div>
|
||||
|
||||
Ou si vous êtes intrépide :
|
||||
Ou si vous êtes intrépide :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -34,7 +26,7 @@ aarch64
|
|||
```
|
||||
</div>
|
||||
|
||||
Assurez-vous également d'avoir un noyau récent, avec la commande `uname -r` :
|
||||
Assurez-vous également d'avoir un noyau récent, avec la commande `uname -r` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -46,53 +38,66 @@ Rassurez-vous, même si vous n'avez pas compilé le dernier noyau disponible sur
|
|||
[`kernel.org`](https://www.kernel.org/), Docker s'utilise à partir de Linux 3.10.
|
||||
|
||||
|
||||
### Par le gestionnaire de paquets
|
||||
### Sous Linux, par le gestionnaire de paquets
|
||||
|
||||
En général, votre distribution mettra à votre disposition une version de Docker
|
||||
plus ou moins récente. Sous Debian et ses dérivés (Ubuntu, Mint, ...) le paquet
|
||||
plus ou moins récente. Sous Debian et ses dérivés (Ubuntu, Mint, ...) le paquet
|
||||
a été nommé [`docker.io`](https://packages.debian.org/sid/docker.io).
|
||||
|
||||
Si dans un environnement de production, on préférera sans doute utiliser une
|
||||
version déjà bien éprouvée (comme celle des dépôts de sa distribution), pour ce
|
||||
cours, nous allons avoir besoin de la **dernière version
|
||||
version déjà bien éprouvée (comme celle des dépôts de sa distribution), pour
|
||||
bien suivre les exemples, nous allons avoir besoin de la **dernière version
|
||||
disponible**. Référez-vous à la documentation officielle correspondant à votre
|
||||
distribution :
|
||||
distribution :
|
||||
|
||||
<https://docs.docker.com/engine/install/debian/>
|
||||
|
||||
**Et Kali Linux alors ?** Kali étant basée sur Debian, référez-vous à
|
||||
::::: {.question}
|
||||
|
||||
**Et Kali Linux alors ?** Kali étant basée sur Debian, référez-vous à
|
||||
la procédure d'installation de cette distribution.
|
||||
|
||||
:::::
|
||||
|
||||
### Windows et macOS
|
||||
### Sous Windows et macOS
|
||||
|
||||
Bien que les fonctionnalités de contenerisation de Docker que nous utiliserons
|
||||
ne soient disponibles que sous Linux, il est possible d'utiliser Docker de
|
||||
manière déportée : le daemon Docker tournera dans une VM Linux, mais vous
|
||||
pourrez interagir avec lui via votre ligne de commande habituelle.
|
||||
manière déportée : le daemon Docker tournera dans une machine virtuelle Linux,
|
||||
mais vous pourrez interagir avec lui via votre ligne de commande habituelle.
|
||||
|
||||
Téléchargez la version correspondante à votre système d'exploitation :
|
||||
Téléchargez la version correspondant à votre système d'exploitation :
|
||||
|
||||
* [Docker Desktop for Mac](https://hub.docker.com/editions/community/docker-ce-desktop-mac)
|
||||
* [Docker Desktop for Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows)
|
||||
* Docker Desktop for Mac :\
|
||||
<https://hub.docker.com/editions/community/docker-ce-desktop-mac>
|
||||
|
||||
Une fois l'installation terminée, lancez l'application : elle ajoutera une
|
||||
* Docker Desktop for Windows :\
|
||||
<https://hub.docker.com/editions/community/docker-ce-desktop-windows>
|
||||
|
||||
Une fois l'installation terminée, lancez l'application : elle ajoutera une
|
||||
icône dans la zone de notification, vous permettant de contrôler l'exécution de
|
||||
la machine virtuelle sous-jacente.
|
||||
|
||||
Notez que depuis septembre 2021, ces applications passent sous une licence
|
||||
payante pour les grosses entreprises[^DockerSubscription]. Cela ne nous
|
||||
concerne pas, car la licence est gratuite pour un usage éducatif ou
|
||||
personnel. Notez que ce n'est pas le binaire Docker qui change de licence, elle
|
||||
reste libre, mais seulement les applications Docker Desktop.
|
||||
::::: {.warning}
|
||||
|
||||
Depuis septembre 2021, ces applications passent sous une licence payante pour
|
||||
les grosses entreprises[^DockerSubscription]. Cela ne nous concerne pas, car la
|
||||
licence est gratuite pour un usage éducatif ou personnel.
|
||||
|
||||
Notez que cela ne concerne pas le projet ou le binaire Docker : ceux-ci restent
|
||||
libres. Seules les applications Docker Desktop sont concernées.
|
||||
|
||||
:::::
|
||||
|
||||
[^DockerSubscription]: <https://www.docker.com/blog/updating-product-subscriptions/>
|
||||
|
||||
### Évaluation en ligne
|
||||
|
||||
Si vous rencontrez des difficultés pour vous lancer, le projet
|
||||
[Play With Docker](https://labs.play-with-docker.com/) vous donne accès à
|
||||
un bac à sable dans lequel vous pourrez commencer à faire ce TP.
|
||||
Si vous rencontrez des difficultés pour vous lancer, le projet Play With
|
||||
Docker[^PlayWithDocker] vous donne accès à un bac à sable
|
||||
dans lequel vous pourrez commencer à faire les exercices à suivre.
|
||||
|
||||
[^PlayWithDocker]: Play With Docker est accessible à cette addresse : <https://labs.play-with-docker.com/>
|
||||
|
||||
Il vous faudra disposer [d'un compte
|
||||
Docker](https://hub.docker.com/signup). Une fois identifié, vous pourrez créer
|
||||
|
@ -101,7 +106,7 @@ une nouvelle instance, et vous connecter dessus via SSH.
|
|||
|
||||
### Vérifier la bonne marche de l'installation
|
||||
|
||||
Vous devriez maintenant être capable de lancer la commande suivante :
|
||||
Vous devriez maintenant être capable de lancer la commande suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -109,7 +114,7 @@ docker version
|
|||
```
|
||||
</div>
|
||||
|
||||
Une sortie similaire au bloc suivant devrait apparaître sur votre écran :
|
||||
Une sortie similaire au bloc suivant devrait apparaître sur votre écran :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -149,8 +154,8 @@ Server:
|
|||
|
||||
#### `no such file or directory`?
|
||||
|
||||
Si vous avez cette erreur : `dial unix /var/run/docker.sock: no such file or
|
||||
directory.`, le deamon n'est sans doute pas lancé. Lancez-le :
|
||||
Si vous avez cette erreur : `dial unix /var/run/docker.sock: no such file or
|
||||
directory.`, le deamon n'est sans doute pas lancé. Lancez-le :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -161,9 +166,9 @@ sudo service docker restart
|
|||
|
||||
#### `permission denied`?
|
||||
|
||||
Si vous avez cette erreur : `dial unix /var/run/docker.sock: permission
|
||||
Si vous avez cette erreur : `dial unix /var/run/docker.sock: permission
|
||||
denied.`, ajoutez votre utilisateur au groupe `docker` et **relancez votre
|
||||
session** :
|
||||
session** :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -171,5 +176,10 @@ sudo gpasswd -a $USER docker
|
|||
```
|
||||
</div>
|
||||
|
||||
**Attention :** cette action n'est pas anodine d'un point de vue sécurité :
|
||||
::::: {.warning}
|
||||
|
||||
Cette action n'est pas anodine d'un point de vue de la sécurité :
|
||||
|
||||
<https://docs.docker.com/engine/security/#docker-daemon-attack-surface>
|
||||
|
||||
:::::
|
||||
|
|
44
tutorial/docker-basis/linking-ex-fic.md
Normal file
44
tutorial/docker-basis/linking-ex-fic.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
## Exercice {-}
|
||||
|
||||
À vous maintenant de connecter une instance de `nemunaire/fic-admin` à sa base
|
||||
de données.
|
||||
|
||||
Ne vous embêtez pas avec les mots de passes des services, initialisez la base
|
||||
de données avec le nom d'utilisateur et le mot de passe par défaut. Vous les
|
||||
obtiendrez en lisant la documentation de l'image fic-admin :
|
||||
<https://hub.docker.com/r/nemunaire/fic-admin/>
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker run --rm -e MYSQL_HOST=mysql_cntr_name nemunaire/fic-admin -help
|
||||
```
|
||||
</div>
|
||||
|
||||
Notez la définition de la variable d'environnement `MYSQL_HOST`, celle-ci
|
||||
indique le nom du serveur vers lequel le service doit se connecter.
|
||||
|
||||
Vous aurez besoin de créer :
|
||||
- un volume pour stocker la base de données,
|
||||
- un réseau, dans lequel vous connecterez la base de données et le conteneur applicatif.
|
||||
|
||||
Une fois le service `fic-admin` lancé, vous pouvez exposer le port 8081, sur
|
||||
lequel vous devriez voir l'interface d'admin : <http://localhost:8081/>.
|
||||
|
||||
Placez les différentes commandes (volumes, réseau, `run`, ...) dans un
|
||||
script `ficadmin-run.sh`. Vous devriez pouvoir appeler ce script
|
||||
plusieurs fois, sans que les données ne soient perdues, entre deux
|
||||
arrêts.
|
||||
|
||||
|
||||
### Exemple d'exécution
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ ./ficadmin-run.sh
|
||||
http://localhost:12345/
|
||||
42sh$ #docker kill db ficadmin
|
||||
42sh$ ./ficadmin-run.sh # le script relancera une base de données,
|
||||
# sans avoir perdu les données
|
||||
http://localhost:12345/
|
||||
```
|
||||
</div>
|
34
tutorial/docker-basis/linking-ex-help.md
Normal file
34
tutorial/docker-basis/linking-ex-help.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
### Au secours, ça veut pas se connecter !
|
||||
|
||||
Lorsque nous lançons pour la première fois notre conteneur MySQL ou MariaDB, un
|
||||
script est chargé d'initialisé le volume attaché à `/var/lib/mysql`. Les
|
||||
démarrage suivant, ou si vous réutilisez un volume déjà initialisé avec une
|
||||
base de données, le script ne refait pas d'initialisation. Même si les
|
||||
variables d'environnement ont changées.
|
||||
|
||||
Si vous rencontrez des difficultés pour connecter votre conteneur à
|
||||
`my-db`, prenez le temps de recréer un volume.
|
||||
|
||||
|
||||
### Entrer dans un conteneur en cours d'exécution
|
||||
|
||||
Dans certaines circonstances, les journaux ne sont pas suffisants pour déboguer
|
||||
correctement l'exécution d'un conteneur.
|
||||
|
||||
En réalisant l'exercice, vous serez sans doute confronté à des comportements
|
||||
étranges, que vous ne pourriez comprendre qu'en ayant la main sur le conteneur,
|
||||
via un shell.
|
||||
|
||||
Lorsqu'un conteneur est actif, vous pouvez y lancer un nouveau processus,
|
||||
notamment un shell par exemple.
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker container exec -it mycloud /bin/bash
|
||||
(inctnr)$ ping mysql_cntr_name
|
||||
```
|
||||
</div>
|
||||
|
||||
Notez qu'il n'est pas possible d'`exec` dans un conteneur éteint, et que si la
|
||||
commande initiale du conteneur se termine, tous les `exec` seront instantanément
|
||||
tués.
|
|
@ -12,14 +12,14 @@ ses données, mais la plupart des applications réclament un serveur de base de
|
|||
données.
|
||||
|
||||
Les bonnes pratiques nous dictent de ne pas placer plus d'un service par
|
||||
conteneur : en effet, on peut vouloir mettre à jour l'applicatif sans pour
|
||||
conteneur : en effet, on peut vouloir mettre à jour l'applicatif sans pour
|
||||
autant redémarrer sa base de données, etc. Nous allons donc voir dans cette
|
||||
partie comment lier deux conteneurs.
|
||||
|
||||
|
||||
## Mise en place du webservice
|
||||
|
||||
Nous allons utiliser l'interface d'administration des serveurs du FIC :
|
||||
Nous allons utiliser l'interface d'administration des serveurs du FIC :
|
||||
[`nemunaire/fic-admin`](https://hub.docker.com/r/nemunaire/fic-admin).
|
||||
|
||||
En lançant le conteneur avec les mêmes options que `youp0m`, les journaux
|
||||
|
@ -30,17 +30,17 @@ MariaDB](https://hub.docker.com/_/mariadb).
|
|||
|
||||
## Les pilotes réseau
|
||||
|
||||
Docker propose de base trois pilotes (*drivers*) pour « gérer » cela :
|
||||
Docker propose de base trois pilotes (*drivers*) pour « gérer » cela :
|
||||
|
||||
- `none` : pour limiter les interfaces réseau du conteneur à l'interface de
|
||||
- `none` : pour limiter les interfaces réseau du conteneur à l'interface de
|
||||
loopback `lo` ;
|
||||
- `host` : pour partager la pile réseau avec l'hôte ;
|
||||
- `bridge` : pour créer une nouvelle pile réseau par conteneur et rejoindre un
|
||||
- `host` : pour partager la pile réseau avec l'hôte ;
|
||||
- `bridge` : pour créer une nouvelle pile réseau par conteneur et rejoindre un
|
||||
pont réseau dédié.
|
||||
|
||||
|
||||
Ces trois *drivers* sont instanciés de base dans Docker avec le même nom que
|
||||
leur pilote. Pour consulter la liste de réseaux utilisables, lancez :
|
||||
leur pilote. Pour consulter la liste de réseaux utilisables, lancez :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -52,7 +52,7 @@ d5d907add6e2 host host local
|
|||
```
|
||||
</div>
|
||||
|
||||
Par défaut, c'est le réseau `bridge` (de type `bridge`) qui est employé : ce
|
||||
Par défaut, c'est le réseau `bridge` (de type `bridge`) qui est employé : ce
|
||||
réseau utilise le pont `docker0` que vous pouvez voir dans vos interfaces
|
||||
réseau via `ip link`. C'est via ce pont que les conteneurs peuvent avoir accès
|
||||
à Internet, au travers d'une couche de NAT.
|
||||
|
@ -76,7 +76,7 @@ Afin de contrôler quels échanges peuvent être réalisés entre les conteneurs
|
|||
est recommandé de créer des réseaux utilisateur.
|
||||
|
||||
La création d'un réseau se fait tout simplement au travers des sous-commandes
|
||||
relatives aux objets Docker `network` :
|
||||
relatives aux objets Docker `network` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -86,7 +86,7 @@ docker network create --driver bridge my_fic
|
|||
|
||||
C'est ensuite ce nom de réseau que vous passerez à l'option `--network` de vos
|
||||
`run`, ou vous pouvez également faire rejoindre un conteneur déjà lancé à un
|
||||
réseau :
|
||||
réseau :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -97,84 +97,3 @@ docker network connect NETWORK CONTAINER
|
|||
Lorsque plusieurs conteneurs ont rejoint un réseau utilisateur, ils peuvent
|
||||
mutuellement se découvrir grâce à un système de résolution de nom basé sur leur
|
||||
nom de conteneur.
|
||||
|
||||
|
||||
## Exercice {-}
|
||||
|
||||
À vous maintenant de connecter une instance de `nemunaire/fic-admin` à sa base
|
||||
de données.
|
||||
|
||||
Ne vous embêtez pas avec les mots de passes des services, initialisez la base
|
||||
de données avec le nom d'utilisateur et le mot de passe par défaut. Vous les
|
||||
obtiendrez en lisant la [documentation de l'image
|
||||
fic-admin](https://hub.docker.com/r/nemunaire/fic-admin/) :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker container run --rm -e MYSQL_HOST=mysql_cntr_name nemunaire/fic-admin -help
|
||||
```
|
||||
</div>
|
||||
|
||||
Notez la définition de la variable d'environnement `MYSQL_HOST`, celle-ci
|
||||
indique le nom du serveur vers lequel le service doit se connecter.
|
||||
|
||||
Vous aurez besoin de créer un volume pour stocker la base de données, un réseau
|
||||
dans lequel vous connecterez la base de données et le conteneur applicatif.
|
||||
|
||||
Une fois le service `fic-admin` lancé, vous pouvez exposer le port 8081, sur
|
||||
lequel vous devriez voir l'interface d'admin : <http://localhost:8081/>.
|
||||
|
||||
Placez les différentes commandes (volumes, réseau, `run`, ...) dans un
|
||||
script `ficadmin-run.sh`, que vous rendrez à la fin du TP. Vous
|
||||
devriez pouvoir appeler ce script plusieurs fois, sans que les données
|
||||
ne soient perdues, entre deux arrêts.
|
||||
|
||||
|
||||
### Exemple d'exécution
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ ./ficadmin-run.sh
|
||||
http://localhost:12345/
|
||||
42sh$ #docker kill db ficadmin
|
||||
42sh$ ./ficadmin-run.sh # le script relancera une base de données,
|
||||
# sans avoir perdu les données
|
||||
http://localhost:12345/
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### Au secours, ça veut pas se connecter !
|
||||
|
||||
Lorsque nous lançons pour la première fois notre conteneur MySQL ou MariaDB, un
|
||||
script est chargé d'initialisé le volume attaché à `/var/lib/mysql`. Les
|
||||
démarrage suivant, ou si vous réutilisez un volume déjà initialisé avec une
|
||||
base de données, le script ne refait pas d'initialisation. Même si les
|
||||
variables d'environnement ont changées.
|
||||
|
||||
Si vous rencontrez des difficultés pour connecter votre conteneur `fic-admin` à
|
||||
`my-db`, prenez le temps de recréer un volume.
|
||||
|
||||
|
||||
### Entrer dans un conteneur en cours d'exécution
|
||||
|
||||
Dans certaines circonstances, les journaux ne sont pas suffisants pour déboguer
|
||||
correctement l'exécution d'un conteneur.
|
||||
|
||||
En réalisant l'exercice, vous serez sans doute confronté à des comportements
|
||||
étranges, que vous ne pourriez comprendre qu'en ayant la main sur le conteneur,
|
||||
via un shell.
|
||||
|
||||
Lorsqu'un conteneur est actif, vous pouvez y lancer un nouveau processus,
|
||||
notamment un shell par exemple.
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker container exec -it ficadmin /bin/bash
|
||||
(inctnr)$ ping mysql_cntr_name
|
||||
```
|
||||
</div>
|
||||
|
||||
Notez qu'il n'est pas possible d'`exec` dans un conteneur éteint, et que si la
|
||||
commande initiale du conteneur se termine, tous les `exec` seront également
|
||||
tués.
|
||||
|
|
|
@ -17,7 +17,7 @@ pour se rendre sur la page de connexion. Une autre machine de votre réseau
|
|||
local devrait également pouvoir accéder à la plate-forme, simplement en
|
||||
renseignant l'IP de votre machine et en ajoutant éventuellement des règles de
|
||||
pare-feu (mais cette dernière partie n'est pas demandée, gardez simplement en
|
||||
tête que cela doit pouvoir être fait manuellement au cas par cas : sur une
|
||||
tête que cela doit pouvoir être fait manuellement au cas par cas : sur une
|
||||
machine sans pare-feu configurée, cela ne demande pas d'étape supplémentaire).
|
||||
|
||||
Votre script devra se limiter aux notions vues durant ce TP (ie. sans utiliser
|
||||
|
@ -67,7 +67,7 @@ Par ailleurs, n'oubliez pas de répondre à
|
|||
## Tarball
|
||||
|
||||
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:
|
||||
|
||||
|
@ -80,7 +80,7 @@ login_x-TP1/mycloud-run.sh
|
|||
|
||||
## Signature du rendu
|
||||
|
||||
Deux méthodes sont utilisables pour signer votre rendu :
|
||||
Deux méthodes sont utilisables pour signer votre rendu :
|
||||
|
||||
* signature du courriel ;
|
||||
* signature de la tarball.
|
||||
|
@ -106,7 +106,7 @@ signature.
|
|||
|
||||
#### No public key
|
||||
|
||||
Si vous recevez un rapport avec l'erreur suivante :
|
||||
Si vous recevez un rapport avec l'erreur suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -129,7 +129,7 @@ rendu.
|
|||
|
||||
#### Not explicit username
|
||||
|
||||
Si vous recevez un rapport avec l'erreur suivante :
|
||||
Si vous recevez un rapport avec l'erreur suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -144,7 +144,7 @@ données.
|
|||
|
||||
#### I've decided to skip your e-mail
|
||||
|
||||
Si vous recevez un rapport concluant ainsi :
|
||||
Si vous recevez un rapport concluant ainsi :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Stockage de données applicatives
|
||||
================================
|
||||
|
||||
Le concept principal de Docker est de concevoir des conteneurs applicatifs : on
|
||||
Le concept principal de Docker est de concevoir des conteneurs applicatifs : on
|
||||
va préférer assigner un unique rôle à un conteneur (donc généralement on ne va
|
||||
lancer qu'une seule application par conteneur) et concevoir un service complet
|
||||
en créant un groupe de conteneurs, partageant des données entre eux par des
|
||||
|
@ -25,21 +25,21 @@ Il est possible de monter un répertoire de la machine hôte dans un
|
|||
conteneur. L'intérêt reste plutôt limité à des fins de facilité ou de test, par
|
||||
exemple si vous voulez partager des fichiers avec votre voisin, en passant par
|
||||
le protocole HTTP, mais sans se casser la tête à installer et configurer un
|
||||
serveur web :
|
||||
serveur web :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker container run --rm -p 80:80 -v ~/Downloads:/usr/share/nginx/html:ro -d nginx
|
||||
docker run --rm -p 80:80 -v ~/Downloads:/usr/share/nginx/html:ro -d nginx
|
||||
```
|
||||
</div>
|
||||
|
||||
Une fois cette commande lancée, votre voisin pourra accéder à votre dossier
|
||||
Downloads en renseignant l'IP de votre machine dans son navigateur favori !
|
||||
Downloads en renseignant l'IP de votre machine dans son navigateur favori !
|
||||
|
||||
Par défaut, `nginx` ne va pas permettre de lister le contenu du répertoire (et
|
||||
va afficher une page 404, car il cherche un fichier `index.html` dans votre
|
||||
répertoire). Vous pouvez par contre accéder à un fichier directement, par
|
||||
exemple : <http://10.42.12.23/dQw4w9WgXcQ.mp4>
|
||||
exemple : <http://10.42.12.23/dQw4w9WgXcQ.mp4>
|
||||
|
||||
|
||||
## Les volumes
|
||||
|
@ -50,7 +50,7 @@ soucier de leur réel emplacement.
|
|||
|
||||
|
||||
Comme il s'agit d'un objet, la première chose à faire va être de créer notre
|
||||
volume :
|
||||
volume :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -59,7 +59,7 @@ docker volume create prod_foodp0m
|
|||
```
|
||||
</div>
|
||||
|
||||
Ensuite, nous pouvons démarrer un conteneur utilisant, par exemple :
|
||||
Ensuite, nous pouvons démarrer un conteneur utilisant, par exemple :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -67,7 +67,7 @@ docker container run --mount source=prod_youp0m,target=/images nemunaire/youp0m
|
|||
```
|
||||
</div>
|
||||
|
||||
On pourra également faire de même avec un conteneur MySQL :
|
||||
On pourra également faire de même avec un conteneur MySQL :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -86,7 +86,7 @@ Lorsque vous n'avez pas besoin de stocker les données et que vous ne désirez
|
|||
pas qu'elles persistent (des données sensibles par exemple) ou si cela peut
|
||||
améliorer les performances de votre conteneur, il est possible de créer des
|
||||
points de montages utilisant le système de fichiers `tmpfs` et donc résidant
|
||||
exclusivement en RAM\ :
|
||||
exclusivement en RAM\ :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -106,12 +106,15 @@ pour mettre à jour ou relancer un conteneur, sans perdre les données. Un autre
|
|||
intérêt est de pouvoir partager des fichiers entre plusieurs conteneurs.
|
||||
|
||||
Il est ainsi parfaitement possible de lancer deux conteneurs qui partagent le
|
||||
même volume :
|
||||
même volume :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker container run -d --mount source=prod_youp0m,target=/images -p 8080:8080 nemunaire/youp0m
|
||||
docker container run -d --mount source=prod_youp0m,target=/images -p 8081:8080 nemunaire/youp0m
|
||||
docker container run -d --mount source=prod_youp0m,target=/images \
|
||||
-p 8080:8080 nemunaire/youp0m
|
||||
|
||||
docker container run -d --mount source=prod_youp0m,target=/images \
|
||||
-p 8081:8080 nemunaire/youp0m
|
||||
```
|
||||
</div>
|
||||
|
||||
|
@ -119,7 +122,7 @@ Dans cet exemple, l'ajout d'une image dans un conteneur l'ajoutera également
|
|||
dans le second.
|
||||
|
||||
Un exemple plus intéressant serait sur une architecture de micro-services
|
||||
traitant des fichiers de grande taille : plutôt que de faire passer les
|
||||
traitant des fichiers de grande taille : plutôt que de faire passer les
|
||||
fichiers par un système de message/socket, on peut partager un volume pour
|
||||
épargner les coûts de transferts inutiles, lorsqu'ils ne changent pas de
|
||||
machine.
|
||||
|
|
|
@ -13,13 +13,13 @@ d'une socket.
|
|||
|
||||
Le client peut d'ailleurs ne pas être sur la même machine qui exécutera
|
||||
effectivement les conteneurs.[^dockermachine]
|
||||
C'est ce qu'il se passe lorsqu'on utilise *Docker4Windows* ou *Docker4Mac* :
|
||||
C'est ce qu'il se passe lorsqu'on utilise *Docker4Windows* ou *Docker4Mac* :
|
||||
une machine virtuelle Linux est lancée parallèlement au système de base et
|
||||
chaque commande `docker` tapée est passée au deamon dans la machine virtuelle.
|
||||
|
||||
[^dockermachine]: Il suffit de modifier la variable d'environnement
|
||||
`DOCKER_HOST` ou de passer le paramètre `-H` suivi de l'URL de la socket à
|
||||
`docker`. Voir aussi : <https://docs.docker.com/machine/overview/>
|
||||
`docker`. Voir aussi : <https://docs.docker.com/machine/overview/>
|
||||
|
||||
Commençons par planter le décor, en détaillant les principaux mécanismes de
|
||||
Docker.
|
||||
|
@ -30,17 +30,17 @@ Docker.
|
|||
Une image Docker est un système de fichiers en lecture seule. Elle est formée
|
||||
d'un ensemble de couches, agrégées selon le principe d'UnionFS.
|
||||
|
||||
Une image peut, par exemple, contenir :
|
||||
Une image peut, par exemple, contenir :
|
||||
|
||||
* un système Ubuntu opérationnel,
|
||||
* le programme `busybox`,
|
||||
* un serveur web et votre application web, prêts à l'emploi,
|
||||
* ...
|
||||
* ...
|
||||
|
||||
Les images sont utilisées comme **modèle** qui sera ensuite dupliqué à chaque
|
||||
fois que l'on démarrera un nouveau conteneur.
|
||||
|
||||
Il y a deux méthodes pour obtenir des images Docker : soit les construire avec
|
||||
Il y a deux méthodes pour obtenir des images Docker : soit les construire avec
|
||||
les outils fournis, soit les récupérer depuis un registre.
|
||||
|
||||
|
||||
|
@ -50,8 +50,8 @@ Les registres sont des plates-formes de stockage, publiques ou privées,
|
|||
contenant des images. Ils permettent de récupérer des images, mais également
|
||||
d'en envoyer.
|
||||
|
||||
Le registre utilisé de base est le [Docker Hub](https://hub.docker.com/) : il
|
||||
contient à la fois des images officielles (ubuntu, debian, nginx, ...), des
|
||||
Le registre utilisé de base est le [Docker Hub](https://hub.docker.com/) : il
|
||||
contient à la fois des images officielles (ubuntu, debian, nginx, ...), des
|
||||
images créées par des utilisateurs, mais aussi des images de grands éditeurs,
|
||||
payantes, à destination des entreprises.
|
||||
|
||||
|
@ -65,10 +65,10 @@ proposent également.
|
|||
### Les conteneurs Docker
|
||||
|
||||
Alors que les images constituent la partie immuable de Docker, les conteneurs
|
||||
sont sa partie vivante. Chaque conteneur est créé à partir d'une image : à
|
||||
sont sa partie vivante. Chaque conteneur est créé à partir d'une image : à
|
||||
chaque fois que nous lançons un conteneur, une couche lecture/écriture est
|
||||
ajoutée au dessus de l'image. Cette couche est propre au conteneur et
|
||||
temporaire : l'image n'est pas modifiée par l'exécution d'un conteneur.
|
||||
temporaire : l'image n'est pas modifiée par l'exécution d'un conteneur.
|
||||
|
||||
{ width=70% }
|
||||
|
||||
|
|
|
@ -113,10 +113,13 @@ Puis on lui demande la génération d'un rapport `html` :
|
|||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
paclair --conf conf.yml Docker nemunaire/fic-admin analyse --output-format html --output-report file
|
||||
paclair --conf conf.yml Docker nemunaire/fic-admin analyse \
|
||||
--output-format html --output-report file
|
||||
```
|
||||
</div>
|
||||
|
||||

|
||||
|
||||
Si l'on souhaite uniquement avoir des statistiques dans la console :
|
||||
|
||||
<div lang="en-US">
|
||||
|
|
|
@ -4,7 +4,7 @@ Si vous n'avez pas déjà le binaire `linuxkit`, vous pouvez télécharger ici
|
|||
<https://github.com/linuxkit/linuxkit/releases/latest>.
|
||||
|
||||
Notez qu'étant donné qu'il est écrit en Go, aucune dépendance n'est nécessaire
|
||||
en plus du binaire[^lollibc] ;-)
|
||||
en plus du binaire[^lollibc] ;-)
|
||||
|
||||
[^lollibc]: à condition tout de même que vous utilisiez une libc habituelle.
|
||||
|
||||
|
@ -17,17 +17,17 @@ Le fichier utilisé pour construire notre image se décompose en plusieurs
|
|||
parties :
|
||||
|
||||
- `kernel` : il est attendu ici une image OCI contenant le nécessaire pour
|
||||
pouvoir utiliser un noyau : l'image du noyau, ses modules et un initramfs ;
|
||||
pouvoir utiliser un noyau : l'image du noyau, ses modules et un initramfs ;
|
||||
- `init` : l'ensemble des images OCI de cette liste seront fusionnés pour
|
||||
donner naissance au *rootfs* de la machine. On n'y place normalement qu'un
|
||||
gestionnaire de conteneur, qui sera chargé de lancer chaque conteneur au bon
|
||||
moment ;
|
||||
moment ;
|
||||
- `onboot`, `onshutdown` et `services` : il s'agit de conteneurs qui seront
|
||||
lancés par le système disponible dans l'`init`, au bon moment. Les conteneurs
|
||||
indiqués dans `onboot` seront lancés **séquentiellement** au démarrage de la
|
||||
machine, ceux dans `onshutdown` seront lancés lors de l'arrêt de la
|
||||
machine. Les conteneurs dans `services` seront lancés simultanément une fois
|
||||
que le dernier conteneur de `onboot` aura rendu la main ;
|
||||
que le dernier conteneur de `onboot` aura rendu la main ;
|
||||
- `files` : des fichiers supplémentaires à placer dans le rootfs.
|
||||
|
||||
Le format est documenté
|
||||
|
@ -63,7 +63,7 @@ trust:
|
|||
</div>
|
||||
|
||||
L'image `getty` est très pratique pour déboguer, car elle permet d'avoir un
|
||||
shell sur la machine !
|
||||
shell sur la machine !
|
||||
|
||||
On notera cependant que, positionné dans `services`, le shell que nous
|
||||
obtiendrons sera lui-même exécuté dans un conteneur, nous n'aurons donc pas un
|
||||
|
@ -143,7 +143,7 @@ réutiliser plus tard ce chemin, en remplacement du mot clef `new` :
|
|||
Toute la puissance de `linuxkit` repose dans son système de construction et
|
||||
surtout de lancement. En effet, il peut construire des images pour un grand
|
||||
nombre de plate-forme, mais il est également possible d'utiliser les API de ces
|
||||
plates-formes pour aller y lancer des instances de cette image !
|
||||
plates-formes pour aller y lancer des instances de cette image !
|
||||
|
||||
Pour construire l'image faite précédemment :
|
||||
|
||||
|
@ -154,7 +154,7 @@ linuxkit build hello.yml
|
|||
</div>
|
||||
|
||||
Cela va générer plusieurs fichiers dont un noyau (extrait de l'image de la
|
||||
partie `kernel`) ainsi qu'une image. Exactement ce qu'attend QEMU ! Pour
|
||||
partie `kernel`) ainsi qu'une image. Exactement ce qu'attend QEMU ! Pour
|
||||
tester, n'attendons pas davantage pour lancer :
|
||||
|
||||
<div lang="en-US">
|
||||
|
@ -227,7 +227,7 @@ choix](https://www.vaultproject.io/docs/configuration/storage/index.html)
|
|||
|
||||
Au démarrage, Vault devra déjà être configuré pour parler à sa base de données,
|
||||
qui devra se trouver dans un conteneur isolé et non accessible d'internet. Il
|
||||
faudra donc établir un lien `virtual ethernet` entre les deux conteneurs ; et
|
||||
faudra donc établir un lien `virtual ethernet` entre les deux conteneurs ; et
|
||||
ne pas oublier de le configurer (automatiquement au *runtime*, grâce à un
|
||||
[`poststart`
|
||||
*hook*](https://github.com/opencontainers/runtime-spec/blob/master/config.md#posix-platform-hooks)
|
||||
|
|
|
@ -8,8 +8,8 @@ tirant parti des conteneurs. Il se positionne comme un système de construction
|
|||
de machine. En effet, grâce à lui, nous allons pouvoir générer des systèmes
|
||||
complets, *bootable* dans QEMU, VirtualBox, VMware ou même sur des machines
|
||||
physiques, qu'il s'agisse de PC ou bien même de Raspberry Pi, ou même encore
|
||||
des images pour les différents fournisseurs de cloud !
|
||||
des images pour les différents fournisseurs de cloud !
|
||||
|
||||
Bien entendu, au sein de ce système, tout est fait de conteneur ! Alors quand
|
||||
Bien entendu, au sein de ce système, tout est fait de conteneur ! Alors quand
|
||||
il s'agit de donner une IP publique utilisable par l'ensemble des conteneurs,
|
||||
il faut savoir jouer avec les *namespaces* pour arriver à ses fins !
|
||||
il faut savoir jouer avec les *namespaces* pour arriver à ses fins !
|
||||
|
|
|
@ -9,14 +9,14 @@ fragmentation de l'écosystème.
|
|||
|
||||
Trois spécifications ont été écrites :
|
||||
|
||||
- [`runtime-spec`](https://github.com/opencontainers/runtime-spec/blob/master/spec.md#platforms): définit les paramètres du démarrage d'un conteneur ;
|
||||
- [`image-spec`](https://github.com/opencontainers/image-spec/blob/master/spec.md): définit la construction, le transport et la préparation des images ;
|
||||
- [`runtime-spec`](https://github.com/opencontainers/runtime-spec/blob/master/spec.md#platforms): définit les paramètres du démarrage d'un conteneur ;
|
||||
- [`image-spec`](https://github.com/opencontainers/image-spec/blob/master/spec.md): définit la construction, le transport et la préparation des images ;
|
||||
- [`distribution-spec`](https://github.com/opencontainers/distribution-spec/blob/master/spec.md): définit la manière dont sont partagées et récupérées les images.
|
||||
|
||||
|
||||
## `runtime-spec`
|
||||
|
||||
`runc` est l'implémentation de cette spécification ; elle a été extraite de
|
||||
`runc` est l'implémentation de cette spécification ; elle a été extraite de
|
||||
`docker`, puis donnée par Docker Inc. à l'OCI.
|
||||
|
||||
Pour démarrer un conteneur, la spécification indique qu'il est nécessaire
|
||||
|
@ -82,5 +82,5 @@ effectivement nos conteneurs, c'est que l'on peut changer cette implémentation
|
|||
? la réponse dans l'article :
|
||||
<https://ops.tips/blog/run-docker-with-forked-runc/>
|
||||
|
||||
Et `containerd` dans l'histoire ?
|
||||
Et `containerd` dans l'histoire ?
|
||||
<https://hackernoon.com/docker-containerd-standalone-runtimes-heres-what-you-should-know-b834ef155426>
|
||||
|
|
|
@ -21,13 +21,13 @@ Hub](https://hub.docker.com/), le registre par défaut de `docker`, nous allons
|
|||
devoir nous plier à leur mécanisme d'authentification : chaque requête au
|
||||
registre doit être effectuée avec un jeton, que l'on obtient en s'authentifiant
|
||||
auprès d'un service dédié. Ce service peut délivrer un jeton sans authentifier
|
||||
l'interlocuteur, en restant anonyme ; dans ce cas, on ne pourra accéder qu'aux
|
||||
images publiques. Ça tombe bien, c'est ce qui nous intéresse aujourd'hui !
|
||||
l'interlocuteur, en restant anonyme ; dans ce cas, on ne pourra accéder qu'aux
|
||||
images publiques. Ça tombe bien, c'est ce qui nous intéresse aujourd'hui !
|
||||
|
||||
Il n'en reste pas moins que le jeton est forgé pour un service donné (dans
|
||||
notre cas `registry.docker.io`) et avec un objectif bien cerné (pour nous, on
|
||||
souhaite récupérer le contenu du dépôt[^quiddepot] `hello-world` :
|
||||
<span lang="en-US">`repository:hello-world:pull`</span>). Ce qui nous donne :
|
||||
Il n'en reste pas moins que le jeton est forgé pour un service donné (ici
|
||||
`registry.docker.io`) et avec un objectif bien cerné (pour nous, on souhaite
|
||||
récupérer le contenu du dépôt[^quiddepot] `hello-world` : <span
|
||||
lang="en-US">`repository:hello-world:pull`</span>). Ce qui nous donne :
|
||||
|
||||
[^quiddepot]: Dans un registre, les fichiers qui composent l'image forment un
|
||||
dépôt (*repository*).
|
||||
|
@ -58,7 +58,11 @@ Avec `jq`, on peut l'extraire grâce à :
|
|||
```
|
||||
</div>
|
||||
|
||||
**Attention :** le token expire ! Pensez à le renouveler régulièrement.
|
||||
::::: {.warning}
|
||||
|
||||
Le token expire ! Pensez à le renouveler régulièrement.
|
||||
|
||||
:::::
|
||||
|
||||
En cas d'erreur inexplicable, vous pouvez ajouter un `-v` à la ligne de
|
||||
commande `curl`, afin d'afficher les en-têtes. Prêtez une attention toute
|
||||
|
@ -94,12 +98,12 @@ système d'exploitation :
|
|||
curl -s \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-H "Accept: ${MEDIATYPE}" \
|
||||
"https://registry-1.docker.io/v2/library/hello-world/manifests/${MANIFEST_DIGEST}" | jq .
|
||||
"https://registry-1.docker.io/v2/library/hello-world/manifests/${MNFST_DGST}"
|
||||
```
|
||||
</div>
|
||||
|
||||
Nous voici donc maintenant avec le manifest de notre image. Nous pouvons
|
||||
constater qu'il n'a bien qu'une seule couche, ouf !
|
||||
constater qu'il n'a bien qu'une seule couche, ouf !
|
||||
|
||||
|
||||
## Récupération de la configuration et de la première couche
|
||||
|
@ -115,7 +119,7 @@ Pour récupérer la configuration de l'image :
|
|||
```bash
|
||||
curl -s --location \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
"https://registry-1.docker.io/v2/library/hello-world/blobs/${CONFIG_DIGEST}" | jq .
|
||||
"https://registry-1.docker.io/v2/library/hello-world/blobs/${CONFIG_DIGEST}"
|
||||
```
|
||||
</div>
|
||||
|
||||
|
@ -132,9 +136,11 @@ wget --header "Authorization: Bearer ${TOKEN}" \
|
|||
|
||||
## Extraction
|
||||
|
||||
Le type indiqué par le manifest pour cette couche était
|
||||
`application/vnd.docker.image.rootfs.diff.tar.gzip`, il s'agit donc d'une
|
||||
tarball compressée au format gzip :
|
||||
Le type indiqué par le manifest pour cette couche était :
|
||||
|
||||
application/vnd.docker.image.rootfs.diff.tar.gzip
|
||||
|
||||
Il s'agit donc d'une tarball compressée au format gzip :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -179,7 +185,7 @@ Pensez également à tester avec d'autres images, comme par exemple
|
|||
`nemunaire/youp0m`. Il vous faudra alors extraire plusieurs couches.
|
||||
|
||||
Pour gérer les différentes couches, vous pouvez utiliser une stratégie
|
||||
similaire au driver `vfs` : en extrayant chaque tarball l'une au dessus de
|
||||
similaire au driver `vfs` : en extrayant chaque tarball l'une au dessus de
|
||||
l'autre, en essayant de gérer les *whiteout files*. Ou bien en suivant le
|
||||
driver `overlayfs`, en montant un système de fichier à chaque couche (dans ce
|
||||
cas, votre script devra être lancé en `root`).
|
||||
|
|
|
@ -22,13 +22,13 @@ essayer de lancer un shell `alpine` avec un volume dans notre home.
|
|||
|
||||
Vous devriez avoir le binaire `runc` ou `docker-runc`. Si ce n'est pas le cas,
|
||||
vous pouvez télécharger la dernière version :
|
||||
<https://github.com/opencontainers/runc/releases>. La 1.0.0-rc92 est Ok.
|
||||
<https://github.com/opencontainers/runc/releases>.
|
||||
|
||||
|
||||
## Extraction du rootfs
|
||||
|
||||
À l'aide du script d'extraction de registre réalisé dans le TP 3, extrayons le
|
||||
rootfs d'alpine : `library/alpine` dans le registre Docker.
|
||||
À l'aide du script d'extraction de registre déjà réalisé, extrayons le
|
||||
*rootfs* d'alpine : `library/alpine` dans le registre Docker.
|
||||
|
||||
Si vous n'avez pas eu le temps de terminer le script d'extraction, vous pouvez
|
||||
utiliser :
|
||||
|
@ -55,9 +55,7 @@ runc spec
|
|||
Pour savoir à quoi correspondent tous ces éléments, vous pouvez consulter :
|
||||
<https://github.com/opencontainers/runtime-spec/blob/master/config.md>
|
||||
|
||||
Nous verrons dans les prochains TP, plus en détails tout ce qui porte sur les
|
||||
*namespaces*, rassurez-vous, il n'y a que très peu de champs à modifier
|
||||
aujourd'hui.
|
||||
Rassurez-vous, il n'y a que très peu de champs à modifier.
|
||||
|
||||
## Test brut
|
||||
|
||||
|
@ -143,8 +141,8 @@ stocker les photos (dossier `/srv/images`)[^chmod].
|
|||
simple pour l'instant serait d'attribuer les permissions `0777` à la
|
||||
source, temporairement.
|
||||
|
||||
Pour ce TP, considérez que vous avez réussi si vous voyez s'afficher :
|
||||
Pour cette étape, Considérez que vous avez réussi si vous voyez s'afficher :
|
||||
|
||||
> `Ready, listening on :8080`
|
||||
|
||||
Il faudra attendre les TP suivants pour avoir du réseau dans notre conteneur.
|
||||
On ne pourra pas tester davantage sans avoir du réseau dans notre conteneur.
|
||||
|
|
|
@ -10,10 +10,10 @@ machine hébergeant des conteneurs, car cela lui apporte des garanties quant à
|
|||
l'effort de cloisonnement mis en place.
|
||||
|
||||
Mais doit-on pour autant s'arrêter là et considérer que nous avons réglé
|
||||
l'ensemble des problématiques de sécurité liées aux conteneurs ?
|
||||
l'ensemble des problématiques de sécurité liées aux conteneurs ?
|
||||
|
||||
Évidemment, non : une fois nos services lancés dans des conteneurs, il ne sont
|
||||
pas moins exposés aux bugs et autres failles applicatives ; qu'elles soient
|
||||
pas moins exposés aux bugs et autres failles applicatives ; qu'elles soient
|
||||
dans notre code ou celui d'une bibliothèque, accessible par rebond, ...
|
||||
|
||||
Il est donc primordial de ne pas laisser ses conteneurs à l'abandon une fois
|
||||
|
@ -23,7 +23,7 @@ image telle que Debian, Ubuntu ou Redhat n'apparaît que pour cela) ou bien
|
|||
lorsqu'un des programmes ou l'une des bibliothèques que l'on a installés
|
||||
ensuite est mise à jour.
|
||||
|
||||
Convaincu ? Cela sonne encore comme des bonnes pratiques difficiles à mettre en
|
||||
Convaincu ? Cela sonne encore comme des bonnes pratiques difficiles à mettre en
|
||||
œuvre, pouvant mettre en péril tout un système d'information. Pour s'en
|
||||
protéger, nous allons avoir besoin de réaliser à intervalles réguliers une
|
||||
analyse statique de nos conteneurs.
|
||||
|
@ -42,9 +42,9 @@ automatiquement) les images que l'on publie sur un registre public, sans
|
|||
oublier de mettre à jour l'image de base.
|
||||
|
||||
D'ailleurs, avez-vous vérifié qu'une mise à jour de l'image `nemunaire/youp0m`
|
||||
n'était pas disponible depuis que vous avez commencé à l'utiliser ? Docker ne
|
||||
n'était pas disponible depuis que vous avez commencé à l'utiliser ? Docker ne
|
||||
vérifie jamais si une mise à jour des images que vous avez précédemment
|
||||
téléchargées. Pensez donc régulièrement à appeler :
|
||||
téléchargées. Pensez donc régulièrement à appeler :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -65,10 +65,11 @@ si vous n'en avez pas, nous verrons dans la section suivante `trivy` qui permet
|
|||
de réaliser ses scans directement sur notre machine, sans passer par un
|
||||
intermédiaire.
|
||||
|
||||
#### Attention {-}
|
||||
::::: {.warning}
|
||||
|
||||
Par cette méthode, vous êtes limité à 10 scans par mois.
|
||||
|
||||
:::::
|
||||
|
||||
### Installation du plugin
|
||||
|
||||
|
@ -82,13 +83,14 @@ préalablement connecté à votre compte Docker avec la commande `docker login`.
|
|||
Comme `docker scan` est un plugin, suivant la méthode d'installation que vous
|
||||
avez suivie, il n'a pas forcément été installé. Si vous obtenez un message
|
||||
d'erreur en lançant la commande, [voici comment récupérer le plugin et
|
||||
l'installer manuellement :](https://github.com/docker/scan-cli-plugin#on-linux)
|
||||
l'installer manuellement :](https://github.com/docker/scan-cli-plugin#on-linux)
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
mkdir -p ~/.docker/cli-plugins
|
||||
curl https://github.com/docker/scan-cli-plugin/releases/latest/download/docker-scan_linux_amd64 \
|
||||
-L -s -S -o ~/.docker/cli-plugins/docker-scan
|
||||
curl -L -s -S -o ~/.docker/cli-plugins/docker-scan \
|
||||
https://github.com/docker/scan-cli-plugin/releases/\
|
||||
latest/download/docker-scan_linux_amd64
|
||||
chmod +x ~/.docker/cli-plugins/docker-scan
|
||||
```
|
||||
</div>
|
||||
|
@ -96,7 +98,7 @@ chmod +x ~/.docker/cli-plugins/docker-scan
|
|||
### Utilisation
|
||||
|
||||
Une fois le plugin installé et la licence du service acceptée, nous pouvons
|
||||
commencer notre analyse :
|
||||
commencer notre analyse :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -112,7 +114,8 @@ Base image: alpine:3.14.2
|
|||
|
||||
✓ Tested 16 dependencies for known vulnerabilities, no vulnerable paths found.
|
||||
|
||||
According to our scan, you are currently using the most secure version of the selected base image
|
||||
According to our scan, you are currently using the most secure version of
|
||||
the selected base image
|
||||
```
|
||||
</div>
|
||||
|
||||
|
@ -128,10 +131,10 @@ Testing mysql...
|
|||
✗ High severity vulnerability found in gcc-8/libstdc++6
|
||||
Description: Insufficient Entropy
|
||||
Info: https://snyk.io/vuln/SNYK-DEBIAN10-GCC8-469413
|
||||
Introduced through: apt@1.8.2.3, mysql-community/mysql-community-client@8.0.26-1debian10, mysql-community/mysql-community-server-core@8.0.26-1debian10, mecab-ipadic@2.7.0-20070801+main-2.1, meta-common-packages@meta
|
||||
Introduced through: apt@1.8.2.3, mysql-community/mysql-community-client@[...]
|
||||
From: apt@1.8.2.3 > gcc-8/libstdc++6@8.3.0-6
|
||||
From: mysql-community/mysql-community-client@8.0.26-1debian10 > gcc-8/libstdc++6@8.3.0-6
|
||||
From: mysql-community/mysql-community-server-core@8.0.26-1debian10 > gcc-8/libstdc++6@8.3.0-6
|
||||
From: mysql-community/mysql-community-client@8.0.26-1debian10 > gcc-8[...]
|
||||
From: mysql-community/mysql-community-server-core@8.0.26-1debian10 > gcc-8[...]
|
||||
and 7 more...
|
||||
Image layer: Introduced by your base image (mysql:8.0.26)
|
||||
|
||||
|
@ -143,11 +146,12 @@ Base image: mysql:8.0.26
|
|||
|
||||
Tested 135 dependencies for known vulnerabilities, found 79 vulnerabilities.
|
||||
|
||||
According to our scan, you are currently using the most secure version of the selected base image
|
||||
According to our scan, you are currently using the most secure version of
|
||||
the selected base image
|
||||
```
|
||||
</div>
|
||||
|
||||
Ce dernier exemple est sans appel : `mysql` est une image officielle, et sa
|
||||
Ce dernier exemple est sans appel : `mysql` est une image officielle, et sa
|
||||
dernière version à l'écriture de ses lignes contient pas moins de 79
|
||||
vulnérabilités dont 11 *high*.
|
||||
|
||||
|
@ -168,7 +172,7 @@ un certain nombre d'arguments, notamment le nom de l'image à analyser.
|
|||
|
||||
### Utilisation
|
||||
|
||||
Tentons à nouveau d'analyser l'image `mysql` :
|
||||
Tentons à nouveau d'analyser l'image `mysql` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -189,7 +193,7 @@ Les résultats sont un peu différents qu'avec `docker scan`, mais on constate
|
|||
que l'image `mysql` contient vraiment de nombreuses vulnérabilités. Même si
|
||||
elles ne sont heureusement pas forcément exploitable directement.
|
||||
|
||||
Voyons maintenant s'il y a des différentes avec l'image `nemunaire/fic-admin` :
|
||||
Voyons maintenant s'il y a des différentes avec l'image `nemunaire/fic-admin` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -217,7 +221,7 @@ vulnérabilités de l'image, a aussi fait une analyse des dépendances du binair
|
|||
`/srv/admin`.
|
||||
|
||||
Trivy est en effet capable de rechercher des vulnérabilités par rapport aux
|
||||
dépendances connues de certains langages : Python, PHP, Node.js, .NET, Java,
|
||||
dépendances connues de certains langages : Python, PHP, Node.js, .NET, Java,
|
||||
Go, ...
|
||||
|
||||
|
||||
|
@ -225,7 +229,7 @@ Go, ...
|
|||
|
||||
Pour éviter de surcharger les serveurs de distributions de la base de données
|
||||
de vulnérabilités, nous devrions utiliser un cache pour faire nos
|
||||
analyses. Préférez lancer `trivy` avec les options suivantes :
|
||||
analyses. Préférez lancer `trivy` avec les options suivantes :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
@ -242,7 +246,7 @@ pouvoir l'exporter pour l'afficher dans un navigateur (par exemple pour le
|
|||
mettre à disposition des développeurs, lors d'une analyse automatique).
|
||||
|
||||
Pour ce faire, on peut ajouter les options suivantes à la ligne de commande de
|
||||
notre conteneur :
|
||||
notre conteneur :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -253,8 +257,6 @@ notre conteneur :
|
|||
En redirigeant la sortie standard vers un fichier, vous pourrez l'ouvrir dans
|
||||
votre navigateur favori.
|
||||
|
||||
---
|
||||
|
||||
{ width=90% }
|
||||
{ width=80% }
|
||||
|
||||
## Clair
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
\newpage
|
||||
|
||||
Création du cluster
|
||||
===================
|
||||
-------------------
|
||||
|
||||
## Le provisionnement de machine
|
||||
|
||||
Pour travailler sur un cluster, il faut avoir plusieurs machines ... au moins
|
||||
plus d'une !
|
||||
Pour travailler sur un cluster, il faut avoir plusieurs machines ... au moins
|
||||
plus d'une !
|
||||
|
||||
Mais qui dit plusieurs machines, dit généralement de nombreuses installations à
|
||||
faire, de nombreuses configurations à partager, etc. Tout ce qu'un
|
||||
administrateur système redoute : du travail !
|
||||
administrateur système redoute : du travail !
|
||||
|
||||
Évidemment, de nombreuses solutions existent pour travailler moins, tout en
|
||||
déployant plus et de manière plus fiable ! On peut parler
|
||||
déployant plus et de manière plus fiable ! On peut parler
|
||||
d'[`ansible`](https://www.ansible.com/), de
|
||||
[`chef`](https://docs.chef.io/provisioning.html), ou encore de
|
||||
[`puppet`](https://puppet.com/products/capabilities/automated-provisioning),
|
||||
... Toutes ces solutions permettent d'obtenir des configurations finement
|
||||
[`puppet`](https://puppet.com/products/capabilities/automated-provisioning), ...
|
||||
Toutes ces solutions permettent d'obtenir des configurations finement
|
||||
personnalisées, mais nécessitent une phase d'apprentissage plutôt lourde.
|
||||
|
||||
Comme nous voulons lancer des conteneurs, les machines à provisionner n'ont pas
|
||||
|
@ -25,9 +23,7 @@ besoin de configuration bien particulière et les seuls paquets importants sont
|
|||
une version récente de `docker` et ses dépendances.
|
||||
|
||||
|
||||
## Provisionner des machines ...
|
||||
|
||||
### Automagiquement
|
||||
### Provisionner des machines ...
|
||||
|
||||
La solution magique consiste à passer par `docker-machine` pour créer des
|
||||
machines virtuelles automatiquement provisionnées avec Docker.
|
||||
|
@ -38,21 +34,20 @@ virtuelles. Si votre machine Linux est en fait une machine virtuelle hébergée
|
|||
par VirtualBox sous Windows, vous allez sans doute préférer la deuxième
|
||||
solution, que d'utiliser PowerShell et Docker4Windows[^amazon].
|
||||
|
||||
[^amazon]: Vous pouvez aussi vous inscrire sur
|
||||
[Amazon Web Services](https://aws.amazon.com/), `docker-machine` est
|
||||
capable, à partir de vos
|
||||
[clefs d'API](https://docs.docker.com/machine/examples/aws/), de créer et
|
||||
lancer des machines dans le cloud ! Et ce n'est pas le seul service de
|
||||
[cloud supporté](https://docs.docker.com/machine/drivers/) !
|
||||
[^amazon]: Vous pouvez aussi vous inscrire sur [Amazon Web
|
||||
Services](https://aws.amazon.com/) <https://aws.amazon.com/>,
|
||||
`docker-machine` est capable, à partir de vos clefs d'API, de créer et
|
||||
lancer des machines dans le cloud ! Et ce n'est pas le seul service de
|
||||
cloud supporté !
|
||||
|
||||
|
||||
#### Créer une machine
|
||||
##### Créer une machine {-}
|
||||
|
||||
Pour créer une nouvelle machine, nous allons utiliser la commande
|
||||
`docker-machine create`, en prenant soin de préciser le pilote à utiliser, les
|
||||
éventuelles options que prend ce pilote, ainsi que le nom que vous souhaitez
|
||||
donner à cette machine (les machines ne sont pas considérées comme jetables,
|
||||
leur nom vous permettra par exemple de relancer une machine plus tard) :
|
||||
leur nom vous permettra par exemple de relancer une machine plus tard) :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -61,30 +56,33 @@ docker-machine create --driver virtualbox echinoidea
|
|||
</div>
|
||||
|
||||
Consultez la section suivante, réservée aux gens qui ne peuvent pas passer par
|
||||
`docker-machine` si vous souhaitez avoir plus d'information sur ce que fait
|
||||
`docker-machine`, si vous souhaitez avoir plus d'information sur ce que fait
|
||||
cette commande.
|
||||
|
||||
#### Commandes usuelles de `docker-machine`
|
||||
##### Commandes usuelles de `docker-machine` {-}
|
||||
|
||||
De la même manière que `docker`, vous pouvez lister les machines connues
|
||||
(`ls`), changer leur état d'exécution (`start`/`stop`/`kill`/`restart`) ou encore supprimer la machine (`rm`)
|
||||
(`ls`), changer leur état d'exécution (`start`/`stop`/`kill`/`restart`) ou
|
||||
encore supprimer une machine (`rm`).
|
||||
|
||||
Si vous avez besoin d'obtenir un shell : `docker-machine ssh $NAME` et
|
||||
Si vous avez besoin d'obtenir un shell : `docker-machine ssh $NAME` et
|
||||
évidemment la commande `scp` s'utilise de la même manière, pour transférer des
|
||||
fichiers.
|
||||
|
||||
#### Utilisation avec Docker
|
||||
##### Utilisation avec Docker {-}
|
||||
|
||||
Rappelez-vous, au cours précédent, nous avions évoqué le fait que le deamon
|
||||
pouvait ne pas se trouver sur la même machine que le client `docker`. Eh bien
|
||||
avec `docker-machine` cela prend tout son sens, car vous pouvez très facilement
|
||||
changer de daamon/machine avec une simple commande :
|
||||
Nous avons déjà évoqué le fait que le deamon pouvait ne pas se trouver sur la
|
||||
même machine que le client `docker`. Eh bien avec `docker-machine` cela prend
|
||||
tout son sens, car vous pouvez très facilement changer de daemon/machine avec
|
||||
une simple commande :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ docker container ls
|
||||
42sh$ docker container ls -a
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS
|
||||
|
||||
42sh$ eval $(docker-machine env echinoidea)
|
||||
|
||||
42sh$ docker container ls -a
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS
|
||||
a814293b9f45 armbuild/busybox "/bin/sh" 18 seconds ago Up 10 minutes
|
||||
|
@ -102,43 +100,44 @@ supprimer manuellement les variables qui ont été ajoutées par l'évaluation,
|
|||
soit lancer `eval $(docker machine env -u)`.
|
||||
|
||||
|
||||
### Automanuellement
|
||||
#### Derrière Docker Machine...
|
||||
|
||||
Si votre environnement ne vous permet pas d'utiliser `docker-machine`, vous
|
||||
pouvez vous contenter aujourd'hui de démarrer une ou deux autres machines
|
||||
virtuelles sur le même réseau que votre machine actuelle.
|
||||
pouvez vous contenter de démarrer une ou deux autres machines virtuelles sur le
|
||||
même réseau que votre machine virtuelle.
|
||||
|
||||
Rassurez-vous, vous n'allez pas avoir besoin de refaire toute la phase
|
||||
d'installation. Des contributeurs maintiennent une petite ISO ne contenant que
|
||||
le strict nécessaire pour utiliser Docker. C'est d'ailleurs cette ISO qui est
|
||||
utilisé par `docker-machine` pour démarrer et configurer en un rien de temps
|
||||
ses machines virtuelles.
|
||||
d'installation. Des contributeurs ont conçu une petite image de CD ne contenant
|
||||
que le strict nécessaire pour utiliser Docker. C'est d'ailleurs cette ISO qui
|
||||
est utilisée par `docker-machine` pour démarrer et configurer en un rien de
|
||||
temps ses machines virtuelles.
|
||||
|
||||
1. Dans un premier temps, commençons par
|
||||
[télécharger la dernière ISO de `boot2docker.iso`](https://github.com/boot2docker/boot2docker/releases/latest).
|
||||
1. Dans un premier temps, commençons par télécharger la dernière ISO de
|
||||
`boot2docker.iso` :\
|
||||
<https://github.com/boot2docker/boot2docker/releases/latest>
|
||||
1. Ensuite, dans notre hyperviseur, créons deux nouvelles machines, avec
|
||||
suffisamment de ressources pour pouvoir lancer des conteneurs. Ce n'est pas
|
||||
parce que l'images que l'on va démarrer est petite, que l'on ne va pas
|
||||
parce que l'image que l'on va démarrer est petite que l'on ne va pas
|
||||
pouvoir allouer beaucoup d'espace disque ou de RAM.
|
||||
1. Lançons ensuite nos deux images, configurées pour démarrer sur l'image ISO
|
||||
que l'on a téléchargée précédemment.
|
||||
1. Faisons un `ip a` pour connaître l'IP de la machine, nous devrions pouvoir
|
||||
s'y connecter en SSH avec l'utilisateur `docker` dont le mot de passe est
|
||||
nous y connecter en SSH avec l'utilisateur `docker` dont le mot de passe est
|
||||
`tcuser`.
|
||||
|
||||
Vous constaterez que le daemon `dockerd` est déjà lancé. `docker` est déjà
|
||||
pleinement utilisable dans cette machine !
|
||||
pleinement utilisable dans cette machine !
|
||||
|
||||
|
||||
#### (Optionnel) Déporter le client Docker
|
||||
|
||||
Dans le suite de ce TP, nous n'allons taper que quelques commandes dans nos
|
||||
Dans la suite, nous n'allons taper que quelques commandes dans nos
|
||||
machines virtuelles, il n'est donc pas primordial d'avoir configuré son
|
||||
environnement pour utiliser localement les daemons Docker des machines
|
||||
virtuelles. Néanmoins, cela ne coûte rien de voir les procédures mise en œuvre.
|
||||
|
||||
Commençons par voir sur quel port le daemon `dockerd` de notre machine
|
||||
virtuelle écoute :
|
||||
virtuelle écoute :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -148,26 +147,25 @@ tcp 0 0 :::2376 :::* 980/dockerd
|
|||
```
|
||||
</div>
|
||||
|
||||
Essayons de renseigner simplement cette configuration à notre client Docker :
|
||||
Essayons de renseigner simplement cette configuration à notre client Docker :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
(main) 42sh$ docker -H tcp://$VM1_IP:2376/ info
|
||||
Get http://$VM1_IP:2376/v1.32/info: net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x15\x03\x01\x00\x02\x02".
|
||||
Get http://$VM1_IP:2376/v1.32/info: net/http: transport connection broken
|
||||
* Are you trying to connect to a TLS-enabled daemon without TLS?
|
||||
```
|
||||
</div>
|
||||
|
||||
En effet, Docker met tout en œuvre pour rendre compliqué l'utilisation
|
||||
En effet, Docker met tout en œuvre pour rendre compliquée l'utilisation
|
||||
non-sécurisée de la plate-forme. Mais ils font également en sorte que la
|
||||
sécurité soit la plus transparente et la moins contraignante possible pour
|
||||
l'utilisateur, sans pour autant être faible.
|
||||
|
||||
Afin de contacter un daemon Docker distant, il est nécessaire présenter un
|
||||
certificat client TLS approuvé par ce daemon (comme lorsque vous vous connectez
|
||||
sur [Epitaf](https://www.epitaf.fr/moodle)). Il est également nécessaire de
|
||||
certificat client TLS approuvé par ce daemon. Il est seulement nécessaire de
|
||||
vérifier le certificat présenté par le daemon, comme dans le cadre d'une
|
||||
connexion TLS classique.
|
||||
connexion SSH classique.
|
||||
|
||||
Tout le nécessaire est déjà configuré au sein de `boot2docker`, pour nos tests,
|
||||
nous n'avons qu'à recopier la clef et les certificats en place.
|
||||
|
@ -182,12 +180,12 @@ key.pem
|
|||
```
|
||||
</div>
|
||||
|
||||
Tentons maintenant de nous connecter au daemon distant en utilisant ces éléments :
|
||||
Tentons maintenant de nous connecter au daemon distant utilisant ces éléments :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ DOCKER_CERT_PATH=remote/virt1/ docker -H tcp://$VM1_IP:2376/ --tlsverify info
|
||||
DOCKER_CERT_PATH=remote/vir1/ docker -H tcp://$VM1_IP:2376/ --tlsverify info
|
||||
```
|
||||
</div>
|
||||
|
||||
Vous pouvez effectuer la même opération pour la seconde VM.
|
||||
Nous pouvons effectuer la même opération pour la seconde machine virtuelle.
|
||||
|
|
|
@ -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, ...).
|
||||
|
||||
Voici une arborescence type (vous pourriez avoir des fichiers supplémentaires,
|
||||
cela dépendra de votre avancée dans le projet) :
|
||||
cela dépendra de votre avancée dans le projet) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
@ -1,42 +1,35 @@
|
|||
\newpage
|
||||
|
||||
Mise en place
|
||||
=============
|
||||
-------------
|
||||
|
||||
Pour cette partie, nous allons avoir besoin de `docker-machine`, installons-le sur
|
||||
notre machine hôte, même si ce n'est pas un Linux : le but va être de lancer
|
||||
plusieurs machines virtuelles dédiées à Docker pour simuler un cluster.
|
||||
|
||||
## `docker-machine`
|
||||
|
||||
Pour ce TP, nous allons avoir besoin de `docker-machine`, installez-le sur
|
||||
votre machine hôte, même si ce n'est pas un Linux : le but va être de lancer
|
||||
plusieurs machines virtuelles Docker pour simuler un cluster.
|
||||
|
||||
Ce programme permet de simplifier la gestion du multiples environnements
|
||||
Docker, comme par exemple lorsque l'on souhaite gérer un cluster de machines
|
||||
Ce programme permet de simplifier la gestion de multiples environnements
|
||||
Docker, comme par exmple lorsque l'on souhaite gérer un cluster de machines
|
||||
pour un projet.
|
||||
|
||||
Ainsi, il est possible de provisionner et gérer des machines hôtes sur les
|
||||
plates-formes de cloud habituelles. C'est également ce projet qui est à la base
|
||||
de *Docker for Mac* et *Docker for Windows*, en permettant de lancer via,
|
||||
respectivement, VirtualBox et Hyper-V, un environnement Linux prêt à être
|
||||
utilisé avec Docker.
|
||||
de *Docker Dektop*, en permettant de lancer via, respectivement, VirtualBox ou
|
||||
Hyper-V, un environnement Linux prêt à être utilisé avec Docker.
|
||||
|
||||
### Par la distribution binaire
|
||||
|
||||
L'équipe en charge de `docker-machine` met à disposition un exécutable compilé
|
||||
pour bon nombres d'environnements. Nous pouvons l'installer en suivant la
|
||||
procédure suivante :
|
||||
pour bon nombre d'environnements. Nous pouvons l'installer en suivant la
|
||||
procédure suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
curl -L https://github.com/docker/machine/releases/download/v0.15.0/docker-machine-Linux-x86_64 \
|
||||
V=0.16.2
|
||||
P=docker-machine-`uname -s`-`uname -m`
|
||||
curl -L https://github.com/docker/machine/releases/download/v${V}/${P} \
|
||||
> /usr/bin/docker-machine
|
||||
chmod +x /usr/bin/docker-machine
|
||||
```
|
||||
</div>
|
||||
|
||||
Si vous êtes dans un environnement différent, jetez un œil à
|
||||
[la documentation d'installation](https://docs.docker.com/machine/install-machine/).
|
||||
|
||||
|
||||
### Support de KVM
|
||||
|
||||
|
@ -46,28 +39,30 @@ plug-ins.
|
|||
|
||||
Si vous utilisez KVM comme hyperviseur, vous allez avoir besoin d'installer le
|
||||
plugins
|
||||
[`docker-machine-kvm`](https://github.com/dhiltgen/docker-machine-kvm). Vous
|
||||
n'aurez qu'à suivre les instructions du
|
||||
[`README`](https://github.com/dhiltgen/docker-machine-kvm/blob/master/README.md)
|
||||
!
|
||||
[`docker-machine-kvm`](https://github.com/machine-drivers/docker-machine-kvm). Vous
|
||||
n'aurez qu'à suivre les instructions du `README` :\
|
||||
<https://github.com/machine-drivers/docker-machine-kvm/>
|
||||
|
||||
Les autres plugins sont disponibles au sein de l'organisation Machine-Driver
|
||||
sur GitHub :\
|
||||
<https://github.com/machine-drivers/>
|
||||
|
||||
### Vérification du fonctionnement
|
||||
|
||||
Comme avec Docker, nous pouvons vérifier le bon fonctionnement de
|
||||
`docker-machine` en exécutant la commande :
|
||||
`docker-machine` en exécutant la commande :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ docker-machine version
|
||||
docker-machine version 0.12.2, build 9371605
|
||||
docker-machine version 0.16.2, build 9371605
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
## Play With Docker
|
||||
### Play With Docker
|
||||
|
||||
Tout comme pour le TP précédent, si vous avez des difficultés pour réaliser les
|
||||
exercices sur vos machines, vous pouvez utiliser le projet
|
||||
[Play With Docker](https://play-with-docker.com/) qui vous donnera accès à un
|
||||
bac à sable avec lequel vous pourrez réaliser tous les exercices de ce TP.
|
||||
Si vous avez des difficultés pour réaliser les exercices sur votre machine,
|
||||
vous pouvez utiliser le projet [Play With
|
||||
Docker](https://play-with-docker.com/) qui vous donnera accès à un bac à sable
|
||||
avec lequel vous pourrez réaliser tous les exercices de cette partie.
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
\newpage
|
||||
|
||||
Déploiement de services
|
||||
=======================
|
||||
-----------------------
|
||||
|
||||
## Services ?
|
||||
### Services ?
|
||||
|
||||
Une petite minute terminologie avant de continuer, car lorsque l'on passe sur
|
||||
les clusters de Docker, cela change un peu :
|
||||
les clusters de Docker, cela change un peu :
|
||||
|
||||
* une *tâche* correspond à **un** unique conteneur, lancé sur l'un des nœuds
|
||||
*workers* du cluster ;
|
||||
*workers* du cluster ;
|
||||
* un *service* est un groupe de tâches (oui, les tâches du point précédent),
|
||||
exécutant la même image.
|
||||
|
||||
|
@ -18,13 +18,13 @@ la haute-disponibilité ou pour répartir la charge.
|
|||
|
||||
|
||||
<div lang="en-US">
|
||||
### Hello world, again?
|
||||
#### Hello world, again?
|
||||
</div>
|
||||
|
||||
Non, pas d'hello-world ici, mais nous allons prendre en main les services avec
|
||||
un serveur web, qui sera bien plus représentatif de ce que l'on pourra obtenir.
|
||||
|
||||
Précédemment, nous lancions notre serveur web favori avec :
|
||||
Précédemment, nous lancions notre serveur web favori avec :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -33,7 +33,7 @@ docker container run --name mywebs -d nginx
|
|||
</div>
|
||||
|
||||
La même commande, mais déployée à partir d'un nœud manager, vers un nœud
|
||||
*workers*, est :
|
||||
*workers*, est :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -41,7 +41,7 @@ docker service create --name myWebS nginx
|
|||
```
|
||||
</div>
|
||||
|
||||
Allons-y, essayons !
|
||||
Allons-y, essayons !
|
||||
|
||||
On peut consulter l'état du service avec, comme d'habitude `ls` :
|
||||
|
||||
|
@ -59,7 +59,7 @@ déployé, le tâche apparaît dans la liste des conteneurs !
|
|||
|
||||
Rien de très excitant pour le moment, car nous ne pouvons pas vraiment accéder
|
||||
à notre serveur. Essayons de modifier sa configuration en direct, afin
|
||||
d'ajouter une redirection de port :
|
||||
d'ajouter une redirection de port :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -71,13 +71,13 @@ docker service update --publish-add 80 myWebS
|
|||
service sont stoppés puis, le manager voyant que le service n'est pas dans
|
||||
l'état demandé, va lancer des tâches avec la nouvelle configuration.
|
||||
|
||||
La commande `update` est très puissante : vous pouvez mettre à jour
|
||||
La commande `update` est très puissante : vous pouvez mettre à jour
|
||||
pratiquement n'importe quel élément de configuration, y compris le nom de
|
||||
l'image ou son tag. Grâce à cela, faire des mises à jour se fait de manière
|
||||
transparente.
|
||||
|
||||
|
||||
#### Magie du mesh
|
||||
##### Magie du mesh {-}
|
||||
|
||||
Lorsque l'on publie un port de cette manière, chaque nœud du cluster devient un
|
||||
point d'entrée pour ce port, même si la tâche ne s'exécute pas sur ce nœud
|
||||
|
@ -88,25 +88,26 @@ nœuds. Vous devriez voir la même page.
|
|||
|
||||
Lorsque plusieurs tâches s'exécutent pour ce service, le nœud d'entrée choisi
|
||||
selon un round-robin à quelle tâche il va diriger la requête. C'est grâce à ce
|
||||
mécanisme qu'il est possible faire une répartition de charge très simplement.
|
||||
mécanisme qu'il est possible de faire de la répartition de charge très
|
||||
simplement.
|
||||
|
||||
\vspace{1.5em}
|
||||
|
||||
Cette méthode n'est pas la seule permettant d'exposer des ports. Mais c'est
|
||||
sans doute la plus intuitive. Si vous souhaitez en apprendre plus, vous deviez
|
||||
consulter la
|
||||
[documentation à ce sujet](https://docs.docker.com/engine/swarm/networking/).
|
||||
sans doute la plus intuitive. Si vous souhaitez en apprendre plus, vous devriez
|
||||
consulter la documentation à ce sujet :\
|
||||
<https://docs.docker.com/engine/swarm/networking/>
|
||||
|
||||
|
||||
### Mise à l'échelle et placement
|
||||
#### Mise à l'échelle et placement
|
||||
|
||||
On parle depuis toute à l'heure de lancer plusieurs tâches pour le même
|
||||
service. La mise à l'échelle c'est ça : exécuter plusieurs conteneurs pour la
|
||||
service. La mise à l'échelle, c'est ça : exécuter plusieurs conteneurs pour la
|
||||
même tâche afin de mieux répartir la charge, idéalement sur des machines
|
||||
physique différentes.
|
||||
physiques différentes.
|
||||
|
||||
Ce qui se fait souvent avec beaucoup de douleur hors de Docker, se résume ici à
|
||||
:
|
||||
Ce qui se fait souvent avec beaucoup de douleur hors de Docker, se résume ici
|
||||
à :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -122,21 +123,21 @@ docker service ps myWebS
|
|||
```
|
||||
</div>
|
||||
|
||||
nous montre bien, a priori 3 tâches en cours d'exécution pour ce service !
|
||||
nous montre bien, a priori 3 tâches en cours d'exécution pour ce service !
|
||||
|
||||
Enfin, vous avez compris le principe !
|
||||
Enfin, vous avez compris le principe !
|
||||
|
||||
|
||||
## Stack ?
|
||||
### Stack ?
|
||||
|
||||
Refermons cette longue parenthèse et revenons-en au sujet du jour : la
|
||||
Refermons cette longue parenthèse et revenons-en au sujet du jour : la
|
||||
supervision de nos machines.
|
||||
|
||||
Une *stack* est un groupe de services. Un projet, par exemple un site web dans
|
||||
son ensemble : frontend, API, base de données, ...
|
||||
son ensemble : frontend, API, base de données, ...
|
||||
|
||||
Notre système de monitoring est une *stack* lui aussi, d'ailleurs, nous pouvons
|
||||
la lancer grâce à notre `docker-compose.yml` :
|
||||
la lancer grâce à notre `docker-compose.yml` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -144,7 +145,7 @@ docker stack deploy --compose-file docker-compose.yml tic
|
|||
```
|
||||
</div>
|
||||
|
||||
### Règle de déploiement
|
||||
#### Règle de déploiement
|
||||
|
||||
Par rapport à `docker-compose`, nous pouvons indiquer dans ce fichier des
|
||||
paramètres qui ne serviront qu'au déploiement de notre tâche.
|
||||
|
|
|
@ -1,61 +1,13 @@
|
|||
\newpage
|
||||
|
||||
Déploiement de conteneurs
|
||||
=========================
|
||||
|
||||
Historiquement, le passage d'une application en production ou simplement dans
|
||||
un environnement de qualification, n'est pas toujours aisé. Parfois d'ailleurs,
|
||||
on ne teste pas, on fait les modifications en production ... et à chaque
|
||||
déploiement, on prie pour ne pas écraser une modification qui faisait que notre
|
||||
projet tombait en marche dans cet environnement.
|
||||
|
||||
Déployer des conteneurs sur sa propre machine, c'est extrêmement simple
|
||||
grâce. Et mieux encore, tout l'environnement étant contenu dans l'image, il
|
||||
suffit de suivre les bonnes pratiques pour que le déploiement en production se
|
||||
fasse de manière transparente.
|
||||
|
||||
|
||||
## L'orchestration
|
||||
|
||||
Cependant, notons une différence de taille entre notre environnement de
|
||||
développement sur nos machines locales et la production : les clients ! Pour
|
||||
répondre de manière adéquate, il convient de dimensionner correctement les
|
||||
machines, le nombre de conteneurs que chacune peut exécuter, en fonction de
|
||||
caractéristiques (on privilégiera les machines avec des SSD pour les serveurs
|
||||
de base de données par exemple), ...
|
||||
|
||||
Il n'est pas question pour un administrateur système de faire cette répartition
|
||||
de la charge à la main : le nombre de critères à prendre en compte est beaucoup
|
||||
trop grand, évolue sans cesse ; cela serait trop long s'il y a beaucoup de
|
||||
conteneurs et de variété de machines.
|
||||
|
||||
Ce processus d'optimisation s'appelle l'*orchestration*. Il s'agit de réussir à
|
||||
répartir au mieux les conteneurs sur les différentes machines disponibles.
|
||||
|
||||
Ce sujet fait l'objet de très nombreuses thèse depuis plusieurs années (avant
|
||||
les conteneurs, c'était pour répartir les machines virtuelles entre différents
|
||||
hôtes), et autant de projets disponibles. Citons par exemple
|
||||
[Google Kubernetes](https://kubernetes.io),
|
||||
[Hashicorp Nomad](https://www.nomadproject.io/) ou encore
|
||||
[Apache Mesos](https://mesos.apache.org/), ...
|
||||
|
||||
Le point commun entre la plupart des orchestrateurs, c'est généralement leur
|
||||
extrême complexité de mise en œuvre. Dans le cadre de notre TP, nous allons
|
||||
plutôt utiliser l'orchestrateur intégré à Docker, dont la caractéristique
|
||||
principale est sa simplicité[^dockerconEU2017].
|
||||
|
||||
[^dockerconEU2017]: À noter qu'une annonce faite à la Docker Con EU
|
||||
2017 indique le début du support de Kubernetes au sein de Docker
|
||||
EE, pouvant être utilisé en symbiose avec Swarm.
|
||||
|
||||
|
||||
### Concepts clefs
|
||||
-------------------------
|
||||
|
||||
Regroupés au sein d'un cluster (on parle de *swarm* pour Docker), chaque
|
||||
*Docker engine* représente un nœud (*node*) dans lequel on va déployer des
|
||||
*services*.
|
||||
|
||||
Certain nœud ont un rôle de *manager*, parmi ceux-ci, un seul est élu leader et
|
||||
Certain nœuds ont un rôle de *manager*, parmi ceux-ci, un seul est élu leader et
|
||||
prendra les décisions d'orchestration. Les autres sont là pour prendre le
|
||||
relais en cas de dysfonctionnement sur le manager élu.
|
||||
|
||||
|
@ -66,15 +18,16 @@ cluster. En cas de crash d'un manager ou d'un *worker*, le (nouveau) manager
|
|||
fera en sorte de redéployer les conteneurs perdus, afin de toujours maintenir
|
||||
le cluster dans l'état désiré.
|
||||
|
||||
En terme de cluster, des tâches sont l'équivalent des conteneurs, hors de Swarm.
|
||||
En termes de cluster, des tâches sont l'équivalent des conteneurs, hors de
|
||||
Swarm.
|
||||
|
||||
|
||||
## Création du cluster Swarm
|
||||
### Création du cluster Swarm
|
||||
|
||||
### Initialisation du cluster
|
||||
#### Initialisation du cluster
|
||||
|
||||
La première chose à faire, est d'initialiser un cluster swarm. Pour se faire,
|
||||
ce n'est pas plus compliqué que de faire :
|
||||
La première chose à faire est d'initialiser un cluster Swarm. Pour se faire,
|
||||
ce n'est pas plus compliqué que de faire :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -88,14 +41,14 @@ cluster, afin de pouvoir lancer des tâches ... au moins sur lui-même en
|
|||
attendant d'autres nœuds.
|
||||
|
||||
|
||||
### Rejoindre le cluster
|
||||
#### Rejoindre un cluster
|
||||
|
||||
Pour rejoindre un cluster, il est nécessaire d'avoir le jeton associé à ce
|
||||
cluster.
|
||||
|
||||
La commande pour rejoindre le cluster et contenant le jeton, est indiquée
|
||||
La commande pour rejoindre un cluster et contenant le jeton est iniquée
|
||||
lorsque vous initialisez le cluster. Si vous avez raté la sortie de la
|
||||
commande, vous pouvez retrouver le jeton avec :
|
||||
commande, vous pouvez retrouver le jeton avec :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -106,17 +59,11 @@ docker swarm join-token worker
|
|||
Lançons maintenant la commande `join` indiquée, sur une autre machine, en
|
||||
utilisant `docker-machine`.
|
||||
|
||||
**Pro tips:** envoyez votre commande `join` à votre voisin qui a réussi à
|
||||
provisionner plusieurs machines Docker (via `docker-machine` ou manuellement,
|
||||
peu importe du moment que les VMs ont bien accès au même réseau que votre
|
||||
*Swarm*[^avertVM]). Et soyez fair-play, attendez un peu avant de lancer
|
||||
l'image `embano1/cpuburn` ;)
|
||||
|
||||
[^avertVM]: Si vous utilisez Docker dans une VM, il faut que celle-ci soit
|
||||
configurée en mode bridge pour qu'elle soit sur le même sous-réseau. Il n'y
|
||||
a pas de problème à avoir des nœuds *workers* derrière un NAT, mais il est
|
||||
primordial que les managers soient joignables. Vous pouvez tenter de faire
|
||||
des redirections de ports, mais le résultat n'est pas garanti !
|
||||
des redirections de ports, mais le résultat n'est pas garanti !
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
@ -125,11 +72,12 @@ docker swarm join --token SWMTKN-1-...-... 10.10.10.42:2377
|
|||
```
|
||||
</div>
|
||||
|
||||
Une fois rejoint, vous devriez voir apparaître un nouveau nœud *worker* dans :
|
||||
Une fois rejoint, vous devriez voir apparaître un nouveau nœud *worker* dans :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ eval $(docker-machine env -u)
|
||||
|
||||
42sh$ docker node ls
|
||||
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
|
||||
y9skzvuf989hjrkciu8mnsy echinoidea Ready Active
|
||||
|
@ -138,21 +86,21 @@ ovgh6r32kgcbswb2we48br1 * wales Ready Active Leader
|
|||
</div>
|
||||
|
||||
|
||||
### Rejoindre en tant que manager
|
||||
#### Rejoindre en tant que manager
|
||||
|
||||
Lorsqu'il est nécessaire d'avoir de la haute-disponibilité, on définit
|
||||
plusieurs managers. Cela permet qu'en cas de dysfonctionnement du manager, un
|
||||
nouveau manager soit élu.
|
||||
|
||||
Nous n'allons pas faire rejoindre de manager supplémentaire durant ce TP, mais
|
||||
Nous n'allons pas faire rejoindre de manager supplémentaire à ce stade, mais
|
||||
vous pouvez facilement expérimenter la chose en lançant 5 machines virtuelles
|
||||
et en définissant trois des cinq machines comme étant managers.
|
||||
|
||||
Pour que l'algorithme de consensus fonctionne de manière optimale, il convient
|
||||
toujours un nombre impair de managers, Docker en recommande 3 ou 5. La pire
|
||||
configuration est avec deux managers, car si un tombe, il ne peut pas savoir si
|
||||
c'est lui qui est isolé (auquel cas il attendrait d'être à nouveau en ligne
|
||||
avant de se proclamer leader) ou si c'est l'autre manager qui est tombé. Avec
|
||||
trois managers, en cas de perte d'un manager, les deux restants peuvent
|
||||
considérer qu'ils ont perdu le troisième et peuvent élire le nouveau manager
|
||||
entre-eux et continuer à faire vivre le cluster.
|
||||
de toujours avoir un nombre impair de managers : Docker en recommande 3
|
||||
ou 5. La pire configuration est avec deux managers, car si l'un des deux tombe,
|
||||
il ne peut pas savoir si c'est lui qui est isolé (auquel cas il attendrait
|
||||
d'être à nouveau en ligne avant de se procalmer leader) ou si c'est l'autre qui
|
||||
est tombé. Avec trois managers, en cas de perte d'un manager, les deux restants
|
||||
peuvent considérer qu'ils ont perdu le troisième et peuvent élire le nouveau
|
||||
manager entre eux et continuer à faire vivre le cluster.
|
||||
|
|
|
@ -6,7 +6,7 @@ institute: EPITA
|
|||
date: Jeudi 18 octobre 2018
|
||||
abstract: |
|
||||
Dans la troisième partie de ce TP, nous allons orchestrer nos
|
||||
conteneurs !
|
||||
conteneurs !
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
\newpage
|
||||
|
||||
Ma première image ... par `Dockerfile`
|
||||
Ma première image ... par `Dockerfile`
|
||||
--------------------------------------
|
||||
|
||||
Pour construire une image, nous ne sommes pas obligés de passer par une série
|
||||
|
@ -22,7 +22,7 @@ l'intitulé d'une instruction (que l'on écrit généralement en majuscule), ell
|
|||
est suivie de ses arguments.
|
||||
|
||||
Dans notre exemple, nous utilisons `FROM`{.dockerfile} qui indique une image de
|
||||
départ à utiliser ; `RUN`{.dockerfile} est une commande qui sera exécutée dans
|
||||
départ à utiliser ; `RUN`{.dockerfile} est une commande qui sera exécutée dans
|
||||
le conteneur, dans le but de le construire.
|
||||
|
||||
Pour lancer la construction de la nouvelle image, créons un nouveau dossier ne
|
||||
|
@ -136,9 +136,9 @@ Rendez-vous ensuite dans votre navigateur sur <http://localhost:49153/>.
|
|||
#### À vous de jouer {-}
|
||||
|
||||
Utilisez l'instruction `COPY`{.dockerfile} pour afficher votre propre
|
||||
`index.html` remplaçant celui installé de base par `nginx`. Si vous manquez
|
||||
`index.html` remplaçant celui installé de base par `nginx`. <!--Si vous manquez
|
||||
d'inspiration, utilisez [cette page de compte à
|
||||
rebours](https://virli.nemunai.re/countdown.html).
|
||||
rebours](https://virli.nemunai.re/countdown.html).-->
|
||||
|
||||
|
||||
### Les caches
|
||||
|
@ -177,9 +177,10 @@ images), en haut du `Dockerfile`.
|
|||
L'instruction `LABEL`{.dockerfile} permet d'ajouter une métadonnée à une image,
|
||||
sous forme de clef/valeur.
|
||||
|
||||
Une métadonnée
|
||||
[courante](https://github.com/nginxinc/docker-nginx/blob/master/stable/debian/Dockerfile#L8)
|
||||
est d'indiquer le nom du mainteneur de l'image :
|
||||
Une métadonnée courante[^MAINTAINER] est d'indiquer le nom du
|
||||
mainteneur de l'image :
|
||||
|
||||
[^MAINTAINER]: Voir par exemple : <https://github.com/nginxinc/docker-nginx/blob/master/stable/debian/Dockerfile#L8>
|
||||
|
||||
<div lang="en-US">
|
||||
```dockerfile
|
||||
|
@ -221,15 +222,15 @@ retirez cette option pour voir ce qui ne va pas, ou utilisez la commande
|
|||
`docker container logs`.
|
||||
|
||||
|
||||
### Construire son application au moment de la construction du conteneur ?
|
||||
### Construire son application au moment de la construction du conteneur ?
|
||||
|
||||
Comment faire lorsque l'on a besoin de compiler une application avant de
|
||||
l'intégrer dans le conteneur ?
|
||||
l'intégrer dans le conteneur ?
|
||||
|
||||
On peut vouloir lancer la compilation sur notre machine, mais cela ne sera pas
|
||||
très reproductible et cela aura nécessité d'installer le compilateur et les
|
||||
outils liés au langage que l'on souhaite compiler. Peut-être que plusieurs
|
||||
versions de ces outils existent, laquelle choisir ? ... Ok c'est trop
|
||||
versions de ces outils existent, laquelle choisir ? ... Ok c'est trop
|
||||
compliqué.
|
||||
|
||||
D'un autre côté, si l'on fait cela dans un conteneur, celui-ci contiendra dans
|
||||
|
@ -300,7 +301,7 @@ sélectionnera ainsi avec l'option `--target` l'un ou l'autre en fonction de
|
|||
l'environnement dans lequel on souhaite se déployer.
|
||||
|
||||
|
||||
### D'autres instructions ?
|
||||
### D'autres instructions ?
|
||||
|
||||
Consultez <https://docs.docker.com/engine/reference/builder/> pour la liste
|
||||
complète des instructions reconnues.
|
||||
|
@ -310,12 +311,12 @@ complète des instructions reconnues.
|
|||
|
||||
Pour mettre en application tout ce que nous venons de voir, réalisons le
|
||||
`Dockerfile` du service web [`youp0m`](https://you.p0m.fr/) que nous avons
|
||||
utilisé la semaine dernière.
|
||||
déjà utilisé précédemment.
|
||||
|
||||
Pour réaliser ce genre de contribution, on ajoute généralement un `Dockerfile`
|
||||
à la racine du dépôt.
|
||||
|
||||
Vous pouvez cloner le dépôt de sources de `youp0m` à :
|
||||
Vous pouvez cloner le dépôt de sources de `youp0m` à :\
|
||||
<https://git.nemunai.re/nemunaire/youp0m.git>
|
||||
|
||||
Pour compiler le projet, vous pouvez utiliser dans votre `Dockerfile`
|
||||
|
|
|
@ -37,7 +37,7 @@ Hello world
|
|||
</div>
|
||||
|
||||
Dans ce premier cas, il n'y a pas d'argument après le nom de l'image, c'est
|
||||
donc le contenu de `CMD`{.dockerfile} qui est utilisé ; il est donc passé en
|
||||
donc le contenu de `CMD`{.dockerfile} qui est utilisé ; il est donc passé en
|
||||
argument à l'`ENTRYPOINT`{.dockerfile}. Concrètement, la première ligne de
|
||||
commande exécutée est :
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ dépendances ont bien été enregistrée.
|
|||
Ce fichier fonctionne de la même manière que le `.gitignore` : vous pouvez
|
||||
utiliser du globing.
|
||||
|
||||
Pour plus d'informations, vous pouvez consulter la documentation accessible à
|
||||
<https://docs.docker.com/engine/reference/builder/#dockerignore-file>.
|
||||
Pour plus d'informations, vous pouvez consulter la documentation accessible à\
|
||||
<https://docs.docker.com/engine/reference/builder/#dockerignore-file>
|
||||
|
||||
|
||||
### N'installez rien de superflu
|
||||
|
@ -40,7 +40,7 @@ comme serveur web. Un autre conteneur pourra contenir cet éditeur de texte dans
|
|||
les cas où vous avez besoin de modifier des données.
|
||||
|
||||
En plus, cela réduira le temps de construction et la taille des images
|
||||
produites !
|
||||
produites !
|
||||
|
||||
Avec `apt` par exemple, vous pouvez ajouter l'option `--no-install-recommends`
|
||||
lors vous installer un paquet qui vient avec de nombreuses recommandations
|
||||
|
@ -64,7 +64,7 @@ place.
|
|||
|
||||
#### Allez à la ligne pour séparer les longues lignes de commandes complexes\
|
||||
|
||||
Aérez vos `Dockerfile` !
|
||||
Aérez vos `Dockerfile` !
|
||||
|
||||
N'hésitez pas à commenter et séparer les blocs logiques ensemble, comme lorsque
|
||||
vous codez.
|
||||
|
@ -176,7 +176,7 @@ CMD ["-g", "daemon", "off;"]
|
|||
|
||||
- Vous pouvez aussi utiliser un script qui servira à faire les initialisations
|
||||
ou les configurations nécessaire au bon fonctionnement du conteneur
|
||||
(rappelez-vous, il doit être éphémère !). Par exemple, le `Dockerfile` pour
|
||||
(rappelez-vous, il doit être éphémère !). Par exemple, le `Dockerfile` pour
|
||||
l'image de PostgreSQL possède cet entrypoint :
|
||||
|
||||
<div lang="en-US">
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue