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.