```bash
-V=1.19.2
+V=1.23.4
P=telegraf-${V}_linux_$(uname -m)
curl https://dl.influxdata.com/telegraf/releases/${P}.tar.gz | \
tar xzv -C /tmp
@@ -163,7 +171,7 @@ Et observons ensuite :
```bash
42sh$ docker container run --rm -it --link mytsdb:zelda influxdb:1.8 \
influx -host zelda
-InfluxDB shell version: 1.8.9
+InfluxDB shell version: 1.8.10
> show databases
name: databases
name
@@ -199,6 +207,16 @@ lancé, celui-ci va régulièrement envoyer des métriques de cette machine.
À vous de jouer pour lancer le conteneur
[*Chronograf*](https://store.docker.com/images/chronograf).
+::::: {.question}
+
+#### InfluxDB v2 {-}
+
+Chronograf n'existe plus en tant que projet indépendant dans la version 2, si
+vous êtes parti sur cette version, vous retrouverez les tableaux de bord
+directement dans l'interface d'InfluxDB, sur le port 8086.
+
+:::::
+
L'interface de *Chronograf* est disponible sur le port 8888.
Consultez la [documentation du conteneur](https://hub.docker.com/_/chronograf)
diff --git a/tutorial/docker-advanced/setup.md b/tutorial/docker-advanced/setup.md
index b70aa5a..f522390 100644
--- a/tutorial/docker-advanced/setup.md
+++ b/tutorial/docker-advanced/setup.md
@@ -1,5 +1,3 @@
-\newpage
-
Mise en place
-------------
@@ -11,19 +9,7 @@ communauté, et parfois même appropriées par Docker.
### `docker-compose`
-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 (et en Python). Il constitue aujourd'hui une brique de
-l'écosystème Docker, presque indispensable !
-
-#### Par le gestionnaire de paquets
-
-Les distributions à jour vous proposeront un paquet `docker-compose` qui
-fonctionnera avec la version de Docker qu'ils fournissent.
-
-#### Par la distribution binaire
+Dans cette partie, nous allons avoir besoin du plugin `docker-compose`.
L'équipe en charge du projet met à disposition un exécutable que nous pouvons
téléchargeant depuis
.
@@ -31,6 +17,21 @@ téléchargeant depuis .
Ajoutez l'exécutable dans le dossier des plugins : `$HOME/.docker/cli-plugins`
(sans oublier de `chmod +x` !).
+::::: {.more}
+
+Autrefois, `docker-compose` était un script tiers que l'on utilisait
+indépendamment de Docker. Le projet, historiquement écrit en Python, a été
+entièrement réécrit récemment afin qu'il s'intégre mieux dans l'écosystème.
+
+Vous trouverez encore de nombreux articles vous incitant à utiliser
+`docker-compose`. Dans la plupart des cas, vous pouvez simplement remplacer par
+des appels à `docker compose`.
+
+Il y a même un outil qui a spécialement été conçu pour migrer les lignes de
+commandes :\
+
+
+:::::
#### Vérification du fonctionnement
@@ -39,8 +40,8 @@ Comme avec Docker, nous pouvons vérifier le bon fonctionnement de
```
-42sh$ docker-compose --version
-docker-compose version: 1.29.2
+42sh$ docker compose version
+Docker Compose version v2.10.2
```
diff --git a/tutorial/docker-basis/discover.md b/tutorial/docker-basis/discover.md
index 69494bd..1afcef6 100644
--- a/tutorial/docker-basis/discover.md
+++ b/tutorial/docker-basis/discover.md
@@ -3,12 +3,17 @@
Découvrons Docker
=================
-Entrons sans plus attendre dans le vif du sujet : Docker.
+Tous les programmes d'exécution de conteneurs (*container runtimes*) ne
+fonctionnent pas de la même manière et n'apportent pas les mêmes
+fonctionnalités. Dans leurs couches les plus basses, chacun de ces programmes
+va certes utiliser les mêmes fonctionnalités du système d'exploitation afin de
+créer les couches d'isolation, mais chacun apporte un enrobage et une manière
+d'utiliser les conteneurs différents.
-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.
+Nous allons commencer sans plus attendre par découvrir 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é.
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
diff --git a/tutorial/docker-basis/ex-flask-s3.md b/tutorial/docker-basis/ex-flask-s3.md
new file mode 100644
index 0000000..a4fadd1
--- /dev/null
+++ b/tutorial/docker-basis/ex-flask-s3.md
@@ -0,0 +1,91 @@
+::::: {.exercice}
+
+Faire persister les données à l'heure du cloud
+----------------------------------------------
+
+Aïe, c'est un sujet épineux... On peut entendre ici et là que les conteneurs
+permettent de monter en puissance facilement, mais lorsque l'on est lié à un
+espace de stockage classique, on se heurte bien vite à des réalités physiques.
+
+Même si l'on utilise un système de fichiers partagé pour stocker nos images et
+ainsi répartir la puissance de calcul entre plusieurs machines, il va vite
+arriver un moment où la bande passante du disque réseau ne suivra plus. Il faut
+donc passer sur une classe de stockage d'un autre type : l'Object Storage.
+
+L'Object Storage est une méthode de stockage des objets adaptée au monde du
+Cloud Computing. Il s'agit d'une API HTTP avec laquelle on peut interagir pour
+accéder, ajouter, partager ou gérer un flot d'octets, que l'on nomme *objet* dans
+le jargon, mais il s'agit ni plus ni moins que d'un fichier.
+
+Il est de la responsabilité de l'administrateur du service (Amazon, Microsoft,
+Google ...) de faire en sorte que les données soient suffisamment réparties
+pour éviter les goulots d'étranglement et les SPOF. Ce n'est plus notre
+problème de gérer la distribution de la bande passante, ni l'usure des disques,
+ni même la capacité de notre espace de stockage.
+
+Toutes les applications ne sont malheureusement pas nativement compatibles avec
+ce système de stockage. Mais il se trouve que youp0m le supporte !
+
+Nous allons déployer le service `minio`, qui est une implémentation libre de
+l'API d'Amazon S3. `minio` dispose d'une interface graphique pour gérer nos
+*buckets*, c'est un volume auquel on attribue des droits particuliers,
+notamment quel utilisateur y a accès. C'est au sein d'un *bucket* que l'on va
+pouvoir envoyer nos fichiers. Ceux-ci seront référencés avec une *clef*
+(l'équivalent du chemin) : il n'y a pas de notion d'arborescence ou de dossier,
+mais par convention, lorsque l'on place un `/` dans le nom de la clef, on
+considère qu'il s'agit d'un séparateur de dossier.
+
+::::: {.question}
+
+Comme il n'y a pas de notion de dossier, il n'y a pas besoin de créer
+l'arborescence avant d'écrire un objet. Chaque objet est référencé par sa clef,
+sans qu'il ne soit question d'arborescence ou de dossier.
+
+À partir d'un *bucket* vide, vous pouvez donc directement ajouter le fichier :
+`images/next/racoon.jpg`, sans vous préoccuper de l'existence ou non des
+dossiers `images` et `next`, la séparation n'est qu'une convention, l'objet
+n'est pas enregistré comme étant le fichier `racoon.jpg` du dossier `next`,
+mais bien comme `images/next/racoon.jpg`.
+
+:::::
+
+Au sein de l'interface minio, vous devrez donc créer un bucket (par exemple
+`youp0m` puisque ce sera un *bucket* dédié à cette application). Ainsi qu'un
+compte de service (sous *Identity* > *Service Accounts*). Cela vous permettra
+de récupérer une *Access Key* ainsi que sa *Secret Key* associée. Ce sont des
+informations qui permettront au conteneur `youp0m` de s'identifier auprès de
+l'API.
+
+
+Il faudra ensuite lancer un conteneur youp0m avec les
+options suivantes :
+
+
+```
+S3_ENDPOINT=http://NOM_DU_CONTENEUR_MINIO:9000
+S3_BUCKET=NOM_DU_BUCKET
+S3_ACCESS_KEY=ACCESS_KEY_GENEREE
+S3_SECRET_KEY=SECRET_KEY_CORRESPONDANTE
+S3_PATH_STYLE=true
+```
+
+
+::::: {.more}
+
+La dernière option `S3_PATH_STYLE` est importante lorsque l'on utilise minio,
+car il y a une subtile différence entre l'API d'Amazon et celle de minio
+lorsque l'on ne le configure pas davantage.
+
+Un *bucket* pour Amazon S3 correspond à un sous-domaine (par exemple
+`youp0m.nemunai.re.s3.amazonaws.com.` pour le bucket
+`youp0m.nemunai.re`). Cependant, dans notre installation de minio, nous n'avons
+pas de nom de domaine à proprement parler. L'option est donc là pour indiquer
+que le nom du *bucket* est attendu comme premier paramètre de l'URL et non pas
+comme sous-domaine.
+
+:::::
+
+Votre instance de `youp0m` est désormais réellement prête pour passer en
+production. Bravo !
+
+:::::
diff --git a/tutorial/docker-basis/ex-flask-volume.md b/tutorial/docker-basis/ex-flask-volume.md
new file mode 100644
index 0000000..a64d22a
--- /dev/null
+++ b/tutorial/docker-basis/ex-flask-volume.md
@@ -0,0 +1,47 @@
+::::: {.exercice}
+
+Faire persister les données : niveau 1
+--------------------------------------
+
+Le service `youp0m` que nous avons déployé fonctionne comme on pourrait s'y
+attendre, mais vous imaginez bien que ce n'est pas très pratique de devoir
+réimporter les données à chaque fois que l'on met à jour le conteneur ou sa
+configuration.
+
+Maintenant que nous savons utiliser les volumes nous allons les utiliser pour
+rendre notre service plus pérenne.
+
+Le service stocke par défaut les images dans le dossier `/images` du
+conteneur. Pour les sauvegarder hors du conteneur, nous devons donc créer un
+volume vers ce dossier :
+
+
+```
+42sh$ docker volume create youp0m_images
+42sh$ docker run -v youp0m-image:/images -p 8080:8080 registry.nemunai.re/youp0m
+```
+
+
+Ajoutons quelques images puis arrêtons et supprimons le conteneur. Relançons
+ensuite un nouveau conteneur avec les mêmes options :
+
+
+```
+42sh$ docker run -v youp0m-image:/images -p 8080:8080 registry.nemunai.re/youp0m
+```
+
+
+::::: {.question}
+
+Nous ne recréons pas le volume, il est important de ne pas l'avoir supprimé
+ici, puisque c'est ce volume qui assure la persistance des images.
+
+:::::
+
+Nos images sont bien persistantes d'une instance à l'autre de notre contenu.
+
+Nous voici prêt à déployer en production notre service, sans crainte de perdre
+les jolies contributions. Mais... est-ce que ce sera suffisant pour répondre aux
+milliers de visiteurs attendus ?
+
+:::::
diff --git a/tutorial/docker-basis/ex-flask.md b/tutorial/docker-basis/ex-flask.md
index a38210f..1ad9b13 100644
--- a/tutorial/docker-basis/ex-flask.md
+++ b/tutorial/docker-basis/ex-flask.md
@@ -1,5 +1,3 @@
-\newpage
-
Mon premier webservice
----------------------
@@ -14,7 +12,7 @@ Nous pouvons télécharger et lancer le service grâce à :
```bash
-docker container run -i nemunaire/youp0m
+docker container run -i registry.nemunai.re/youp0m
```
@@ -37,7 +35,7 @@ Nous pouvons rediriger le port avec l'argument `-p dst_host:s
```bash
-docker container run -i -p 8080:8080 nemunaire/youp0m
+docker container run -i -p 8080:8080 registry.nemunai.re/youp0m
```
@@ -75,7 +73,7 @@ On utilise l'option `-d` pour lancer le conteneur en tâche de fond :
```bash
-docker container run -d -p 8080:8080 nemunaire/youp0m
+docker container run -d -p 8080:8080 registry.nemunai.re/youp0m
```
@@ -98,11 +96,11 @@ absolument un clone de !
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 :
```bash
-docker container run -d -p 8081:8080 nemunaire/youp0m
+docker container run -d -p 8081:8080 registry.nemunai.re/youp0m
```
@@ -141,7 +139,7 @@ Pour ajouter une variable d'environnement, cela se passe dans la commande
```bash
-docker container run -e YOUP0M_PASSWORD=foobar -p 8080:8080 nemunaire/youp0m
+docker container run -e YOUP0M_PASSWORD=foobar -p 8080:8080 registry.nemunai.re/youp0m
```
diff --git a/tutorial/docker-basis/ex-owncloud.md b/tutorial/docker-basis/ex-owncloud.md
index 1550898..3c9bdb6 100644
--- a/tutorial/docker-basis/ex-owncloud.md
+++ b/tutorial/docker-basis/ex-owncloud.md
@@ -16,11 +16,11 @@ 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
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 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.
+Votre script devra se limiter aux notions vues durant cette partie (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 votre
script dans un autre conteneur) et contenir ses données dans un ou plusieurs
@@ -46,3 +46,14 @@ http://localhost:12345/
:::::
+
+### 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'initialiser le volume attaché à `/var/lib/mysql`. Les
+démarrages 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é.
+
+Si vous rencontrez des difficultés pour connecter votre conteneur à
+`my-db`, prenez le temps de recréer un volume.
diff --git a/tutorial/docker-basis/first.md b/tutorial/docker-basis/first.md
index 3a9fd02..320620d 100644
--- a/tutorial/docker-basis/first.md
+++ b/tutorial/docker-basis/first.md
@@ -1,5 +1,3 @@
-\newpage
-
Mon premier conteneur
---------------------
diff --git a/tutorial/docker-basis/installation.md b/tutorial/docker-basis/installation.md
index c30b2e0..96264d3 100644
--- a/tutorial/docker-basis/installation.md
+++ b/tutorial/docker-basis/installation.md
@@ -52,13 +52,6 @@ distribution :
```bash
diff --git a/tutorial/docker-basis/linking-ex-help.md b/tutorial/docker-basis/linking-ex-help.md
index 3f8fe1c..4bd9821 100644
--- a/tutorial/docker-basis/linking-ex-help.md
+++ b/tutorial/docker-basis/linking-ex-help.md
@@ -1,15 +1,3 @@
-### 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'initialiser le volume attaché à `/var/lib/mysql`. Les
-démarrages 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é.
-
-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
diff --git a/tutorial/docker-basis/volumes.md b/tutorial/docker-basis/volumes.md
index d91d1bc..9e09ca5 100644
--- a/tutorial/docker-basis/volumes.md
+++ b/tutorial/docker-basis/volumes.md
@@ -73,8 +73,7 @@ On pourra également faire de même avec un conteneur MySQL :
```bash
docker container run --name mydb -e MYSQL_ROOT_PASSWORD=my-secret-pw \
- --mount source=prod_db,target=/var/lib/mysql\
- mysql
+ --mount source=prod_db,target=/var/lib/mysql mysql
```
@@ -88,7 +87,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 :
```bash
diff --git a/tutorial/docker-basis/what.md b/tutorial/docker-basis/what.md
index 41df769..1c16055 100644
--- a/tutorial/docker-basis/what.md
+++ b/tutorial/docker-basis/what.md
@@ -1,40 +1,56 @@
-\newpage
-
Composition de Docker
---------------------
-Docker est un écosystème d'outils de haut niveau, permettant d'utiliser des
-*conteneurs*.
+Docker est une suite d'outils de haut niveau, permettant d'utiliser des
+*conteneurs*. Le projet en lui-même utilise de nombreuses dépendances,
+originellement développées par l'entreprise Docker Inc., puis laissé dans le
+domaine public lors des efforts de standardisation en 2015.
-Docker est composé d'un daemon lancé au démarrage de votre machine, avec lequel
-vous interagissez via un client (le programme `docker`). La communication entre
-le daemon et le client s'effectuant sur une API REST généralement au travers
-d'une socket.
+Commençons par planter le décor, en détaillant les principes de base de Docker.
-Le client peut d'ailleurs ne pas être sur la même machine qui exécutera
+### Séparation des compétences
+
+Le projet s'article autour d'un daemon lancé au démarrage de la machine, avec
+lequel on interagit via un client (le programme `docker`). La communication
+entre le daemon et le client s'effectuant sur une API REST généralement au
+travers d'une socket.
+
+::::: {.more}
+
+Tous les programmes d'exécution de conteneurs n'utilisent pas une architecture
+avec un daemon et un client. `podman` que l'on peut généralement substituer à
+Docker n'emploie pas de daemon. Chaque utilisateur de la machine peut donc
+disposer de ses propres conteneurs, sans interférer avec ceux de ses voisins.
+
+D'un point de vue de la sécurité, le daemon Docker est exécuté en tant que
+super-utilisateur. C'est sur ce daemon que repose la sécurité de la machine, ce
+qui peut être beaucoup de responsabilité. Gardez en tête que le modèle
+d'exécution de Docker n'est pas unique. Nous avons le choix.
+
+:::::
+
+Le processus client peut d'ailleurs ne pas être sur la même machine qui exécute
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 Docker sur Windows ou macOS :
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.
+chaque commande `docker` tapée est passée au daemon 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 :
-Commençons par planter le décor, en détaillant les principaux mécanismes de
-Docker.
-
### Les images 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.
+Comme nous l'avons vu en introduction, les images sont un moyen de récupérer
+facilement un environnement d'exécution complet, prêt à l'emploi. Une image
+Docker donc est un système de fichiers en lecture seule.
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,
+* votre site web personnel, prêt à l'emploi,
* ...
Les images sont utilisées comme **modèle** qui sera ensuite dupliqué à chaque
@@ -43,36 +59,34 @@ fois que l'on démarrera un nouveau conteneur.
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.
-
-### Les registres Docker (*Docker registries*)
-
-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
-images créées par des utilisateurs, mais aussi des images de grands éditeurs,
-payantes, à destination des entreprises.
-
-Des registres alternatifs existent comme celui de [quay.io](https://quay.io/search),
-et les dépôts de sources tels que
-[GitHub](https://github.blog/2020-09-01-introducing-github-container-registry/)
-et [GitLab](https://docs.gitlab.com/ee/user/packages/container_registry/) le
-proposent également.
+Lorsque vous ne précisez pas l'adresse d'un registre, Docker va aller chercher
+sur le [Docker Hub](https://hub.docker.com/). C'est son registre par défaut, chaque
-### Les conteneurs Docker
+### Les plugins 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 : à
-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.
+L'architecture de Docker est devenue très modulable. Le projet est parti dans
+de nombreuses directions, chacun voulant tirer la couverture vers soit, et
+l'équipe maintenant le projet a parfois eu du mal à arbitrer les bonnes choses
+à ajouter ou non au projet.
-![Couches d'un conteneur](layers-multi-container.png "Couches d'un conteneur"){ width=70% }
+Afin de palier aux besoins complémentaires, parfois accessoires, parfois
+salvateurs, un système de plugins a été intégré. Il permet d'appeler d'autres
+programmes comme s'il s'agissait de composant de Docker.
-Chaque conteneur s'exécute dans un environnement restreint et distinct de
-l'environnement principal (où vous avez votre bureau). Par exemple, dans cet
-environnement, vous ne pouvez pas voir les processus qui sont situés en dehors,
-ni accéder aux fichiers extérieurs.
+Certains plugins ajoutent des options à la ligne de commande (`docker-compose`,
+`docker-scan`, `docker-buildx` ...). D'autres ajoutent des typologies de
+réseaux, de gestion du stockage ou ajoutent de l'authentification.
+
+Pour ajouter un plugin à Docker, il suffit de l'ajouter dans un sous-dossier de
+`/usr/lib/docker/cli-plugins` pour qu'il soit accessible à tous les
+utilisateurs de notre machine ou dans `$HOME/.docker/` si l'on veut l'installer
+seulement pour nous.
+
+Par exemple, les plugins ajoutant des commandes iront dans
+`$HOME/.docker/cli-plugins`. Par exemple, si l'on souhaite pouvoir disposer de
+la commande `docker compose`, on téléchargera le plugin vers l'emplacement :
+`$HOME/.docker/cli-plugins/docker-compose`.
+
+Plus récemment, de nouveaux plugins ont vu le jour et se basent directement sur
+des conteneurs que l'on peut télécharger depuis un registre d'images.
diff --git a/tutorial/docker-orchestration/machine.md b/tutorial/docker-orchestration/machine.md
index 85bc6d6..1fc4b1a 100644
--- a/tutorial/docker-orchestration/machine.md
+++ b/tutorial/docker-orchestration/machine.md
@@ -71,7 +71,7 @@ fichiers.
##### Utilisation avec Docker {-}
-Nous avons déjà évoqué le fait que le deamon pouvait ne pas se trouver sur la
+Nous avons déjà évoqué le fait que le daemon 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 :
diff --git a/tutorial/header-tp-fun.md b/tutorial/header-tp-fun.md
new file mode 100644
index 0000000..8e3f700
--- /dev/null
+++ b/tutorial/header-tp-fun.md
@@ -0,0 +1,2 @@
+Exercices et travaux pratiques (version fun !)
+==============================
diff --git a/tutorial/header-tp.md b/tutorial/header-tp.md
new file mode 100644
index 0000000..e910ecb
--- /dev/null
+++ b/tutorial/header-tp.md
@@ -0,0 +1,2 @@
+Exercices et travaux pratiques
+==============================
diff --git a/tutorial/new-page.md b/tutorial/new-page.md
new file mode 100644
index 0000000..16dd787
--- /dev/null
+++ b/tutorial/new-page.md
@@ -0,0 +1 @@
+\newpage