TP2 done
This commit is contained in:
parent
d3b050024c
commit
d3281c2d51
|
@ -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
|
TEMPLATE = ../../template.tex
|
||||||
PANDOCOPTS = --latex-engine=xelatex \
|
PANDOCOPTS = --latex-engine=xelatex \
|
||||||
--standalone \
|
--standalone \
|
||||||
|
|
|
@ -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 <https://docs.docker.com/reference/builder/> 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 <http://localhost:49153/>.
|
|
||||||
|
|
||||||
À 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 à
|
|
||||||
<https://docs.docker.com/userguide/dockerlinks/#environment-variables>.
|
|
||||||
|
|
||||||
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 à
|
|
||||||
<https://docs.docker.com/articles/ambassador_pattern_linking/>.
|
|
167
tutorial/2/dockerfile.md
Normal file
167
tutorial/2/dockerfile.md
Normal file
|
@ -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 <http://localhost:49153/>.
|
||||||
|
|
||||||
|
À 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 <https://docs.docker.com/reference/builder/> 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
|
||||||
|
```
|
182
tutorial/2/first.md
Normal file
182
tutorial/2/first.md
Normal file
|
@ -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
|
||||||
|
<hub.docker.com>. 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`.
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
# Installation
|
# 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é
|
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
|
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
|
Sous les autres distributions, `docker` correspond a priori bien à la solution
|
||||||
de virtualisation légère que l'on va utiliser.
|
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
|
L'équipe en charge de Docker met à disposition un script pour installer Docker
|
||||||
sur n'importe quel système :
|
sur n'importe quel système :
|
||||||
|
@ -22,7 +57,8 @@ sur n'importe quel système :
|
||||||
curl -sSL https://get.docker.com/ | sh
|
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 :
|
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 :
|
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
|
Client API version: 1.15
|
||||||
Go version (client): go1.3.3
|
Go version (client): go1.3.3
|
||||||
Git commit (client): 39fa2fa
|
Git commit (client): d344625
|
||||||
OS/Arch (client): linux/amd64
|
OS/Arch (client): linux/amd64
|
||||||
Server version: 1.3.2
|
Server version: 1.3.3
|
||||||
Server API version: 1.15
|
Server API version: 1.15
|
||||||
Go version (server): go1.3.3
|
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
|
Si vous avez cette erreur : `dial unix /var/run/docker.sock: permission
|
||||||
denied.`, ajoutez votre utilisateur au groupe `docker` et **relancer votre
|
denied.`, ajoutez votre utilisateur au groupe `docker` et **relancer votre
|
||||||
session** :
|
session** :
|
||||||
|
@ -51,3 +99,21 @@ session** :
|
||||||
```
|
```
|
||||||
sudo gpasswd -a $USER docker
|
sudo gpasswd -a $USER docker
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Attention :** cette action n'est pas anodine d'un point de vue sécurité :
|
||||||
|
<https://docs.docker.com/articles/security/#docker-daemon-attack-surface>
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
35
tutorial/2/linking.md
Normal file
35
tutorial/2/linking.md
Normal file
|
@ -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 à
|
||||||
|
<https://docs.docker.com/userguide/dockerlinks/#environment-variables>.
|
||||||
|
|
||||||
|
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 à
|
||||||
|
<https://docs.docker.com/articles/ambassador_pattern_linking/>.
|
2
tutorial/2/todo.org
Normal file
2
tutorial/2/todo.org
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
* entrypoint
|
||||||
|
* parler du contexte du build
|
|
@ -1,12 +1,11 @@
|
||||||
% Virtualisation légère -- TP n^o^2
|
% Virtualisation légère -- TP n^o^ 2
|
||||||
% Pierre-Olivier *Nemunaire* Mercier
|
% Pierre-Olivier *Nemunaire* Mercier
|
||||||
% Jeudi 22 octobre 2015
|
% Jeudi 22 octobre 2015
|
||||||
|
|
||||||
Le but de ce premier TP est d'utiliser les commandes et les appels systèmes vu
|
Durant ce deuxième TP, nous allons apprendre à utiliser Docker !
|
||||||
durant le cours.
|
|
||||||
|
|
||||||
Tous les éléments de ce TP (exercices et questions) sont à rendre à
|
Tous les éléments de ce TP (exercices et questions) sont à rendre à
|
||||||
<virli@nemunai.re> au plus tard le mercredi 21 octobre 2015 à 23 h 42. Consultez la
|
<virli@nemunai.re> 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 à
|
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
|
rendre. Vous pouvez placer les réponses aux questions dans le corps du courriel
|
||||||
ou dans un fichier joint.
|
ou dans un fichier joint.
|
||||||
|
|
114
tutorial/2/volumes.md
Normal file
114
tutorial/2/volumes.md
Normal file
|
@ -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.
|
68
tutorial/2/what.md
Normal file
68
tutorial/2/what.md
Normal file
|
@ -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.
|
Loading…
Reference in New Issue
Block a user