diff --git a/tutorial/2/Makefile b/tutorial/2/Makefile
new file mode 100644
index 0000000..9097b04
--- /dev/null
+++ b/tutorial/2/Makefile
@@ -0,0 +1,19 @@
+SOURCES = tutorial.md installation.md docker.md
+TEMPLATE = ../../template.tex
+PANDOCOPTS = --latex-engine=xelatex \
+ --standalone \
+ --normalize \
+ --number-sections \
+ -M lang=frenchb \
+ -M fontsize=12pt \
+ -M papersize=a4paper \
+ --template=${TEMPLATE}
+
+
+all: tutorial.pdf
+
+tutorial.pdf: ${SOURCES}
+ pandoc ${PANDOCOPTS} -o $@ $+
+
+clean::
+ rm tutorial.pdf
diff --git a/tutorial/2/docker.md b/tutorial/2/docker.md
new file mode 100644
index 0000000..f6f630d
--- /dev/null
+++ b/tutorial/2/docker.md
@@ -0,0 +1,384 @@
+\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/installation.md b/tutorial/2/installation.md
new file mode 100644
index 0000000..b716c02
--- /dev/null
+++ b/tutorial/2/installation.md
@@ -0,0 +1,53 @@
+\newpage
+
+# Installation
+
+## Docker
+
+### 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
+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
+
+L'équipe en charge de Docker met à disposition un script pour installer Docker
+sur n'importe quel système :
+
+```sh
+curl -sSL https://get.docker.com/ | sh
+```
+
+### Vérifier la bonne marche de l'installation
+
+Vous devriez maintenant être capable de lancer la commande suivante :
+
+```
+docker version
+```
+
+Une sortie similaire au bloc suivant devrait apparaître sur votre écran :
+
+```
+Client version: 1.3.2
+Client API version: 1.15
+Go version (client): go1.3.3
+Git commit (client): 39fa2fa
+OS/Arch (client): linux/amd64
+Server version: 1.3.2
+Server API version: 1.15
+Go version (server): go1.3.3
+Git commit (server): 39fa2fa
+```
+
+Si vous avez cette erreur : `dial unix /var/run/docker.sock: permission
+denied.`, ajoutez votre utilisateur au groupe `docker` et **relancer votre
+session** :
+
+```
+sudo gpasswd -a $USER docker
+```
diff --git a/tutorial/2/tutorial.md b/tutorial/2/tutorial.md
new file mode 100644
index 0000000..c833930
--- /dev/null
+++ b/tutorial/2/tutorial.md
@@ -0,0 +1,21 @@
+% 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.
+
+Tous les éléments de ce TP (exercices et questions) sont à rendre à
+ au plus tard le mercredi 21 octobre 2015 à 23 h 42. Consultez la
+dernière section de chaque partie pour plus d'information sur les éléments à
+rendre. Vous pouvez placer les réponses aux questions dans le corps du courriel
+ou dans un fichier joint.
+
+En tant que personnes sensibilisées à la sécurité des échanges électroniques,
+vous devriez m'envoyer vos rendus signés avec votre clef PGP. Pensez à
+[me](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x842807A84573CC96) faire
+signer votre clef et n'hésitez pas à
+[faire signer votre clef](http://www.meetup.com/fr/Paris-certification-de-cles-PGP-et-CAcert/).
+
+\hypersetup{linkcolor=black}
+\tableofcontents