diff --git a/tutorial/2/Makefile b/tutorial/2/Makefile
index 9097b04..712ba6e 100644
--- a/tutorial/2/Makefile
+++ b/tutorial/2/Makefile
@@ -1,4 +1,4 @@
-SOURCES = tutorial.md installation.md docker.md
+SOURCES = tutorial.md installation.md what.md first.md dockerfile.md volumes.md linking.md
TEMPLATE = ../../template.tex
PANDOCOPTS = --latex-engine=xelatex \
--standalone \
diff --git a/tutorial/2/docker.md b/tutorial/2/docker.md
deleted file mode 100644
index f6f630d..0000000
--- a/tutorial/2/docker.md
+++ /dev/null
@@ -1,384 +0,0 @@
-\newpage
-
-# Docker
-
-Docker est un outil haut niveau permettant de faire fonctionner facilement les
-conteneurs.
-
-## Composition de Docker
-
-Docker est un daemon lancé au démarrage de votre machine, avec lequel vous
-interagissez via un client qui se connecte au daemon au moyen d'une socket (le
-client peut donc être sur une machine distincte du daemon où sont exécutés les
-conteneurs).
-
-
-## Mon premier conteneur
-
-Afin de tester la bonne marche de votre installation, exécutez la commande :
-
-```
-docker run hello-world
-```
-
-Cette commande va automatiquement exécuter une série de commandes pour vous,
-comme indiqué dans le message affiché en retour :
-
-D'abord, le démon va rechercher s'il possède localement l'image
-*hello-world*. Si ce n'est pas le cas, il va aller la récupérer sur
-hub.docker.com. Ce site met à votre disposition un grand nombre d'images : des
-systèmes de base comme Ubuntu, Debian, Centos, etc. jusqu'à des conteneurs
-prêts à l'emploi : le serveur web nginx, la base de données MySQL, un serveur
-node.js, etc.
-
-Vous pouvez directement utiliser le client pour rechercher une image sur le
-hub, en utilisant la commande `search` :
-
-```
-docker search mariadb
-```
-
-Vous pouvez mettre à jour vos images locales ou simplement pré-télécharger des
-images depuis le hub en utilisant la commande `pull` :
-
-```
-docker pull ubuntu
-```
-
-Pour consulter la liste des images dont vous disposez localement (soit
-parce que vous les avez téléchargées, soit parce que vous les avez
-créées vous-même), utilisez la commande `images` :
-
-```
-docker images
-```
-
-Vous devez constater la présence de deux images « Ubuntu », ayant un *TAG*
-différent. Souvent, il existe plusieurs versions d'une même image. Pour Ubuntu
-par exemple, vous avez la possibilité de lancer la version `vivid`, `trusty` ou
-`precise`.
-
-Chaque image est identifiable par son *Image ID* unique, les noms d'images
-ainsi que leurs tags sont, comme les tags Git, une manière humainement plus
-simple de faire référence aux identifiants.
-
-Chaque nom d'image possède au moins un tag associé : *latest*, c'est le tag qui
-est automatiquement recherché lorsque vous ne le précisez pas en lançant
-l'image.
-
-
-## Exécuter un programme dans un conteneur
-
-Maintenant que nous avons à notre disposition l'image d'un conteneur Ubuntu,
-lançons-la !
-
-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 :
-
-```
-docker run ubuntu /bin/echo "Hello World"
-```
-
-Dans notre exemple, c'est bien le `/bin/echo` présent dans le conteneur qui est
-appelé (et non pas le programme `/bin/echo` de la machine hôte qui est
-transféré dans le conteneur).
-
-
-## Modifier un conteneur
-
-À chaque fois que vous lancez un `run`, un nouveau conteneur est créé à partir
-de l'image que vous précisez (via un mécanisme de Copy-On-Write, c'est donc
-très rapide et ne consomme pas beaucoup d'espace disque). Cela signifie que
-lorsque vous exécutez une commande modifiant le contenu d'un conteneur, cela ne
-modifie pas l'image de base, mais crée une nouvelle image. Que vous pouvez
-ensuite utiliser comme image de base.
-
-Commençons par entrer dans un nouveau conteneur pour modifier l'image :
-
-```
-docker run -it ubuntu /bin/bash
-```
-
-Vous voilà maintenant dans le conteneur ! Il est assez épuré, il n'y a rien de
-superflu : vous n'avez pas d'éditeur de texte : ni vim, ni emacs, même pas vi !
-
-La première chose à faire est de mettre à jour la liste des paquets :
-
-```
-apt-get update
-```
-
-Il peut arriver que des paquets présents dans l'image officielle ne soient pas
-à jour. Afin de garder un environnement cohérent, il est recommandé de ne pas
-utiliser le gestionnaire de paquets pour mettre à jour les paquets, mais plutôt
-de contacter le mainteneur de l'image pour qu'il la mette à jour.
-
-Installons maintenant un programme :
-
-```
-apt-get install nano
-```
-
-En attendant la fin de l'installation, jetez un œil à la commande dans un autre
-terminal :
-
-```
-docker ps
-```
-
-Cette commande liste les conteneurs actifs. Notez le *Container ID* ainsi que
-le *NAMES* du conteneur du conteneur actuellement en cours d'installation de
-nano.
-
-Lorsque l'installation de `nano` est terminée, quittez l'image en tapant
-`exit`.
-
-Sauvegardez votre image modifiée avec la commande `commit` pour pouvoir
-commencer directement de votre image avec `nano` :
-
-```
-docker commit CONTAINER my_nano
-```
-
-En remplaçant `CONTAINER` par le nom ou l'identifiant de votre
-container. `my_nano` est le nom que vous voudrez utiliser à la place
-d'`ubuntu` :
-
-```
-docker run -it my_nano /bin/bash
-```
-
-Vous constatez cette fois que vous pouvez lancer `nano`, alors que vous ne
-pouvez toujours pas le faire dans un conteneur issue d'une image `ubuntu` !
-
-
-## Dockerfile
-
-Pour construire une image, vous n'êtes pas obligé de passer par une série de
-commits. Docker dispose d'un mécanisme permettant d'automatiser la construction
-de nouvelles images. Vous pouvez arriver au même résultat que ce que l'on a
-réussi à faire précédemment en utilisant le Docker file suivant :
-
-```
-FROM ubuntu:latest
-
-RUN apt-get update
-RUN apt-get install -y nano
-```
-
-La syntaxe d'un `Dockerfile` est simple, le premier mot de chaque ligne est
-l'intitulé d'une instruction (que l'on écrit généralement en majuscule), elle
-est suivie de ses arguments.
-
-Dans notre exemple, nous utilisons `FROM` qui indique une image de départ à
-utiliser ; `RUN` est une commande qui sera exécutée dans le conteneur, dans le
-but de le construire. Chaque ligne est exécutée indépendamment des autres ;
-cela signifie que l'exemple suivant ne fonctionne pas :
-
-```
-COPY db.sql /db.sql
-RUN service mysqld start
-RUN mysql -u root -p toor virli < /db.sql
-```
-
-Cet exemple ne fonctionne pas car le serveur MySQL est lancé dans le premier
-RUN, n'est plus lancé au moment du deuxième RUN. Pour avoir le résultat
-escompté, il faut exécuter les commandes ensemble :
-
-```
-COPY db.sql /db.sql
-RUN service mysqld start && mysql -u root -p toor virli < /db.sql
-```
-
-Après le `RUN`, MySQL sera de nouveau arrêté, si on veut l'utiliser dans le
-conteneur, il ne faudra pas oublier lancer le processus.
-
-Pour lancer la construction de la nouvelle image, créer un nouveau dossier ne
-contenant que votre fichier `Dockerfile`, placez-vous dedans, puis utilisez la
-commande `build` :
-
-```
-docker build --tag=my_editor .
-```
-
-Une fois la construction de l'image terminée, vous pouvez la lancer et
-constater l'existence de notre éditeur favori :
-
-```
-docker run -it my_editor /bin/bash
-```
-
-Consultez pour la liste complète
-des instructions reconnues.
-
-
-## Exposer des ports
-
-Construisons maintenant un conteneur avec un serveur web :
-
-```
-FROM my_editor
-
-RUN apt-get update
-RUN apt-get install -y nginx
-
-EXPOSE 80
-```
-
-L'instruction `EXPOSE` sera traité plus tard par le client Docker
-(équivalent à l'argument `--expose`). Il s'agit de préciser les ports
-sur lesquels votre image écoute.
-
-En utilisant l'option `-P` du `run`, vous allez pouvoir assigner une
-redirection de port aléatoire sur la machine hôte vers votre
-conteneur :
-
-```
-docker build --tag=my_webserver .
-docker run -it -P my_webserver /bin/bash
-service nginx start
-```
-
-Dans un autre terminal, lancer un `docker ps` et consulter la colonne
-*PORTS* pour connaître le port choisit par Docker pour effectuer la
-redirection.
-
-Rendez-vous ensuite dans votre navigateur sur .
-
-À vous de jouer : utilisez l'instruction `COPY` pour afficher votre
-propre `index.html` remplaçant celui installé de base par nginx.
-
-
-## Lancement de commande automatique
-
-Vous pouvez placer dans un `Dockerfile` une instruction `CMD` qui sera
-exécutée si aucune commande n'est passée lors du `run`, par exemple :
-
-```
-CMD nginx -g "daemon off;"
-```
-
-```
-docker build --tag=my_nginx .
-docker run -d -P my_nginx
-```
-
-L'option `-d` passée au `run` lance le conteneur en tâche de
-fond. Si vous constatez via un `docker ps` que le conteneur s'arrête
-directement, retirer cette option pour voir ce qui ne va pas, ou
-utilisez la commande `docker logs`.
-
-
-## Volumes
-
-Il est possible de partager des répertoires entre plusieurs
-conteneurs. Pour ce faire, il faut déclarer dans le `Dockerfile` une
-ou plusieurs instructions `VOLUME` avec le chemin du répertoire à
-considérer comme volume (il est également possible de le faire via
-l'option `--volume` du client). Ces deux lignes sont équivalentes :
-
-```
-VOLUME /var/log/nginx
-```
-
-```
-docker run -v /var/log/nginx my_nginx
-```
-
-Pour monter les volumes dans un autre conteneur, on utilise l'argument
-`--volume-from` du client, en indiquant le nom du conteneur avec
-lequel on souhaite partager les volumes :
-
-```
-docker run -it --volume-from romantic_archimedes ubuntu /bin/bash
-```
-
-Vous constaterez que le répertoire `/var/log/nginx` est partagé entre
-`romantic_archimedes` et le dernier conteneur lancé.
-\newline
-
-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éralement on ne va
-lancer qu'une seule application par conteneur) et concevoir un service complet
-en créant un groupe de conteneur, partageant des données entre-eux par des
-volumes.
-
-Une lecture intéressante sur ce sujet est sans doute [cet article de Michael
-Crosby](http://crosbymichael.com/advanced-docker-volumes.html).
-
-### Data Volume Container
-
-Dans de nombreuses situation, il est intéressant de séparer les données de
-l'application, et donc d'avoir un conteneur exécutant l'application et un
-second stockant les données.
-
-Cela est particulièrement utile dans le cas d'une base de données : on veut
-pouvoir mettre à jour le conteneur exécutant le serveur, sans pour autant
-perdre les données.
-
-L'idée derrière le concept de `Data Volume Container` est de partager un volume
-avec un conteneur dont le seul rôle est de stocker les données.
-
-Il est parfaitement possible de partager un volume avec un conteneur qui n'est
-plus lancé. En effet, tant que vous n'avez pas demandé explicitement à un
-conteneur d'être supprimé, il est préservé dans un coin en attendant des jours
-meilleurs.
-
-Voici comment on pourrait lancer un conteneur exécutant une base de données :
-
-```
-docker run -v /var/lib/mysql --name dbdata busybox
-docker run --volume-from dbdata -e MYSQL_ROOT_PASSWORD=mysecretpassword -d mysql
-```
-
-Le premier conteneur, sans commande passée, va s'arrêter dès son
-lancement. Busybox est l'une des plus petites images possédant tous les outils
-de base (il est possible d'obtenir un shell en cas de besoin). Il expose un
-volume qui sera utiliser comme stockage persistant.
-
-Le second conteneur va lancer le serveur MySQL et utiliser le répertoire
-partagé pour stocker les données.
-
-Lorsqu'il y aura besoin de mettre à jour le conteneur MySQL, les données ne
-seront pas perdues (et s'il y avait besoin de migrer les données entre les deux
-versions des conteneurs, un conteneur intermédiaire pourrait parfaitement s'en
-charger).
-
-Cela facile également les sauvegardes, qui peuvent s'exécuter dans un conteneur
-distinct, dédié à la tâche de sauvegarde.
-
-
-## Lier les conteneurs
-
-En plus de vouloir partager des répertoires entre deux conteneurs, il est
-souvent nécessaire de partager des ports.
-
-Pour automatiser le partage d'informations sur les IP et ports exposés, la
-commande `run` possède l'option `--link` qui permet de définir dans les
-variables d'environnement du conteneur que l'on va lancer.
-
-Le détail des variables ajoutées dans cette situation est disponible à
-.
-
-On utiliser généralement cette liaison pour fournir au conteneur hébergeant un
-site web dynamique l'IP et le port où trouver la base de données :
-
-```
-docker run -e MYSQL_ROOT_PASSWORD=mysecretpassword -d --name db1 mysql
-docker run --link db1 my_nginx
-```
-
-### Ambasador
-
-Afin d'abstraire le plus possible l'infrastructure sous-jacente et d'autoriser
-les migrations de conteneurs, on utilise le modèle *ambassador*.
-
-On lancera systématiquement un conteneur entre deux conteneurs que l'on veut
-lier : l'ambassadeur. Celui-ci s'occupera de router correctement le trafic. En
-cas de changement de route (si l'un des conteneurs change de machine hôte par
-exemple), on a simplement à redémarrer l'ambassadeur plutôt que le conteneur
-principal.
-
-La documentation officielle pour ce modèle est disponible à
-.
diff --git a/tutorial/2/dockerfile.md b/tutorial/2/dockerfile.md
new file mode 100644
index 0000000..ff5367a
--- /dev/null
+++ b/tutorial/2/dockerfile.md
@@ -0,0 +1,167 @@
+\newpage
+
+# `Dockerfile`
+
+## Mon premier conteneur ... par `Dockerfile`
+
+Pour construire une image, vous n'êtes pas obligé de passer par une série de
+commits. Docker dispose d'un mécanisme permettant d'automatiser la construction
+de nouvelles images. Vous pouvez arriver au même résultat que ce que l'on a
+réussi à faire précédemment en utilisant le Docker file suivant :
+
+```
+FROM ubuntu:latest
+
+RUN apt-get update
+RUN apt-get install -y nano
+```
+
+La syntaxe d'un `Dockerfile` est simple, le premier mot de chaque ligne est
+l'intitulé d'une instruction (que l'on écrit généralement en majuscule), elle
+est suivie de ses arguments.
+
+Dans notre exemple, nous utilisons `FROM` qui indique une image de départ à
+utiliser ; `RUN` 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éer un nouveau dossier ne
+contenant que votre fichier `Dockerfile`, placez-vous dedans, puis utilisez la
+commande `build` :
+
+```
+docker build --tag=my_editor .
+```
+
+Une fois la construction de l'image terminée, vous pouvez la lancer et
+constater l'existence de notre éditeur favori :
+
+```
+docker run -it my_editor /bin/bash
+```
+
+
+## `RUN` dans le `Dockerfile`
+
+Chaque ligne est exécutée indépendamment des autres ;
+cela signifie que l'exemple suivant **ne fonctionne pas** :
+
+```
+COPY db.sql /db.sql
+RUN service mysqld start
+RUN mysql -u root -p toor virli < /db.sql
+```
+
+Cet exemple ne fonctionne pas car le serveur MySQL est lancé dans le premier
+RUN, n'est plus lancé au moment du deuxième RUN. En effet, chaque commande du
+`Dockerfile` a pour but de modifier le système de fichiers.
+
+Pour avoir le résultat escompté, il faut exécuter les commandes ensemble :
+
+```
+COPY db.sql /db.sql
+RUN service mysqld start && mysql -u root -p toor virli < /db.sql
+```
+
+Après le `RUN`, MySQL sera de nouveau arrêté, si on veut l'utiliser dans le
+conteneur, il ne faudra pas oublier de lancer le processus.
+
+
+## Exposer des ports
+
+Construisons maintenant un conteneur avec un serveur web :
+
+```
+FROM my_editor
+
+RUN apt-get update
+RUN apt-get install -y nginx
+
+EXPOSE 80
+```
+
+L'instruction `EXPOSE` sera traité plus tard par le client Docker
+(équivalent à l'argument `--expose`). Il s'agit de préciser les ports
+sur lesquels votre image écoute.
+
+En utilisant l'option `-P` du `run`, vous allez pouvoir assigner une
+redirection de port aléatoire sur la machine hôte vers votre
+conteneur :
+
+```
+docker build --tag=my_webserver .
+docker run -it -P my_webserver /bin/bash
+service nginx start
+```
+
+Dans un autre terminal, lancer un `docker ps` et consulter la colonne
+*PORTS* pour connaître le port choisit par Docker pour effectuer la
+redirection.
+
+Rendez-vous ensuite dans votre navigateur sur .
+
+À vous de jouer : utilisez l'instruction `COPY` pour afficher votre
+propre `index.html` remplaçant celui installé de base par nginx.
+
+
+## Lancement de commande automatique
+
+Vous pouvez placer dans un `Dockerfile` une instruction `CMD` qui sera
+exécutée si aucune commande n'est passée lors du `run`, par exemple :
+
+```
+CMD nginx -g "daemon off;"
+```
+
+```
+docker build --tag=my_nginx .
+docker run -d -P my_nginx
+```
+
+L'option `-d` passée au `run` lance le conteneur en tâche de
+fond. Si vous constatez via un `docker ps` que le conteneur s'arrête
+directement, retirer cette option pour voir ce qui ne va pas, ou
+utilisez la commande `docker logs`.
+
+
+## D'autres instructions ?
+
+Consultez pour la liste complète
+des instructions reconnues.
+
+
+## Rendu
+
+### Exercice
+
+Rendez le fichier `Dockerfile` et son contexte (`index.html`, fichiers de conf
+éventuels, ...) que vous avez utiliser pour réaliser votre image
+`my_webserver`.
+
+### Questions
+
+1. De combien de couches de systèmes de fichiers est composé votre image
+ `my_webserver` ? Comment pourriez-vous en avoir moins ?
+
+1. On a vu comment créer une nouvelle image à partir d'une image existante
+ (`FROM`). Mais comment sont créés les images de bases comme debian ou ubuntu
+ (quelle(s) commande(s) et quels type(s) de fichier(s)) ?
+
+1. Quels sont les avantages de ce `RUN` :
+
+```
+RUN apt-get update && \
+ apt-get install -y \
+ nginx \
+ php5-fpm \
+ php5-mysql \
+ php5-gd \
+ && apt-get clean && \
+ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+```
+
+par rapport aux précédents exemples :
+
+```
+RUN apt-get update
+RUN apt-get install -y nginx php5-fpm
+```
diff --git a/tutorial/2/first.md b/tutorial/2/first.md
new file mode 100644
index 0000000..138f7e2
--- /dev/null
+++ b/tutorial/2/first.md
@@ -0,0 +1,182 @@
+\newpage
+
+# Mon premier conteneur
+
+Afin de tester la bonne marche de votre installation, exécutons la commande :
+
+```
+docker run hello-world
+```
+
+Cette commande va automatiquement exécuter une série de commandes pour nous,
+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 la récupérer sur
+. Ce site met à disposition un grand nombre d'images : des
+systèmes de base comme Ubuntu, Debian, Centos, etc. jusqu'à des conteneurs
+prêts à l'emploi : le serveur web nginx, la base de données MySQL, un serveur
+node.js, etc.
+
+Nous pouvons directement utiliser le client pour rechercher une image sur le
+hub, en utilisant la commande `search` :
+
+```
+docker search mariadb
+```
+
+Il est possible de mettre à jour les images locales ou simplement
+pré-télécharger des images depuis le hub en utilisant la commande `pull` :
+
+```
+docker pull ubuntu
+```
+
+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 `images` :
+
+```
+docker images
+```
+
+Nous devrions constater la présence de deux images « Ubuntu », ayant un *TAG*
+différent. Souvent, il existe plusieurs versions d'une même image. Pour Ubuntu
+par exemple, nous avons la possibilité de lancer la version `vivid`, `trusty`
+ou `precise`.
+
+Chaque image est identifiable par son *Image ID* unique ; les noms d'images
+ainsi que leurs tags sont, comme les tags Git, une manière humainement plus
+simple de faire référence aux identifiants.
+
+Chaque nom d'image possède au moins un tag associé : *latest*. C'est le tag qui
+est automatiquement recherché lorsque l'on ne le précisez pas en lançant
+l'image.
+
+
+## Exécuter un programme dans un conteneur
+
+Maintenant que nous avons à notre disposition l'image d'un conteneur Ubuntu,
+lançons-la !
+
+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 :
+
+```
+docker run ubuntu /bin/echo "Hello World"
+```
+
+Dans notre exemple, c'est bien le `/bin/echo` présent dans le conteneur qui est
+appelé. Ce n'est pas le programme `/bin/echo` de la machine hôte qui a été
+transféré dans le conteneur.
+
+
+## Modifier un conteneur
+
+À chaque fois que nous lançons un `run`, un nouveau conteneur est créé à partir
+de l'image que l'on a précisé (via un mécanisme de Copy-On-Write, c'est donc
+très rapide et ne consomme pas beaucoup d'espace disque). Cela signifie que
+lorsque nous exécutons une commande modifiant les fichiers d'un conteneur, cela
+ne modifie pas l'image de base, mais crée une nouvelle image. Que nous pouvons
+ensuite utiliser comme image de base.
+
+Commençons par entrer dans un nouveau conteneur pour modifier l'image :
+
+```
+docker run -it ubuntu /bin/bash
+```
+
+Nous voilà maintenant dans le conteneur ! Il est assez épuré, il n'y a rien de
+superflu : il n'y a même pas d'éditeur de texte : ni vim, ni emacs, même pas
+`vi` !
+
+La première chose à faire est de télécharger la liste des paquets. En effet,
+afin de ne pas livrer de superflu, la liste des paquets et son cache ne sont
+pas inclues dans le conteneur.
+
+```
+apt-get update
+```
+
+Il peut arriver que des paquets présents dans l'image ne soient pas à
+jour. Afin de garder un environnement cohérent, il est recommandé de ne pas
+utiliser le gestionnaire de paquets pour mettre à jour les paquets présent de
+base, mais plutôt de contacter le mainteneur de l'image pour qu'il la mette à
+jour.
+
+Installons maintenant un programme :
+
+```
+apt-get install nano
+```
+
+En attendant la fin de l'installation, jetons un œil à la commande dans un
+autre terminal :
+
+```
+docker ps
+```
+
+Cette commande liste les conteneurs actifs. Notez le *Container ID* ainsi que
+le *NAMES* du conteneur du conteneur actuellement en cours d'installation de
+`nano`.
+
+Lorsque l'installation de `nano` est terminée, quittez l'image en tapant
+`exit`.
+
+Sauvegardez votre image modifiée avec la commande `commit` pour pouvoir
+commencer directement de votre image avec `nano` :
+
+```
+docker commit CONTAINER my_nano
+```
+
+En remplaçant `CONTAINER` par le nom ou l'identifiant de votre
+container. `my_nano` est le nom que vous voudrez utiliser à la place
+d'`ubuntu` :
+
+```
+docker run -it my_nano /bin/bash
+```
+
+Vous constatez cette fois que vous pouvez lancer `nano`, alors que vous ne
+pouvez toujours pas le faire dans un conteneur issue d'une image `ubuntu` !
+
+
+## Métadonnées
+
+Les images et les conteneurs sont composés d'un ensemble de couches de système
+de fichiers et de métadonnées. Ces métadonnées stockent de nombreux paramètres
+tels que la commande à lancer par défaut pour une image, ou le PID du premier
+programme lancé pour un conteneur.
+
+Vous pouvez affichez ces métadonnées avec la commande `docker inspect
+hello-world`.
+
+
+## Rendu
+
+### Questions
+
+1. Comment limiter la quantité maximale de mémoire qu'un conteneur pourra
+ utiliser ?
+
+1. Un conteneur Docker se détache-t-il de tous les *namespaces* ? Si non,
+ pourquoi ?
+
+### Exercice
+
+Réalisez un script permettant de rejoindre les namespaces d'un conteneur Docker
+actif. Vous pouvez réutiliser votre exécutable `setns` du premier TP. Vous
+allez sans doute avoir besoin d'utiliser `docker inspect`, n'hésitez pas à
+consulter son aide : `docker inspect --help`.
+
+```
+host# ./docker-attach romantic_archimedes /bin/bash
+inCntnr# _
+```
+
+où `romantic_archimedes` correspond au nom du conteneur Docker auquel on veut
+s'attacher et `/bin/bash`, la première commande que l'on va exécuter après le
+`clone`.
diff --git a/tutorial/2/installation.md b/tutorial/2/installation.md
index b716c02..9a57dd3 100644
--- a/tutorial/2/installation.md
+++ b/tutorial/2/installation.md
@@ -2,9 +2,7 @@
# Installation
-## Docker
-
-### Par le gestionnaire de paquets
+## Par le gestionnaire de paquets
Sous Debian et ses dérivés (Ubuntu, Mint, ...) le paquet et la commande ont été
nommés `docker.io`. Vous pouvez vous créer un alias `alias docker=docker.io` si
@@ -13,7 +11,44 @@ celui-ci n'a pas déjà été défini.
Sous les autres distributions, `docker` correspond a priori bien à la solution
de virtualisation légère que l'on va utiliser.
-### Manuellement
+### Debian Jessie
+
+`docker` se trouve dans les backports, ajouter-les à votre `/etc/apt/sources.list` :
+
+```
+deb http://ftp.debian.org/debian/ wheezy-backports main non-free contrib
+```
+
+Puis :
+
+```
+apt-get update
+apt-get install docker.io
+```
+
+### Debian Wheezy
+
+Il vous faut utiliser le dépôt de paquets fourni par Docker :
+
+```
+apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
+```
+
+Ajoutez cette ligne dans votre `/etc/apt/sources.list` :
+
+```
+deb https://apt.dockerproject.org/repo debian-wheezy main
+```
+
+Puis :
+
+```
+apt-get update
+apt-get install docker-engine
+```
+
+
+## Manuellement
L'équipe en charge de Docker met à disposition un script pour installer Docker
sur n'importe quel système :
@@ -22,7 +57,8 @@ sur n'importe quel système :
curl -sSL https://get.docker.com/ | sh
```
-### Vérifier la bonne marche de l'installation
+
+## Vérifier la bonne marche de l'installation
Vous devriez maintenant être capable de lancer la commande suivante :
@@ -33,17 +69,29 @@ docker version
Une sortie similaire au bloc suivant devrait apparaître sur votre écran :
```
-Client version: 1.3.2
+Client version: 1.3.3
Client API version: 1.15
Go version (client): go1.3.3
-Git commit (client): 39fa2fa
+Git commit (client): d344625
OS/Arch (client): linux/amd64
-Server version: 1.3.2
+Server version: 1.3.3
Server API version: 1.15
Go version (server): go1.3.3
-Git commit (server): 39fa2fa
+Git commit (server): d344625
```
+### `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 :
+
+```
+sudo service docker restart
+```
+
+
+### `permission denied`?
+
Si vous avez cette erreur : `dial unix /var/run/docker.sock: permission
denied.`, ajoutez votre utilisateur au groupe `docker` et **relancer votre
session** :
@@ -51,3 +99,21 @@ session** :
```
sudo gpasswd -a $USER docker
```
+
+**Attention :** cette action n'est pas anodine d'un point de vue sécurité :
+
+
+
+## Rendu
+
+### Questions
+
+1. Dans quel langage Docker a-t-il été écrit ? Docker utilise la `libcontainer`
+ afin d'avoir une couche d'abstraction des *namespaces* et des
+ *cgroups*. Dois-je installer cette bibliothèque avant de recopier sur une
+ nouvelle machine le binaire `docker` (sans passer par le gestionnaire de
+ paquets) ? Pourquoi ?
+
+1. Décrivez une méthode permettant à un utilisateur (non-root),
+ présent dans le groupe `docker`, d'effectuer une action
+ privilégiée impactant la machine hôte.
diff --git a/tutorial/2/linking.md b/tutorial/2/linking.md
new file mode 100644
index 0000000..ad233d2
--- /dev/null
+++ b/tutorial/2/linking.md
@@ -0,0 +1,35 @@
+\newpage
+
+## Lier les conteneurs
+
+En plus de vouloir partager des répertoires entre deux conteneurs, il est
+souvent nécessaire de partager des ports.
+
+Pour automatiser le partage d'informations sur les IP et ports exposés, la
+commande `run` possède l'option `--link` qui permet de définir dans les
+variables d'environnement du conteneur que l'on va lancer.
+
+Le détail des variables ajoutées dans cette situation est disponible à
+.
+
+On utilise généralement cette liaison pour fournir au conteneur hébergeant un
+site web dynamique l'IP et le port où trouver la base de données :
+
+```
+docker run -e MYSQL_ROOT_PASSWORD=mysecretpassword -d --name db1 mysql
+docker run --link db1 my_nginx
+```
+
+### Ambasador
+
+Afin d'abstraire le plus possible l'infrastructure sous-jacente et d'autoriser
+les migrations de conteneurs, on utilise le modèle *ambassador*.
+
+On lancera systématiquement un conteneur entre deux conteneurs que l'on veut
+lier : l'ambassadeur. Celui-ci s'occupera de router correctement le trafic. En
+cas de changement de route (si l'un des conteneurs change de machine hôte par
+exemple), on a simplement à redémarrer l'ambassadeur plutôt que le conteneur
+principal.
+
+La documentation officielle pour ce modèle est disponible à
+.
diff --git a/tutorial/2/todo.org b/tutorial/2/todo.org
new file mode 100644
index 0000000..4122aff
--- /dev/null
+++ b/tutorial/2/todo.org
@@ -0,0 +1,2 @@
+* entrypoint
+* parler du contexte du build
diff --git a/tutorial/2/tutorial.md b/tutorial/2/tutorial.md
index c833930..4d55df9 100644
--- a/tutorial/2/tutorial.md
+++ b/tutorial/2/tutorial.md
@@ -1,12 +1,11 @@
-% Virtualisation légère -- TP n^o^2
+% Virtualisation légère -- TP n^o^ 2
% Pierre-Olivier *Nemunaire* Mercier
% Jeudi 22 octobre 2015
-Le but de ce premier TP est d'utiliser les commandes et les appels systèmes vu
-durant le cours.
+Durant ce deuxième TP, nous allons apprendre à utiliser Docker !
Tous les éléments de ce TP (exercices et questions) sont à rendre à
- au plus tard le mercredi 21 octobre 2015 à 23 h 42. Consultez la
+ au plus tard le mercredi 28 octobre 2015 à 23 h 42. Consultez la
dernière section de chaque partie pour plus d'information sur les éléments à
rendre. Vous pouvez placer les réponses aux questions dans le corps du courriel
ou dans un fichier joint.
diff --git a/tutorial/2/volumes.md b/tutorial/2/volumes.md
new file mode 100644
index 0000000..6d53c2f
--- /dev/null
+++ b/tutorial/2/volumes.md
@@ -0,0 +1,114 @@
+\newpage
+
+## Volumes
+
+Il est possible de partager des répertoires entre plusieurs conteneurs. Pour ce
+faire, il faut déclarer dans le `Dockerfile` une ou plusieurs instructions
+`VOLUME` avec le chemin du répertoire à considérer comme volume (il est
+également possible de le faire via l'option `--volume` du client). Ces deux
+lignes sont équivalentes :
+
+```
+VOLUME /var/log/nginx
+```
+
+```
+docker run -v /var/log/nginx my_nginx
+```
+
+Pour monter les volumes dans un autre conteneur, on utilise l'argument
+`--volume-from` du client, en indiquant le nom du conteneur avec lequel on
+souhaite partager les volumes :
+
+```
+docker run -it --volume-from romantic_archimedes ubuntu /bin/bash
+```
+
+Vous constaterez que le répertoire `/var/log/nginx` est partagé entre
+`romantic_archimedes` et le dernier conteneur lancé.
+\newline
+
+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éralement on ne va
+lancer qu'une seule application par conteneur) et concevoir un service complet
+en créant un groupe de conteneur, partageant des données entre-eux par des
+volumes.
+
+Une lecture intéressante sur ce sujet est sans doute [cet article de Michael
+Crosby](http://crosbymichael.com/advanced-docker-volumes.html).
+
+
+### Partage avec la machine hôte
+
+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 :
+
+```
+docker run --rm -p 80:80 -v ~/Downloads:/usr/share/nginx/html:ro -d nginx
+```
+
+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 !
+
+
+### Data Volume Container
+
+Dans de nombreuses situations, il est intéressant de séparer les données de
+l'application, et donc d'avoir un conteneur exécutant l'application et un
+second stockant les données.
+
+Cela est particulièrement utile dans le cas d'une base de données : on veut
+pouvoir mettre à jour le conteneur exécutant le serveur, sans pour autant
+perdre les données.
+
+L'idée derrière le concept de `Data Volume Container` est de partager un volume
+avec un conteneur dont le seul rôle est de stocker les données.
+
+Il est parfaitement possible de partager un volume avec un conteneur qui n'est
+plus lancé. En effet, tant que vous n'avez pas demandé explicitement à un
+conteneur d'être supprimé, il est préservé dans un coin en attendant des jours
+meilleurs.
+
+Voici comment on pourrait lancer un conteneur exécutant une base de données :
+
+```
+docker run -v /var/lib/mysql --name dbdata busybox
+docker run --volume-from dbdata -e MYSQL_ROOT_PASSWORD=mysecretpassword -d mysql
+```
+
+Le premier conteneur, sans commande passée, va s'arrêter dès son
+lancement. Busybox est l'une des plus petites images possédant tous les outils
+de base (il est possible d'obtenir un shell en cas de besoin). Il expose un
+volume qui sera utiliser comme stockage persistant.
+
+Le second conteneur va lancer le serveur MySQL et utiliser le répertoire
+partagé pour stocker les données.
+
+Lorsqu'il y aura besoin de mettre à jour le conteneur MySQL, les données ne
+seront pas perdues (et s'il y avait besoin de migrer les données entre les deux
+versions des conteneurs, un conteneur intermédiaire pourrait parfaitement s'en
+charger).
+
+Cela facile également les sauvegardes, qui peuvent s'exécuter dans un conteneur
+distinct, dédié à la tâche de sauvegarde.
+
+
+## Rendu
+
+### Exercice
+
+Modifiez le `Dockerfile` de l'exercice précédent pour que votre application web
+(ok, c'est juste un `index.html` ...) soit contenue dans un *data volume
+container*.
+
+Choisissez le nom de votre volume judicieusement, cela peut vous faciliter la
+vie !
+
+Écrivez un script shell qui reprend les commandes que vous avez tapé dans votre
+terminal pour créer le *data volume container*, construire l'image à partir du
+Dockerfile et lancer le conteneur `my_webserver` lié.
+
+Rendre le Dockerfile, son contexte et le script de construction/lancement.
diff --git a/tutorial/2/what.md b/tutorial/2/what.md
new file mode 100644
index 0000000..861815c
--- /dev/null
+++ b/tutorial/2/what.md
@@ -0,0 +1,68 @@
+\newpage
+
+# Composition de Docker
+
+Docker est une suite d'outils de haut niveau, permettant d'utiliser très
+facilement les conteneurs.
+
+Docker est composé d'un daemon lancé au démarrage de votre machine, avec lequel
+vous interagissez via un client (le programme `docker`) qui se connecte au
+daemon au moyen d'une socket. Le client peut donc potentiellement être sur une
+machine distincte du daemon où s'exécutent les conteneurs.
+
+
+## Les images Docker
+
+Une image Docker est un système de fichiers en lecture seule. Il est formé d'un
+ensemble de couches, agrégées par un UnionFS.
+
+Par exemple, une image peut être un système Ubuntu complet ou juste busybox ou
+encore un serveur web et votre application web, prêt à l'emploi.
+
+Les images sont utilisées pour créer des conteneurs.
+
+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 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 : à
+chaque fois que vous lancez un conteneur, une couche lecture/écriture est
+ajoutée au dessus de l'image. Cette couche est propre au conteneur et est
+temporaire : l'image n'est pas modifié par l'exécution d'un conteneur.
+
+Chaque conteneur s'exécute dans un environnement restreint (namespaces,
+cgroups, capabilities, ...).
+
+
+## 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 réceptionner.
+
+Le registre utilisé de base est le [Docker Hub](https://hub.docker.com/) : il
+contient à la fois des images officielles (ubuntu, debian, nginx, ...) et des
+images crées par des utilisateurs.
+
+
+## Outils annexes
+
+En plus du Docker-engine, le daemon et client que nous allons utiliser
+aujourd'hui, Docker développe également Docker-machine : qui permet d'installer
+et configurer le daemon rapidement sur plusieurs machines (afin de les utiliser
+au sein d'un cluster) et Docker-compose : qui permet de lancer un ensemble de
+conteneurs dépend les uns des autres (par exemple un serveur web et sa base de
+données).
+
+
+## Rendu
+
+1. À quoi correspondent les différents modes réseau utilisables dans Docker : à
+ quel type de réseau LXC (VLAN, MACVLAN-VEPA, veth, phys, ...)
+ correspondent-ils ? comment sont utilisés les *namespaces Network* ?
+
+1. Quels sont les différents *storage drivers* de Docker ? décrivez-les en
+ quelques mots.