Ready for j1
This commit is contained in:
parent
150f5a8834
commit
dc8544c0c9
31 changed files with 688 additions and 544 deletions
|
@ -1,4 +1,4 @@
|
|||
SOURCES = tutorial.md installation.md what.md first.md dockerfile.md volumes.md linking.md
|
||||
SOURCES = tutorial.md installation.md what.md first.md supervisor.md goodpractices.md compose.md project.md
|
||||
TEMPLATE = ../../template.tex
|
||||
PANDOCOPTS = --latex-engine=xelatex \
|
||||
--standalone \
|
||||
|
|
36
tutorial/2/compose.md
Normal file
36
tutorial/2/compose.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
\newpage
|
||||
|
||||
# Compose
|
||||
|
||||
Avec notre conteneur utilisant `supervisor`, nous ne respectons pas
|
||||
bien cette dernière bonne pratique d'un seul processus par conteneur
|
||||
:-(
|
||||
|
||||
L'intérêt est de permettre à chaque conteneur d'effectuer une tâche
|
||||
générique, de manière à pouvoir être réutilisé pour d'autres projet
|
||||
dans le futur. Par exemple, notre conteneur InfluxDB pourra être
|
||||
utilisé pour stocker des relevés de métriques systèmes ou des logs.
|
||||
Grafana peut également afficher davantage d'informations ou combiner
|
||||
les informations de plusieurs bases distinctes.
|
||||
|
||||
|
||||
## Séparer le `Dockerfile`
|
||||
|
||||
Commençons par séparer notre `Dockerfile` en deux : dans une partie
|
||||
nous allons garder la partie InfluxDB, de l'autre la partie Grafana.
|
||||
|
||||
Il va vous falloir créer deux dossiers distincts, il en faut un par
|
||||
`Dockerfile`.
|
||||
|
||||
Profitez en pour rajouter les Data Volume Container.
|
||||
|
||||
|
||||
## Automatiser le lancement
|
||||
|
||||
Commencez par lancer tous vos conteneurs à la main pour voir les
|
||||
étapes que vous allez devoir automatiser.
|
||||
|
||||
Au lieu de faire un script pour construire et lancer tous vos
|
||||
conteneurs, définissez à la racine de votre projet un fichier
|
||||
`docker-compose.yml` qui contiendra les méthodes de construction et
|
||||
les paramètres d'exécution.
|
|
@ -1,167 +0,0 @@
|
|||
\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
|
||||
```
|
18
tutorial/2/entrypoint.md
Normal file
18
tutorial/2/entrypoint.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
\newpage
|
||||
|
||||
# Entrypoint
|
||||
|
||||
Jusque là, à chaque redémarrage d'InfluxDB, il est nécessaire de reconfigurer
|
||||
Grafana pour lui indiquer la nouvelle IP du conteneur. En effet, le data
|
||||
container préserve les données, mais un changement d'IP n'est pas
|
||||
répercuté. Pour cela, il nous fait un script d'initialisation, qui va écrire
|
||||
l'ip de notre conteneur Docker dans la table `data_source` :
|
||||
|
||||
Petit indice, les requêtes SQL sont les suivantes :
|
||||
|
||||
```
|
||||
DELETE FROM "data_source";
|
||||
INSERT INTO "data_source" VALUES(1,1,0,'influxdb','influx','direct','http://${}:8086/','user','pass','metrics',0,'','',0,'null','2015-10-29 09:00:00','2015-10-29 09:05:00');
|
||||
```
|
||||
|
||||
La base se trouve dans `/var/lib/grafana/grafana.db`.
|
|
@ -1,182 +1,85 @@
|
|||
\newpage
|
||||
|
||||
# Mon premier conteneur
|
||||
# Premiers pas
|
||||
|
||||
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.
|
||||
Dans un premier temps, nous allons créer une image Docker comme si
|
||||
l'on réalisait l'installation sur une machine classique : en suivant
|
||||
une recette. La machine (notre première image Docker) contient tout le
|
||||
nécessaire pour faire fonctionner notre service.
|
||||
|
||||
|
||||
## Exécuter un programme dans un conteneur
|
||||
## Les caches
|
||||
|
||||
Maintenant que nous avons à notre disposition l'image d'un conteneur Ubuntu,
|
||||
lançons-la !
|
||||
Nous avons vu que chaque instruction de notre `Dockerfile` génère une
|
||||
couche. Chaque couche sert de cache d'une construction de conteneur à
|
||||
l'autre. Ainsi, lorsque vous modifiez une instruction dans votre
|
||||
`Dockerfile`, les instructions précédentes ne sont pas réexécutées
|
||||
mais sont ressorties du cache.
|
||||
|
||||
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 :
|
||||
Le cache se basant principalement sur le contenu de chaque instruction
|
||||
dans le `Dockerfile` (pour les `COPY` et `ADD`, il va aussi regarder
|
||||
la date de dernière modification de fichier copié ou ajouté). Donc
|
||||
tant qu'une instruction n'est pas modifiée dans le `Dockerfile`, le
|
||||
cache sera utilisé.
|
||||
|
||||
```
|
||||
docker run ubuntu /bin/echo "Hello World"
|
||||
```
|
||||
Il est possible de ne pas utiliser le cache et de relancer toutes les
|
||||
étapes du `Dockerfile` en ajoutant l'option `--no-cache` au moment du
|
||||
`docker build`.
|
||||
|
||||
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.
|
||||
Les couches du cache peuvent être partagées entre plusieurs conteneur,
|
||||
c'est ainsi que vous pouvez partager facilement une plus grosse partie
|
||||
du système de fichier (afin de profiter du cache du système de
|
||||
fichiers au moment de l'exécution du conteneur).
|
||||
|
||||
|
||||
## Modifier un conteneur
|
||||
## `apt-get`
|
||||
|
||||
À 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.
|
||||
Pour profiter du cache, il faut donc placer les étapes les plus
|
||||
génériques (qui seraient susceptibles d'apparaître dans plusieurs
|
||||
conteneur), en haut du `Dockerfile`.
|
||||
|
||||
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` !
|
||||
Commençons donc notre `Dockerfile` : choisissez une image de base pour
|
||||
votre `FROM`, et indiquez votre nom avec l'instruction `MAINTAINER`,
|
||||
pour indiquez que c'est vous qui maintenez ce conteneur (si d'autres
|
||||
gens ont besoin qu'il faut le mettre à jour par exemple).
|
||||
|
||||
|
||||
## Métadonnées
|
||||
## `RUN` ou script ?
|
||||
|
||||
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.
|
||||
### InfluxDB
|
||||
|
||||
Vous pouvez affichez ces métadonnées avec la commande `docker inspect
|
||||
hello-world`.
|
||||
Ensuite viens l'installation d'InfluxDB. Le paquet n'est pas
|
||||
disponible dans les dépôts. La
|
||||
[https://influxdb.com/docs/v0.9/introduction/installation.html](procédure
|
||||
décrite sur le site) incite à télécharger le paquet mis à disposition
|
||||
puis à l'installer via `dpkg -i`.
|
||||
|
||||
Deux solutions s'offrent à nous : télécharger le paquet hors du
|
||||
conteneur, le copier, puis l'installer. Ou faire un `RUN` avec toutes
|
||||
ces opérations (sans oublier l'installation de `wget`/`curl`).
|
||||
|
||||
La copie étant définitive (supprimer le fichier ne le supprimera pas
|
||||
des couches où il a pu exister), donc la seconde solution semble
|
||||
préférable (mais `wget` restera en déchet).
|
||||
|
||||
Écrivez une commande `RUN` qui va télécharger la dernière version
|
||||
d'InfluxDB, qui va l'installer et supprimer le fichier.
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
À ce stade, nous pouvons déjà terminer le conteneur et tester
|
||||
qu'InfluxDB est bien utilisable : `EXPOSE`, `CMD`, ... Il est possible
|
||||
que vous ayez à écraser le fichier de configuration via un
|
||||
`COPY`. Garder la ligne qui vous permet de lancer votre serveur web
|
||||
dans un coin, en attendant la partie suivante.
|
||||
|
||||
|
||||
## Rendu
|
||||
### Grafana
|
||||
|
||||
### Questions
|
||||
Une fois InfluxDB configuré, nous allons avoir la même réflexion avec
|
||||
Grafana.
|
||||
|
||||
1. Comment limiter la quantité maximale de mémoire qu'un conteneur pourra
|
||||
utiliser ?
|
||||
De la même manière, téléchargez, installez et supprimez le paquet.
|
||||
|
||||
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`.
|
||||
Lors de vos tests, sachez que vous pouvez vous connecter sur grafana avec
|
||||
l'utilisateur *admin*, mot de passe *admin*.
|
||||
|
|
214
tutorial/2/goodpractices.md
Normal file
214
tutorial/2/goodpractices.md
Normal file
|
@ -0,0 +1,214 @@
|
|||
\newpage
|
||||
|
||||
# Retour sur les bonnes pratiques
|
||||
|
||||
http://docs.docker.com/articles/dockerfile_best-practices/
|
||||
|
||||
## Utilisez le fichier `.dockerignore`
|
||||
|
||||
Dans la plupart des cas, vos Dockerfile seront dans des dossiers contenant
|
||||
beaucoup de fichiers qui ne sont pas nécessaire à la construction de votre
|
||||
conteneur (par exemple, vous pouvez avoir un `Dockerfile` placé à la racine
|
||||
d'un dépôt git : il va avoir besoin des binaires compilés, mais pas des
|
||||
sources).
|
||||
|
||||
Afin d'améliorer les performances lors de la construction, vous pouvez exclure
|
||||
les fichiers et dossiers inutiles au conteneur en ajoutant un fichier
|
||||
`.dockerignore` dans le répertoire de votre `Dockerfile`.
|
||||
|
||||
Ce fichier fonctionne de la même manière que le `.gitignore` : vous pouvez
|
||||
utiliser du globing.
|
||||
|
||||
Pour plus d'informations, vous pouvez consulter la documentation accessible à
|
||||
<http://docs.docker.com/reference/builder/#dockerignore-file>.
|
||||
|
||||
|
||||
## N'installez rien de superflu
|
||||
|
||||
Afin de réduire la quantité de dépendances à installer, n'installez pas de
|
||||
paquets dont vous n'avez pas vraiment l'utilité : il n'y a pas de raison par
|
||||
exemple d'avoir un éditeur de texte dans un environnement qui sera utilisé
|
||||
comme serveur web. Un autre conteneur pourra contenir cet éditeur de texte dans
|
||||
les cas où vous avez besoin de modifier des données.
|
||||
|
||||
En plus, cela réduira le temps de build et la taille des images produites !
|
||||
|
||||
|
||||
## Minimisez le nombre de couches
|
||||
|
||||
Vous devez trouver l'équilibre idéal entre la lisibilité de votre `Dockerfile`
|
||||
(qui assure la maintenabilité sur le long-terme) et le nombre de couches
|
||||
créées. Le nombre de couches idéal devrait être égal au nombre de branches
|
||||
distincte partant d'une image de base, afin d'utiliser au mieux le cache du
|
||||
système de fichiers.
|
||||
|
||||
|
||||
## Ordonnez vos lignes de commandes complexes
|
||||
|
||||
### Allez à la ligne pour séparer les longues lignes de commandes complexes
|
||||
|
||||
Aérez vos `Dockerfile` !
|
||||
|
||||
N'hésitez pas à commenter et séparer les blocs logiques ensemble, comme lorsque
|
||||
vous codez.
|
||||
|
||||
Lorsqu'une ligne devient complexe, allez à la ligne :
|
||||
|
||||
```
|
||||
RUN apt-get update && apt-get install -y \
|
||||
nginx \
|
||||
php5-fpm
|
||||
```
|
||||
|
||||
Notez les backslashs à la fin des lignes, indiquant qu'elle n'est pas terminée.
|
||||
|
||||
### Triez les arguments par ordre alphabétique
|
||||
|
||||
Lorsque c'est possible, ordonnez vos lignes suivant un ordre logique. Par
|
||||
exemple :
|
||||
|
||||
```
|
||||
RUN apt-get update && apt-get install -y \
|
||||
bzr \
|
||||
cvs \
|
||||
git \
|
||||
mercurial \
|
||||
subversion
|
||||
```
|
||||
|
||||
|
||||
## Profitez du système de cache
|
||||
|
||||
Le processus de construction de votre image Docker va lire les informations de
|
||||
votre Dockerfile dans l'ordre. Pour chaque instruction, Docker va essayer de
|
||||
trouver si une image n'est pas déjà disponible dans le cache (plutôt que de
|
||||
créer une nouvelle image identique).
|
||||
|
||||
Il y a un certain nombre de règles à connaître pour bien utiliser ce mécanisme :
|
||||
|
||||
- En démarrant d'une image de base déjà présente dans le cache (`docker
|
||||
images`), l'instruction suivante est comparée avec toutes les autres images
|
||||
existantes qui en dérivent directement. Si aucune image correspondant n'est
|
||||
trouvé pour l'instruction, le cache est invalidé pour le reste de cette
|
||||
construction.
|
||||
- Dans la plupart des cas, Docker va simplement comparer l'instruction lue avec
|
||||
le(s) différente(s) image(s) qui dérive(nt) de la commande précédente. Si
|
||||
aucune commande correspondante n'est trouvé, le cache se retrouve invalidé
|
||||
pour les instructions suivantes.
|
||||
- Pour les instructions `ADD` et `COPY`, en plus de la comparaison précédente,
|
||||
la somme de contrôle du fichier est ajoutée. Si le fichier a été modifié, le
|
||||
cache se retrouve invalidé.
|
||||
- Une fois que le cache est invalidé, toutes les commandes restantes à exécuter
|
||||
dans le `Dockerfile` vont être exécutées.
|
||||
|
||||
|
||||
## Concevez des conteneur éphémères
|
||||
|
||||
Les conteneurs que vous générez doivent aussi éphémères que possible : ils
|
||||
devraient pouvoir être arrêtés, détruits et recréés sans nécessité d'étape de
|
||||
reconfiguration. La configuration devrait se faire au lancement du conteneur ou
|
||||
lors de sa construction.
|
||||
|
||||
|
||||
## Cas d'`apt-get` et des gestionnaires de paquets
|
||||
|
||||
- N'exécutez pas `apt-get update` seul sur une ligne. Cela risque de poser des
|
||||
problèmes de cache, car la ligne ne va jamais changer et le cache sera
|
||||
toujours utilisé. Vous risquez de récupérer des paquets qui ne sont pas à
|
||||
jour.
|
||||
- Évitez de mettre à jour le système fourni (via `apt-get upgrade` ou `apt-get
|
||||
update`). Si l'image n'est pas à jour, contactez son mainteneur. Si vous avez
|
||||
besoin d'une version à jour d'un paquet distribué avec l'image, préférez
|
||||
l'utilisation d'`apt-get install -y foo` qui mettra à jour exclusivement le
|
||||
paquet `foo`, sans altérer le reste du système.
|
||||
- Pour assurer une bonne gestion du cache, n'hésitez pas à indiquer les
|
||||
versions des programmes que vous voulez installer sur votre ligne de commande
|
||||
`apt-get`.
|
||||
|
||||
|
||||
## Exposez les ports standards
|
||||
|
||||
La commande `EXPOSE` vous permet d'indiquer les ports sur lesquels votre
|
||||
conteneur s'attend à recevoir des paquets venant de l'extérieur. Ces ports ne
|
||||
sont pas partagés avec l'hôte ou les autres conteneur, donc vous n'avez pas de
|
||||
raison de ne pas utiliser les ports standards.
|
||||
|
||||
Si vous faites cela, il y a de forte chance qu'il n'y ait pas besoin de
|
||||
modifier la configuration des autres logiciels contenu dans d'autres conteneurs
|
||||
puis qu'ils sont généralement configurés pour se connecter aux ports standards.
|
||||
|
||||
S'il y a un conflit sur la machine hôte, il sera toujours temps de créer une
|
||||
redirection à ce moment là.
|
||||
|
||||
|
||||
## La bonne utilisation de l'`ENTRYPOINT`
|
||||
|
||||
L'entrypoint peut être utilisé de deux manières différentes :
|
||||
|
||||
- Vous pouvez l'utiliser de telle sorte que la commande passée au `docker run`,
|
||||
après le nom de l'image, corresponde aux arguments attendu par le programme
|
||||
indiqué dans l'entrypoint. Par exemple pour nginx :
|
||||
|
||||
```
|
||||
ENTRYPOINT ["nginx"]
|
||||
CMD ["-g daemon off;"]
|
||||
```
|
||||
|
||||
- Vous pouvez aussi utiliser un script qui servira à faire les initialisations
|
||||
ou les configurations nécessaire au bon fonctionnement du conteneur
|
||||
(rappelez-vous, il doit être éphémère !). Par exemple, le `Dockerfile` pour
|
||||
l'image de PostgreSQL possède cet entrypoint :
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ "$1" = 'postgres' ]; then
|
||||
chown -R postgres "$PGDATA"
|
||||
|
||||
if [ -z "$(ls -A "$PGDATA")" ]; then
|
||||
gosu postgres initdb
|
||||
fi
|
||||
|
||||
exec gosu postgres "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
```
|
||||
|
||||
|
||||
## `[""]`, `'` et sans `[]`
|
||||
|
||||
Les instructions `ENTRYPOINT` et `CMD` peuvent prendre deux formes :
|
||||
|
||||
- `["cmd", "arg1", "arg2"]` : ici, un simple `exexve` sera effectué avec ces
|
||||
arguments. Si d'éventuels variables se trouve dans les arguments, elles ne
|
||||
seront pas remplacées.
|
||||
- `cmd arg1 arg2` : ici l'exécution se fera au sein d'un `sh -c`, donc les
|
||||
variables seront remplacés et étendues.
|
||||
|
||||
Les commandes sous forme de tableau étant parsées par un parser JSON, vous ne
|
||||
pouvez pas utiliser les simple quotes.
|
||||
|
||||
|
||||
## Volumes
|
||||
|
||||
L'instruction `VOLUME` doit être utilisée pour exposer tous les espaces de
|
||||
stockage
|
||||
|
||||
|
||||
## Réduisez les privilèges
|
||||
|
||||
Utilisez l'instruction `USER` dès que vous le pouvez, lorsqu'un service ne
|
||||
réclame pas de privilège particulier.
|
||||
|
||||
Il vous faudra sans doute créer l'utilisateur et son groupe dans le Dockerfile.
|
||||
|
||||
|
||||
## Exécutez un seul processus par conteneur
|
||||
|
||||
Dans la majorité des cas, vous ne devriez jamais lancer plus d'un seul
|
||||
processus par conteneur. Il est préférable de répartir chaque application dans
|
||||
un conteneur distinct qui n'effectue que le travail pour lequel il est
|
||||
chargé. Les options de liaison entre conteneur sont à votre disposition pour
|
||||
vous aider à cette tâche.
|
|
@ -2,118 +2,30 @@
|
|||
|
||||
# Installation
|
||||
|
||||
## Par le gestionnaire de paquets
|
||||
## `docker-compose`
|
||||
|
||||
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.
|
||||
|
||||
### Debian Jessie
|
||||
|
||||
`docker` se trouve dans les backports, ajouter-les à votre `/etc/apt/sources.list` :
|
||||
L'équipe en charge de Docker compose met à disposition un binaire contenant
|
||||
tous les scripts. Nous pouvons l'installer en suivant la procédure suivante :
|
||||
|
||||
```
|
||||
deb http://ftp.debian.org/debian/ jessie-backports main non-free contrib
|
||||
curl -L https://github.com/docker/compose/releases/download/1.3.3/docker-compose-Linux-x86_64 > /usr/bin/docker-compose
|
||||
chmod +x /usr/bin/docker-compose
|
||||
```
|
||||
|
||||
Puis :
|
||||
Le projet étant écrit en Python, il est également disponible via `pip`, si vous
|
||||
préférez cette méthode. N'oubliez pas de préciser une version compatible avec
|
||||
votre version de Docker.
|
||||
|
||||
|
||||
### Vérification du fonctionnement
|
||||
|
||||
Comme avec Docker, nous pouvons vérifier le bon fonctionnement de
|
||||
`docker-compose` en exécutant la commande :
|
||||
|
||||
```
|
||||
apt-get update
|
||||
apt-get install docker.io
|
||||
42sh$ docker-compose --version
|
||||
docker-compose version: 1.3.3
|
||||
```
|
||||
|
||||
### 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 :
|
||||
|
||||
```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.3
|
||||
Client API version: 1.15
|
||||
Go version (client): go1.3.3
|
||||
Git commit (client): d344625
|
||||
OS/Arch (client): linux/amd64
|
||||
Server version: 1.3.3
|
||||
Server API version: 1.15
|
||||
Go version (server): go1.3.3
|
||||
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** :
|
||||
|
||||
```
|
||||
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.
|
||||
Si vous obtenez une réponse similaire, c'est que vous êtes prêt à commencer le
|
||||
TP ! Alors n'attendons pas, partons à l'aventure !
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
\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/>.
|
63
tutorial/2/project.md
Normal file
63
tutorial/2/project.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
\newpage
|
||||
|
||||
# Rendu
|
||||
|
||||
## TP
|
||||
|
||||
Rendez le contenu de votre dossier à la dernière étape du TP : avec le
|
||||
`docker-compose.yml`, ainsi que vos `Dockerfile` et les éventuels fichiers
|
||||
annexes.
|
||||
|
||||
|
||||
## Projet
|
||||
|
||||
De la même manière que nous avons réaliser un groupe de conteneurs utilisant
|
||||
`grafana` et `InfluxDB`, qui permet d'afficher facilement des métriques sous
|
||||
forme de graphiques, vous allez réaliser, à l'aide des images Docker
|
||||
présentent sur le hub, une interface web de recherche et de visualisation de
|
||||
logs, utilisant
|
||||
[Kibana](https://www.digitalocean.com/community/tutorials/how-to-install-elasticsearch-logstash-and-kibana-4-on-ubuntu-14-04).
|
||||
|
||||
Toutes la chaîne d'image Docker est déjà présente sur le hub :
|
||||
[logstash](https://hub.docker.com/_/logstash/),
|
||||
[elasticsearch](https://hub.docker.com/_/kibana/),
|
||||
[kibana](https://hub.docker.com/_/kibana/).
|
||||
|
||||
Le but du projet est donc de réaliser un `docker-compose.yml` permettant
|
||||
d'avoir un système de centralisation de logs fonctionnels. Vous aurez sans
|
||||
doute à faire quelques adaptations au niveau des images Docker, au moins pour
|
||||
des fichiers de configuration, donc il n'y aura sans doute pas que ce fichier à
|
||||
rendre.
|
||||
|
||||
Vous pouvez utiliser comme source de logs les conteneurs du TP, grâce aux
|
||||
options `log-driver=gelf` et `log-opt=gelf-address=udp://host:port`, passées
|
||||
aux `docker run` (ou dans le `docker-compose`).
|
||||
|
||||
Côté `logstash`, votre configuration devrait ressembler à ça :
|
||||
|
||||
```
|
||||
input {
|
||||
tcp {
|
||||
port => 4242
|
||||
}
|
||||
udp {
|
||||
port => 4242
|
||||
}
|
||||
}
|
||||
|
||||
output {
|
||||
elasticsearch { }
|
||||
}
|
||||
```
|
||||
|
||||
Vous pourrez ainsi envoyez les logs de Docker sur le port 4242. Ou directement
|
||||
vos logs syslog :
|
||||
|
||||
```
|
||||
netcat localhost 4242 < /var/log/syslog
|
||||
```
|
||||
|
||||
N'oubliez pas de lire les README associés aux images Docker du hub, ils vous
|
||||
indiqueront comment utiliser les images et comment leur passer des paramètres.
|
||||
|
||||
Bon courage !
|
60
tutorial/2/supervisor.md
Normal file
60
tutorial/2/supervisor.md
Normal file
|
@ -0,0 +1,60 @@
|
|||
\newpage
|
||||
|
||||
# Plusieurs daemons dans un conteneur
|
||||
|
||||
## Script d'init
|
||||
|
||||
Lors du dernier TP, nous avons vu que les conteneurs étaient détruits
|
||||
dès que le premier processus du conteneur (celui qui a le PID 1, à la
|
||||
place d'`init`) terminer son exécution, quelque soit le statut de ses
|
||||
éventuels fils.
|
||||
|
||||
Pour lancer tous nos daemon,
|
||||
|
||||
|
||||
## Autorestart
|
||||
|
||||
L'avantage de détruire le conteneur à la mort du père, est que s'il
|
||||
s'agit de notre processus principal et qu'il est seul (par exemple
|
||||
`nginx` pour un conteneur qui délivre des pages web), il va être
|
||||
possible de redémarrer le conteneur automatiquement grâce à la
|
||||
*restart policy* que l'on peut définir au moment du `docker run` :
|
||||
|
||||
```
|
||||
docker run -d -p 80:80 --restart=on-failure nginx
|
||||
```
|
||||
|
||||
Il existe trois règles de redémarrage différentes :
|
||||
|
||||
- **`no` :** il s'agit de la règle par défaut. Lorsque l'exécution du
|
||||
conteneur se termine, il n'est pas redémarré.
|
||||
- **`on-failure[:max-retries]` :** redémarre uniquement si le code de
|
||||
sortie du conteneur n'est pas 0. Il est possible de préciser pour
|
||||
cette option le nombre maximum de redémarrage qui sera tenté.
|
||||
- **`always` :** redémarre le conteneur dans tous les cas, quelque
|
||||
soit son code de sortie et indéfiniment.
|
||||
|
||||
Le script d'init que vous avez réalisé ne tient sans doute pas compte
|
||||
de cela. Mais plein de gens ont cette problématique et `supervisor`
|
||||
répond parfaitement à notre problématique !
|
||||
|
||||
|
||||
## `supervisor`
|
||||
|
||||
Première étape : installer `supervisor`, le paquet se trouve dans les
|
||||
dépôts.
|
||||
|
||||
L'étape suivante consiste à remplir puis copier le fichier de
|
||||
configuration dans le conteneur. Vous allez devoir écraser dans votre
|
||||
conteneur le fichier `/etc/supervisord.conf` pour démarrer à la fois
|
||||
`grafana` et `influxdb`.
|
||||
|
||||
Vous pouvez vous aider de la documentation disponible à :
|
||||
<http://supervisord.org/configuration.html>
|
||||
|
||||
|
||||
## C'est parti !
|
||||
|
||||
Votre conteneur doit maintenant être parfaitement fonctionnel : vous
|
||||
devriez pouvoir lancer votre script de monitoring et voir apparaître
|
||||
vos données dans Grafana !
|
|
@ -1,2 +0,0 @@
|
|||
* entrypoint
|
||||
* parler du contexte du build
|
|
@ -1,11 +1,11 @@
|
|||
% Virtualisation légère -- TP n^o^ 2
|
||||
% Virtualisation légère -- TP n^o^3
|
||||
% Pierre-Olivier *Nemunaire* Mercier
|
||||
% Jeudi 22 octobre 2015
|
||||
% Jeudi 29 octobre 2015
|
||||
|
||||
Durant ce deuxième TP, nous allons apprendre à utiliser Docker !
|
||||
Durant ce troisième TP, nous allons approfondir l'utilisation de Docker !
|
||||
|
||||
Tous les éléments de ce TP (exercices et questions) sont à rendre à
|
||||
<virli@nemunai.re> au plus tard le mercredi 28 octobre 2015 à 23 h 42. Consultez la
|
||||
<virli@nemunai.re> au plus tard le jeudi 12 novembre 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.
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
\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.
|
|
@ -1,68 +1,18 @@
|
|||
\newpage
|
||||
|
||||
# Composition de Docker
|
||||
# But du TP
|
||||
|
||||
Docker est une suite d'outils de haut niveau, permettant d'utiliser très
|
||||
facilement les conteneurs.
|
||||
Aujourd'hui, nous allons terminer notre système de monitoring commencé lors du
|
||||
premier TP.
|
||||
|
||||
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.
|
||||
Le résultat attendu d'ici la fin du TP, est un groupe de conteneurs
|
||||
indépendants les uns des autres, réutilisables en fonction des besoins.
|
||||
|
||||
TODO image de graphana
|
||||
|
||||
## 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.
|
||||
Nous reprendrons le script de monitoring que vous avez rendu au premier TP. Les
|
||||
données collectées seront envoyés vers [https://influxdb.com/](InfluxDB), puis
|
||||
elles seront affichées sous forme de graphique dans
|
||||
[http://grafana.org/](Grafana). L'interface sera servie par un reverse-proxy
|
||||
qui vous permettra de n'ouvrir que le port 80 ou 443, pour accéder à
|
||||
l'interface d'administration d'InfluxDB et à l'interface de Grafana.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue