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