Save tuto corrections

This commit is contained in:
nemunaire 2022-02-24 20:43:43 +01:00
commit 10448a6c8d
115 changed files with 1423 additions and 1289 deletions

View file

@ -1,6 +1,6 @@
include ../pandoc-opts.mk
SOURCES = tutorial.md installation.md what.md first.md cleaning.md ex-flask.md volumes.md linking.md
SOURCES = tutorial.md installation.md what.md first.md cleaning.md ex-flask.md volumes.md linking.md linking-ex-fic.md linking-ex-help.md
all: tutorial.pdf

View file

@ -17,19 +17,19 @@ l'option `--rm`.
### Conteneurs
Nous pouvons afficher l'ensemble des conteneurs, quel que soit leur état (en
cours d'exécution, arrêtés,\ ...) avec la commande suivante :
cours d'exécution, arrêtés, ...) avec la commande suivante:
<div lang="en-US">
```
42sh$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
552d71619723 hello-world "/hello" 4 days ago Exited (0) 4 days ago dreamy_gates
0e8bbff6d500 debian "/bin/bash" 2 weeks ago Exited (0) 2 weeks ago cranky_jones
552d71619723 hello-world "/hello" 4 days ago Exited (0) 4 days ago dreamy_g
0e8bbff6d500 debian "/bin/bash" 2 weeks ago Exited (0) 2 weeks ago cranky_j
```
</div>
Il y a de fortes chances pour que vous n'ayez plus besoin de ces vieux
conteneurs. Pour les supprimer, utilisez la commande :
conteneurs. Pour les supprimer, utilisez la commande:
<div lang="en-US">
```bash
@ -37,7 +37,7 @@ docker container rm 0e8bbff6d500 552d71619723
```
</div>
ou encore :
ou encore:
<div lang="en-US">
```bash
@ -57,7 +57,7 @@ de la même manière que les conteneurs, avec les sous-commandes `docker image`.
### `prune`
Dans la plupart des menus permettant de gérer les objets Docker, vous trouverez
une commande `prune` qui supprimera les objets inutilisés :
une commande `prune` qui supprimera les objets inutilisés:
<div lang="en-US">
```bash
@ -65,7 +65,7 @@ docker container prune
```
</div>
On aura tendance à vouloir supprimer tous les objets inutiles d'un seul coup, via :
On aura tendance à vouloir supprimer tous les objets inutiles d'un seul coup, via:
<div lang="en-US">
```bash

View file

@ -2,3 +2,15 @@
Découvrons Docker
=================
Entrons sans plus attendre dans le vif du sujet: Docker.
Ce projet, dont les sources ont été rendues libres en 2013, a tout de
suite remporté un engouement indéniable. Le projet a énormément grossi
depuis, et il s'est aussi bien stabilisé. Aujourd'hui de nombreuses
entreprises n'hésitent plus à l'utiliser en production.
Dans ce chapitre, nous allons partir à la découverte de cet outil:
après l'avoir installé, nous apprendrons d'abord les concepts clefs puis
nous lancerons notre premier conteneur et nous irons jusqu'à déployer
un premier service web avec lequel nous pourrons interagir.

View file

@ -3,13 +3,13 @@
Mon premier webservice
----------------------
C'est parti, nous allons déployer notre premier service !
C'est parti, nous allons déployer notre premier service!
Il s'agit d'un service montrant une image aléatoire à chaque chargement de
page : <https://you.p0m.fr/>.
page: <https://you.p0m.fr/>.
Nous pouvons télécharger et lancer le service grâce à :
Nous pouvons télécharger et lancer le service grâce à:
<div lang="en-US">
```bash
@ -17,22 +17,22 @@ docker container run -i nemunaire/youp0m
```
</div>
Cette fois-ci, ce n'est pas un shell que nous obtenons[^defaultcmd] : il semblerait que le
service soit lancé et écoute sur le port 8080. Est-ce le cas ?
Cette fois-ci, ce n'est pas un shell que nous obtenons[^defaultcmd]: il semblerait que le
service soit lancé et écoute sur le port 8080. Est-ce le cas?
<http://localhost:8080>
[^defaultcmd]: Chaque conteneur dispose d'une commande par défaut : les images
[^defaultcmd]: Chaque conteneur dispose d'une commande par défaut: les images
de base telles que les distributions vont lancer un shell, tandis que les
conteneurs de service vont lancer leur service directement.
Non ! Car le service est contenerisé ! Il s'exécute dans son coin, sans
Non! Car le service est contenerisé! Il s'exécute dans son coin, sans
interférer avec son hôte.
### Redirection de ports
Nous pouvons rediriger le port avec l'argument <span lang="en-US">`-p dst_host:src_cntr`</span> :
Nous pouvons rediriger le port avec l'argument <span lang="en-US">`-p dst_host:src_cntr`</span>:
<div lang="en-US">
```bash
@ -43,7 +43,7 @@ docker container run -i -p 8080:8080 nemunaire/youp0m
Cette fois, nous pouvons accéder au service.
Pour le moment, le service ne dispose d'aucune image à afficher, vous pouvez
utiliser cette syntaxe pour ajouter une image :
utiliser cette syntaxe pour ajouter une image:
<div lang="en-US">
```bash
@ -51,7 +51,7 @@ base64 monimage.jpg | curl --data @- http://localhost:8080/api/images/monimage
```
</div>
Si vous n'êtes pas particulièrement inspiré, vous pouvez ajouter ces images :
Si vous n'êtes pas particulièrement inspiré, vous pouvez ajouter ces images:
<div lang="en-US">
```bash
@ -63,13 +63,13 @@ done
</div>
### Prêt pour la production ?
### Prêt pour la production?
Avec l'option `-i`, nous pouvons encore transmettre les signaux de terminaison
au conteneur. C'est pratique lorsque l'on développe, mais en production, notre
service ne s'exécutera pas dans notre terminal !
service ne s'exécutera pas dans notre terminal!
On utilise l'option `-d` pour lancer le conteneur en tâche de fond :
On utilise l'option `-d` pour lancer le conteneur en tâche de fond:
<div lang="en-US">
```bash
@ -79,7 +79,7 @@ docker container run -d -p 8080:8080 nemunaire/youp0m
À partir de l'identifiant renvoyé par cette commande (que l'on peut également
obtenir avec un `docker container ls`), nous pouvons consulter les logs du
service (en fait, les sorties standard et d'erreur) :
service (en fait, les sorties standard et d'erreur):
<div lang="en-US">
```bash
@ -88,15 +88,15 @@ docker container logs 0123456789abcdef
</div>
### Une autre instance ?
### Une autre instance?
Maintenant que nous avons un clone de <https://you.p0m.fr/>, nous voulons
absolument un clone de <https://food.p0m.fr/> !
absolument un clone de <https://food.p0m.fr/>!
Il s'agit du même service, mais ce ne sont pas les mêmes images.
On ne peut pas utiliser le même port sur la machine hôte, mais pour le reste,
il s'agit des mêmes options\ :
il s'agit des mêmes options\:
<div lang="en-US">
```bash
@ -104,10 +104,10 @@ docker container run -d -p 8081:8080 nemunaire/youp0m
```
</div>
Voyons le résultat : <http://localhost:8081>
Voyons le résultat: <http://localhost:8081>
Nous avons réussi à lancer deux conteneurs à partir de la même image, et on
voit bien que ceux-ci ne partagent pas leur système de fichiers : notre
voit bien que ceux-ci ne partagent pas leur système de fichiers: notre
nouvelle instance est encore immaculée.
@ -123,18 +123,19 @@ Outre les arguments que l'on peut passer au premier processus du conteneur, la
plupart des images peuvent adapter leur comportement en fonction de variables
d'environnement que l'on passe en paramètre.
Cette bonne pratique est recommandée par <https://12factor.net/>, qui détaille
les raisons qui devraient pousser les développeurs à privilégier les variables
d'environnements aux arguments sur la ligne de commande.
Cette bonne pratique est recommandée par
[`12factor.net`](https://12factor.net/), qui détaille les raisons qui devraient
pousser les développeurs à privilégier les variables d'environnements aux
arguments sur la ligne de commande.
Il se trouve que les conteneurs `youp0m` peuvent créer le fichier `htpasswd`,
s'ils sont démarrés avec les variables d'environnement :
s'ils sont démarrés avec les variables d'environnement:
- `YOUP0M_USERNAME` : nom d'utilisateur pour l'administrateur (par défaut admin) ;
- `YOUP0M_PASSWORD` : mot de passe de l'utilisateur.
- `YOUP0M_USERNAME`: nom d'utilisateur pour l'administrateur (par défaut admin) ;
- `YOUP0M_PASSWORD`: mot de passe de l'utilisateur.
Pour ajouter une variable d'environnement, cela se passe dans la commande
`run`, en ajoutant une ou plusieurs options `-e` :
`run`, en ajoutant une ou plusieurs options `-e`:
<div lang="en-US">
```bash
@ -143,13 +144,14 @@ docker container run -e YOUP0M_PASSWORD=foobar -p 8080:8080 nemunaire/youp0m
</div>
Une fois lancé, ce conteneur exposera une interface d'administration à cette
adresse : <http://localhost:8080/admin/>.
adresse:\
<http://localhost:8080/admin/>.
### Arrêt des conteneurs et persistance des données
Lorsque l'on souhaite stopper un conteneur lancé en tâche de fond, on utilise
son identifiant dans la commande suivante :
son identifiant dans la commande suivante:
<div lang="en-US">
```bash

View file

@ -1,7 +1,5 @@
\newpage
Exercice
========
Exercice {-}
--------
Pour mettre en pratiques toutes les notions que l'on a vu jusque là, écrivez un
script `mycloud-run.sh` pour automatiser le lancement de votre instance
@ -16,25 +14,26 @@ pour se rendre sur la page de connexion. Une autre machine de votre réseau
local devrait également pouvoir accéder à la plate-forme, simplement en
renseignant l'IP de votre machine et en ajoutant éventuellement des règles de
pare-feu (mais cette dernière partie n'est pas demandée, gardez simplement en
tête que cela doit pouvoir être fait manuellement au cas par cas : sur une
tête que cela doit pouvoir être fait manuellement au cas par cas: sur une
machine sans pare-feu configurée, cela ne demande pas d'étape supplémentaire).
Votre script devra se limiter aux notions vues durant cette partie du TP
(ie. sans utiliser `docker-compose` ou `docker stack` que l'on verra dans la
seconde partie). Il pourra cependant faire usage des commandes `docker OBJECT
inspect` pour ne pas avoir à faire d'analyse syntaxique sur les retours des
commandes lisibles par les humains.
(ie. sans utiliser `docker-compose` ou `docker stack` que l'on verra par la
suite). Il pourra cependant faire usage des commandes `docker OBJECT inspect`
pour ne pas avoir à faire d'analyse syntaxique sur les retours des commandes
lisibles par les humains.
Cette instance devra utiliser une base de données MySQL (lancée par vos soins
dans un autre conteneur) et contenir ses données dans un ou plusieurs volumes
(afin qu'elles persistent à une mise à jour des conteneurs par exemple).
Cette instance devra utiliser une base de données MySQL (lancée par votre
script dans un autre conteneur) et contenir ses données dans un ou plusieurs
volumes (afin qu'elles persistent à une mise à jour des conteneurs par
exemple).
L'exécution doit être la plus sécurisée possible (pas de port MySQL exposé sur
l'hôte par exemple, etc.) et la plus respectueuse des bonnes pratiques que l'on
a pu voir durant ce premier cours.
a pu voir jusque là.
### Exemple d'exécution
### Exemple d'exécution {-}
<div lang="en-US">
```bash

View file

@ -4,7 +4,7 @@ Mon premier conteneur
---------------------
Afin de tester la bonne marche de notre installation, lançons notre premier
conteneur avec la commande\ :
conteneur avec la commande:
<div lang="en-US">
```bash
@ -13,7 +13,7 @@ docker container run hello-world
</div>
Cette commande va automatiquement exécuter une série d'actions pour nous,
comme indiqué dans le message affiché en retour :
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 récupérer les différentes
@ -23,7 +23,7 @@ conteneur. Enfin, il lance la commande par défaut, telle que définie dans les
métadonnées de l'image.
Nous pouvons directement utiliser le client pour rechercher une image sur le
registre, en utilisant la commande `search` :
registre, en utilisant la commande `search`:
<div lang="en-US">
```bash
@ -32,7 +32,7 @@ docker search mariadb
</div>
Il est possible de mettre à jour les images locales, ou télécharger les couches
d'images qui nous intéressent, en utilisant la commande `pull` :
d'images qui nous intéressent, en utilisant la commande `pull`:
<div lang="en-US">
```bash
@ -41,40 +41,42 @@ docker image pull ubuntu
</div>
#### Attention {-}
::::: {.warning}
Les registres publics tels quel le Docker Hub mettent à disposition des images
officielles, mais aussi des images créés par la communauté. Chaque utilisateur
est libre d'envoyer une image qu'il a lui-même créée : soit car l'éditeur ne
officielles, mais aussi des images créées par la communauté. Chaque utilisateur
est libre d'envoyer une image qu'il a lui-même créé: soit car l'éditeur ne
proposait pas d'image et que quelqu'un s'est dévoué pour la faire, soit parce
qu'il avait des besoins plus spécifiques qui n'étaient pas couvert par l'image
originale. Il est important de garder en tête que vous téléchargez des
exécutables, et bien qu'ils s'exécutent dans un environnement isolé, ils
peuvent contenir du code malveillant. **De la même manière que vous devez être
attentif aux binaires que vous exécutez sur votre machine et au contexte de
leurs téléchargements, ici assurez-vous d'avoir confiance dans la personne
affiliée à l'image.**
peuvent contenir du code malveillant.
**De la même manière que vous devez être attentif aux binaires que vous
exécutez sur votre machine et au contexte de leurs téléchargements, ici
assurez-vous d'avoir confiance dans la personne affiliée à l'image.**
:::::
### Arguments de la ligne de commande
Remarquez comment on interagit avec chaque *objet Docker* : dans la ligne de
Remarquez comment on interagit avec chaque *objet Docker*: dans la ligne de
commande, le premier mot clef est le type d'objet (`container`, `image`,
`service`, `network`, `volume`, ...) ; ensuite, vient l'action que l'on
`service`, `network`, `volume`, ...) ; ensuite, vient l'action que l'on
souhaite faire dans ce cadre.[^oldcall]
[^oldcall]: cela n'a pas toujours été aussi simple, cette syntaxe n'existe que
depuis la version 1.13 (janvier 2017). C'est pourquoi, lorsque vous ferez
des recherches sur internet, vous trouverez de nombreux articles utilisant
l'ancienne syntaxe, sans le type d'objets : `docker images` au lieu de
`docker image ls`, `docker run` au lieu de `docker container run`, ...
l'ancienne syntaxe, sans le type d'objets: `docker images` au lieu de
`docker image ls`, `docker run` au lieu de `docker container run`, ...
L'ancienne syntaxe est dépréciée, mais il reste actuellement possible de
l'utiliser.
Par exemple, 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 `ls` sous le type d'objets `image` :
nous-même), on utilise la commande `ls` sous le type d'objets `image`:
<div lang="en-US">
```bash
@ -85,24 +87,26 @@ docker image ls
### *Image ID*, nom, tag
Chaque image est identifiable par son *Image ID* : il s'agit d'un long
Chaque image est identifiable par son *Image ID*: il s'agit d'un long
identifiant unique. Chaque modification qui est apportée à l'image
générera un *Image ID* différent. Un peu comme un identifiant de
commit dans Git.
Pour s'y retrouver, on utilise habituellement les noms des images :
Pour s'y retrouver, on utilise habituellement les noms des images:
`hello-world` est ainsi le nom de l'image
`1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792`.
Lorsque, comme dans le cas d'Ubuntu, il y a plusieurs *versions*
disponibles, il est possible de préciser la version au moyen d'un
*tag*. En consultant [la
documentation](https://hub.docker.com/_/ubuntu) qui accompagne chaque
conteneur, nous pouvons constater la présence de plusieurs versions
d'Ubuntu : `trusty`, `xenial`, `focal` ou `bionic`.
Lorsque, comme dans le cas d'Ubuntu, il y a plusieurs *versions* disponibles,
il est possible de préciser la version au moyen d'un *tag*. En consultant la
documentation[^hubDocUbuntu] qui accompagne chaque conteneur, nous pouvons
constater la présence de plusieurs versions d'Ubuntu: `trusty`, `xenial`,
`focal` ou `bionic`.
[^hubDocUbuntu]: Pour voir la documentation des images d'Ubuntu, consultez
<https://hub.docker.com/_/ubuntu>
Par convention, lorsque l'on souhaite désigner un tag en particulier,
on utilise la syntaxe suivante :
on utilise la syntaxe suivante:
<div lang="en-US">
```
@ -110,7 +114,7 @@ ubuntu:focal
```
</div>
Par exemple, pour lancer un conteneur Ubuntu Focal, on utilisera :
Par exemple, pour lancer un conteneur Ubuntu Focal, on utilisera:
<div lang="en-US">
```
@ -119,7 +123,7 @@ docker container run ubuntu:focal
</div>
Chaque nom d'image possède au moins un tag associé par défaut : *latest*. C'est
Chaque nom d'image possède au moins un tag associé par défaut: *latest*. C'est
le tag qui est automatiquement recherché lorsque l'on ne le précise pas en
lançant l'image.
@ -127,11 +131,11 @@ lançant l'image.
### Exécuter un programme dans un conteneur
Maintenant que nous avons à notre disposition l'image d'un conteneur Ubuntu,
nous allons pouvoir jouer avec !
nous allons pouvoir jouer avec!
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 :
un Hello World:
<div lang="en-US">
```bash
@ -146,7 +150,7 @@ transféré dans le conteneur.
Pour nous en convaincre, nous pouvons tenter d'exécuter un programme qui n'est
pas présent sur notre machine, mais bien uniquement dans le conteneur. Si vous
n'utilisez pas [Alpine Linux](https://www.alpinelinux.org), vous pourriez
tenter d'utiliser son gestionnaire de paquet `apk`, via :
tenter d'utiliser son gestionnaire de paquet `apk`, via:
<div lang="en-US">
```bash
@ -184,7 +188,7 @@ programme à exécuter par défaut si l'on ne le précise pas dans la ligne de
commande.
C'est grâce à cela que vous n'avez pas eu besoin de préciser de programme
lorsque vous avez lancé l'image `hello-world` :
lorsque vous avez lancé l'image `hello-world`:
<div lang="en-US">
```bash
@ -193,7 +197,7 @@ docker container run hello-world
</div>
Il est commun que le programme le plus attendu/approprié soit lancé par défaut,
il est donc tout naturel que pour l'image `hello-world`, ce soit `/hello` :
il est donc tout naturel que pour l'image `hello-world`, ce soit `/hello`:
<div lang="en-US">
```bash
@ -201,20 +205,21 @@ docker container run hello-world /hello
```
</div>
L'image ne contenant que ce programme, vous ne pourrez pas y lancer de shell :
L'image ne contenant que ce programme, vous ne pourrez pas y lancer de shell:
<div lang="en-US">
```bash
```
42sh$ docker container run hello-world /bin/sh
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349:
starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory": unknown.
docker: Error response from daemon: OCI runtime create failed:
container_linux.go:349: starting container process caused
"exec: \"/bin/sh\": stat /bin/sh: no such file or directory"
```
</div>
Pour les images `alpine` et `ubuntu`, le programme par défaut est un shell
(`/bin/ash` pour `alpine` et `/bin/bash` pour `ubuntu`), mais il y a une
subtilité : il faut ajouter les options `--interactive` et `--tty` pour ne pas
que `docker` nous rende la main tout de suite :
subtilité: il faut ajouter les options `--interactive` et `--tty` pour ne pas
que `docker` nous rende la main tout de suite:
<div lang="en-US">
```bash
@ -239,7 +244,7 @@ s'assure que l'entrée standard ne sera pas fermée (`close(2)`). Nous demandons
interractif[^bashnointer].
[^bashnointer]: Mais il sera possible de l'utiliser sans allouer de TTY, comme
dans cet exemple :
dans cet exemple:
<div lang="en-US">
```
@ -253,7 +258,7 @@ interractif[^bashnointer].
L'option `-i` reste néanmoins nécessaire pour que l'entrée standard soit
transmise au conteneur.
Rassurez-vous, on peut les abbréger en `-i` et `-t` :
Rassurez-vous, on peut les abréger en `-i` et `-t`:
<div lang="en-US">
```bash
@ -265,22 +270,22 @@ Rassurez-vous, on peut les abbréger en `-i` et `-t` :
### Les paramètres
Vous avez remarqué le placement des options `--tty` et `--interactive` ? Avant
Vous avez remarqué le placement des options `--tty` et `--interactive`? Avant
le nom de l'image, elles sont utilisées par Docker pour modifier le comportement
du `run`. En fait, tout comme `git(1)` et ses sous-commandes, chaque niveau de
commande peut prendre des paramètres :
commande peut prendre des paramètres:
<div lang="en-US">
```bash
docker DOCKER_PARAMS container run RUN_OPTS image IMAGE_CMD IMAGE_ARGS ...
docker DOCKER_PARAMS container run RUN_OPTS image IMAGE_CMD IMAGE_ARGS …
```
</div>
Par exemple :
Par exemple:
<div lang="en-US">
```bash
docker -H unix:///var/run/docker.sock container run -it alpine /bin/ash -c "echo foo"
docker -H unix:///run/docker.sock container run -it alpine /bin/ash -c "echo foo"
```
</div>
@ -295,13 +300,13 @@ conteneur.
Avant de quitter notre conteneur, regardons, à l'aide d'un autre terminal,
l'état de notre conteneur. La commande suivante permet d'obtenir la liste des
conteneurs en cours d'exécution :
conteneurs en cours d'exécution:
<div lang="en-US">
```
42sh$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c39fc049cd1 ubuntu "/bin/bash" 6 minutes ago Up 5 minutes suspicious_galileo
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c39fc049cd1 ubuntu "/bin/bash" 6 minutes ago Up 5 minutes bold_gates
```
</div>

View file

@ -1,24 +1,16 @@
\newpage
Installation
------------
Avant de voir de quoi il s'agit, afin de gagner du temps, nous allons commencer
par installer Docker.
### Prérequis
Docker repose sur plusieurs techniques implémentées dans les récents noyaux
Linux (et plus marginalement, Windows). Nous consacrerons les prochains cours à
comprendre leur fonctionnement. Ces techniques, contrairement aux instructions
de virtualisation qui rendent les hyperviseurs attractifs, ne sont pas limitées
à une architecture de microprocesseur spécifique ; cependant la communauté
autour de Docker utilise principalement l'architecture `amd64`, c'est sur cette
dernière que Docker pourra être exploité à son plein potentiel, suivi de près
par l'architecture `arm64`.
Docker repose sur plusieurs techniques implémentées dans les noyaux Linux
récents (et plus marginalement, Windows). Ces techniques, contrairement aux
instructions de virtualisation qui rendent les hyperviseurs attractifs, ne sont
pas limitées à une architecture de microprocesseur spécifique ; cependant la
communauté autour de Docker utilise principalement l'architecture `amd64`,
c'est sur cette dernière que Docker pourra être exploité à son plein potentiel,
suivi de près par l'architecture `arm64`.
Avant de continuer, assurez-vous que votre machine a bien démarré sur un noyau
64 bits. Le retour de la commande `uname -m` doit vous indiquer :
64 bits. Le retour de la commande `uname -m` doit vous indiquer:
<div lang="en-US">
```
@ -26,7 +18,7 @@ x86_64
```
</div>
Ou si vous êtes intrépide :
Ou si vous êtes intrépide:
<div lang="en-US">
```
@ -34,7 +26,7 @@ aarch64
```
</div>
Assurez-vous également d'avoir un noyau récent, avec la commande `uname -r` :
Assurez-vous également d'avoir un noyau récent, avec la commande `uname -r`:
<div lang="en-US">
```
@ -46,53 +38,66 @@ Rassurez-vous, même si vous n'avez pas compilé le dernier noyau disponible sur
[`kernel.org`](https://www.kernel.org/), Docker s'utilise à partir de Linux 3.10.
### Par le gestionnaire de paquets
### Sous Linux, par le gestionnaire de paquets
En général, votre distribution mettra à votre disposition une version de Docker
plus ou moins récente. Sous Debian et ses dérivés (Ubuntu, Mint, ...) le paquet
plus ou moins récente. Sous Debian et ses dérivés (Ubuntu, Mint, ...) le paquet
a été nommé [`docker.io`](https://packages.debian.org/sid/docker.io).
Si dans un environnement de production, on préférera sans doute utiliser une
version déjà bien éprouvée (comme celle des dépôts de sa distribution), pour ce
cours, nous allons avoir besoin de la **dernière version
version déjà bien éprouvée (comme celle des dépôts de sa distribution), pour
bien suivre les exemples, nous allons avoir besoin de la **dernière version
disponible**. Référez-vous à la documentation officielle correspondant à votre
distribution :
distribution:
<https://docs.docker.com/engine/install/debian/>
**Et Kali Linux alors ?** Kali étant basée sur Debian, référez-vous à
::::: {.question}
**Et Kali Linux alors?** Kali étant basée sur Debian, référez-vous à
la procédure d'installation de cette distribution.
:::::
### Windows et macOS
### Sous Windows et macOS
Bien que les fonctionnalités de contenerisation de Docker que nous utiliserons
ne soient disponibles que sous Linux, il est possible d'utiliser Docker de
manière déportée : le daemon Docker tournera dans une VM Linux, mais vous
pourrez interagir avec lui via votre ligne de commande habituelle.
manière déportée: le daemon Docker tournera dans une machine virtuelle Linux,
mais vous pourrez interagir avec lui via votre ligne de commande habituelle.
Téléchargez la version correspondante à votre système d'exploitation :
Téléchargez la version correspondant à votre système d'exploitation:
* [Docker Desktop for Mac](https://hub.docker.com/editions/community/docker-ce-desktop-mac)
* [Docker Desktop for Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows)
* Docker Desktop for Mac:\
<https://hub.docker.com/editions/community/docker-ce-desktop-mac>
Une fois l'installation terminée, lancez l'application : elle ajoutera une
* Docker Desktop for Windows:\
<https://hub.docker.com/editions/community/docker-ce-desktop-windows>
Une fois l'installation terminée, lancez l'application: elle ajoutera une
icône dans la zone de notification, vous permettant de contrôler l'exécution de
la machine virtuelle sous-jacente.
Notez que depuis septembre 2021, ces applications passent sous une licence
payante pour les grosses entreprises[^DockerSubscription]. Cela ne nous
concerne pas, car la licence est gratuite pour un usage éducatif ou
personnel. Notez que ce n'est pas le binaire Docker qui change de licence, elle
reste libre, mais seulement les applications Docker Desktop.
::::: {.warning}
Depuis septembre 2021, ces applications passent sous une licence payante pour
les grosses entreprises[^DockerSubscription]. Cela ne nous concerne pas, car la
licence est gratuite pour un usage éducatif ou personnel.
Notez que cela ne concerne pas le projet ou le binaire Docker: ceux-ci restent
libres. Seules les applications Docker Desktop sont concernées.
:::::
[^DockerSubscription]: <https://www.docker.com/blog/updating-product-subscriptions/>
### Évaluation en ligne
Si vous rencontrez des difficultés pour vous lancer, le projet
[Play With Docker](https://labs.play-with-docker.com/) vous donne accès à
un bac à sable dans lequel vous pourrez commencer à faire ce TP.
Si vous rencontrez des difficultés pour vous lancer, le projet Play With
Docker[^PlayWithDocker] vous donne accès à un bac à sable
dans lequel vous pourrez commencer à faire les exercices à suivre.
[^PlayWithDocker]: Play With Docker est accessible à cette addresse: <https://labs.play-with-docker.com/>
Il vous faudra disposer [d'un compte
Docker](https://hub.docker.com/signup). Une fois identifié, vous pourrez créer
@ -101,7 +106,7 @@ une nouvelle instance, et vous connecter dessus via SSH.
### 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:
<div lang="en-US">
```bash
@ -109,7 +114,7 @@ docker version
```
</div>
Une sortie similaire au bloc suivant devrait apparaître sur votre écran :
Une sortie similaire au bloc suivant devrait apparaître sur votre écran:
<div lang="en-US">
```
@ -149,8 +154,8 @@ Server:
#### `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 :
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:
<div lang="en-US">
```bash
@ -161,9 +166,9 @@ 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 **relancez votre
session** :
session**:
<div lang="en-US">
```bash
@ -171,5 +176,10 @@ sudo gpasswd -a $USER docker
```
</div>
**Attention :** cette action n'est pas anodine d'un point de vue sécurité :
::::: {.warning}
Cette action n'est pas anodine d'un point de vue de la sécurité:
<https://docs.docker.com/engine/security/#docker-daemon-attack-surface>
:::::

View file

@ -0,0 +1,44 @@
## Exercice {-}
À vous maintenant de connecter une instance de `nemunaire/fic-admin` à sa base
de données.
Ne vous embêtez pas avec les mots de passes des services, initialisez la base
de données avec le nom d'utilisateur et le mot de passe par défaut. Vous les
obtiendrez en lisant la documentation de l'image fic-admin:
<https://hub.docker.com/r/nemunaire/fic-admin/>
<div lang="en-US">
```bash
docker run --rm -e MYSQL_HOST=mysql_cntr_name nemunaire/fic-admin -help
```
</div>
Notez la définition de la variable d'environnement `MYSQL_HOST`, celle-ci
indique le nom du serveur vers lequel le service doit se connecter.
Vous aurez besoin de créer:
- un volume pour stocker la base de données,
- un réseau, dans lequel vous connecterez la base de données et le conteneur applicatif.
Une fois le service `fic-admin` lancé, vous pouvez exposer le port 8081, sur
lequel vous devriez voir l'interface d'admin: <http://localhost:8081/>.
Placez les différentes commandes (volumes, réseau, `run`, ...) dans un
script `ficadmin-run.sh`. Vous devriez pouvoir appeler ce script
plusieurs fois, sans que les données ne soient perdues, entre deux
arrêts.
### Exemple d'exécution
<div lang="en-US">
```bash
42sh$ ./ficadmin-run.sh
http://localhost:12345/
42sh$ #docker kill db ficadmin
42sh$ ./ficadmin-run.sh # le script relancera une base de données,
# sans avoir perdu les données
http://localhost:12345/
```
</div>

View file

@ -0,0 +1,34 @@
### Au secours, ça veut pas se connecter!
Lorsque nous lançons pour la première fois notre conteneur MySQL ou MariaDB, un
script est chargé d'initialisé le volume attaché à `/var/lib/mysql`. Les
démarrage suivant, ou si vous réutilisez un volume déjà initialisé avec une
base de données, le script ne refait pas d'initialisation. Même si les
variables d'environnement ont changées.
Si vous rencontrez des difficultés pour connecter votre conteneur à
`my-db`, prenez le temps de recréer un volume.
### Entrer dans un conteneur en cours d'exécution
Dans certaines circonstances, les journaux ne sont pas suffisants pour déboguer
correctement l'exécution d'un conteneur.
En réalisant l'exercice, vous serez sans doute confronté à des comportements
étranges, que vous ne pourriez comprendre qu'en ayant la main sur le conteneur,
via un shell.
Lorsqu'un conteneur est actif, vous pouvez y lancer un nouveau processus,
notamment un shell par exemple.
<div lang="en-US">
```bash
docker container exec -it mycloud /bin/bash
(inctnr)$ ping mysql_cntr_name
```
</div>
Notez qu'il n'est pas possible d'`exec` dans un conteneur éteint, et que si la
commande initiale du conteneur se termine, tous les `exec` seront instantanément
tués.

View file

@ -12,14 +12,14 @@ ses données, mais la plupart des applications réclament un serveur de base de
données.
Les bonnes pratiques nous dictent de ne pas placer plus d'un service par
conteneur : en effet, on peut vouloir mettre à jour l'applicatif sans pour
conteneur: en effet, on peut vouloir mettre à jour l'applicatif sans pour
autant redémarrer sa base de données, etc. Nous allons donc voir dans cette
partie comment lier deux conteneurs.
## Mise en place du webservice
Nous allons utiliser l'interface d'administration des serveurs du FIC :
Nous allons utiliser l'interface d'administration des serveurs du FIC:
[`nemunaire/fic-admin`](https://hub.docker.com/r/nemunaire/fic-admin).
En lançant le conteneur avec les mêmes options que `youp0m`, les journaux
@ -30,17 +30,17 @@ MariaDB](https://hub.docker.com/_/mariadb).
## Les pilotes réseau
Docker propose de base trois pilotes (*drivers*) pour « gérer » cela :
Docker propose de base trois pilotes (*drivers*) pour « gérer » cela:
- `none` : pour limiter les interfaces réseau du conteneur à l'interface de
- `none`: pour limiter les interfaces réseau du conteneur à l'interface de
loopback `lo` ;
- `host` : pour partager la pile réseau avec l'hôte ;
- `bridge` : pour créer une nouvelle pile réseau par conteneur et rejoindre un
- `host`: pour partager la pile réseau avec l'hôte ;
- `bridge`: pour créer une nouvelle pile réseau par conteneur et rejoindre un
pont réseau dédié.
Ces trois *drivers* sont instanciés de base dans Docker avec le même nom que
leur pilote. Pour consulter la liste de réseaux utilisables, lancez :
leur pilote. Pour consulter la liste de réseaux utilisables, lancez:
<div lang="en-US">
```
@ -52,7 +52,7 @@ d5d907add6e2 host host local
```
</div>
Par défaut, c'est le réseau `bridge` (de type `bridge`) qui est employé : ce
Par défaut, c'est le réseau `bridge` (de type `bridge`) qui est employé: ce
réseau utilise le pont `docker0` que vous pouvez voir dans vos interfaces
réseau via `ip link`. C'est via ce pont que les conteneurs peuvent avoir accès
à Internet, au travers d'une couche de NAT.
@ -76,7 +76,7 @@ Afin de contrôler quels échanges peuvent être réalisés entre les conteneurs
est recommandé de créer des réseaux utilisateur.
La création d'un réseau se fait tout simplement au travers des sous-commandes
relatives aux objets Docker `network` :
relatives aux objets Docker `network`:
<div lang="en-US">
```bash
@ -86,7 +86,7 @@ docker network create --driver bridge my_fic
C'est ensuite ce nom de réseau que vous passerez à l'option `--network` de vos
`run`, ou vous pouvez également faire rejoindre un conteneur déjà lancé à un
réseau :
réseau:
<div lang="en-US">
```bash
@ -97,84 +97,3 @@ docker network connect NETWORK CONTAINER
Lorsque plusieurs conteneurs ont rejoint un réseau utilisateur, ils peuvent
mutuellement se découvrir grâce à un système de résolution de nom basé sur leur
nom de conteneur.
## Exercice {-}
À vous maintenant de connecter une instance de `nemunaire/fic-admin` à sa base
de données.
Ne vous embêtez pas avec les mots de passes des services, initialisez la base
de données avec le nom d'utilisateur et le mot de passe par défaut. Vous les
obtiendrez en lisant la [documentation de l'image
fic-admin](https://hub.docker.com/r/nemunaire/fic-admin/) :
<div lang="en-US">
```bash
docker container run --rm -e MYSQL_HOST=mysql_cntr_name nemunaire/fic-admin -help
```
</div>
Notez la définition de la variable d'environnement `MYSQL_HOST`, celle-ci
indique le nom du serveur vers lequel le service doit se connecter.
Vous aurez besoin de créer un volume pour stocker la base de données, un réseau
dans lequel vous connecterez la base de données et le conteneur applicatif.
Une fois le service `fic-admin` lancé, vous pouvez exposer le port 8081, sur
lequel vous devriez voir l'interface d'admin : <http://localhost:8081/>.
Placez les différentes commandes (volumes, réseau, `run`, ...) dans un
script `ficadmin-run.sh`, que vous rendrez à la fin du TP. Vous
devriez pouvoir appeler ce script plusieurs fois, sans que les données
ne soient perdues, entre deux arrêts.
### Exemple d'exécution
<div lang="en-US">
```bash
42sh$ ./ficadmin-run.sh
http://localhost:12345/
42sh$ #docker kill db ficadmin
42sh$ ./ficadmin-run.sh # le script relancera une base de données,
# sans avoir perdu les données
http://localhost:12345/
```
</div>
### Au secours, ça veut pas se connecter !
Lorsque nous lançons pour la première fois notre conteneur MySQL ou MariaDB, un
script est chargé d'initialisé le volume attaché à `/var/lib/mysql`. Les
démarrage suivant, ou si vous réutilisez un volume déjà initialisé avec une
base de données, le script ne refait pas d'initialisation. Même si les
variables d'environnement ont changées.
Si vous rencontrez des difficultés pour connecter votre conteneur `fic-admin` à
`my-db`, prenez le temps de recréer un volume.
### Entrer dans un conteneur en cours d'exécution
Dans certaines circonstances, les journaux ne sont pas suffisants pour déboguer
correctement l'exécution d'un conteneur.
En réalisant l'exercice, vous serez sans doute confronté à des comportements
étranges, que vous ne pourriez comprendre qu'en ayant la main sur le conteneur,
via un shell.
Lorsqu'un conteneur est actif, vous pouvez y lancer un nouveau processus,
notamment un shell par exemple.
<div lang="en-US">
```bash
docker container exec -it ficadmin /bin/bash
(inctnr)$ ping mysql_cntr_name
```
</div>
Notez qu'il n'est pas possible d'`exec` dans un conteneur éteint, et que si la
commande initiale du conteneur se termine, tous les `exec` seront également
tués.

View file

@ -17,7 +17,7 @@ pour se rendre sur la page de connexion. Une autre machine de votre réseau
local devrait également pouvoir accéder à la plate-forme, simplement en
renseignant l'IP de votre machine et en ajoutant éventuellement des règles de
pare-feu (mais cette dernière partie n'est pas demandée, gardez simplement en
tête que cela doit pouvoir être fait manuellement au cas par cas : sur une
tête que cela doit pouvoir être fait manuellement au cas par cas: sur une
machine sans pare-feu configurée, cela ne demande pas d'étape supplémentaire).
Votre script devra se limiter aux notions vues durant ce TP (ie. sans utiliser
@ -67,7 +67,7 @@ Par ailleurs, n'oubliez pas de répondre à
## Tarball
Tous les fichiers identifiés comme étant à rendre pour ce TP sont à
placer dans une tarball (pas d'archive ZIP, RAR, ...).
placer dans une tarball (pas d'archive ZIP, RAR, ...).
Voici une arborescence type:
@ -80,7 +80,7 @@ login_x-TP1/mycloud-run.sh
## Signature du rendu
Deux méthodes sont utilisables pour signer votre rendu :
Deux méthodes sont utilisables pour signer votre rendu:
* signature du courriel ;
* signature de la tarball.
@ -106,7 +106,7 @@ signature.
#### No public key
Si vous recevez un rapport avec l'erreur suivante :
Si vous recevez un rapport avec l'erreur suivante:
<div lang="en-US">
```
@ -129,7 +129,7 @@ rendu.
#### Not explicit username
Si vous recevez un rapport avec l'erreur suivante :
Si vous recevez un rapport avec l'erreur suivante:
<div lang="en-US">
```
@ -144,7 +144,7 @@ données.
#### I've decided to skip your e-mail
Si vous recevez un rapport concluant ainsi :
Si vous recevez un rapport concluant ainsi:
<div lang="en-US">
```

View file

@ -3,7 +3,7 @@
Stockage de données applicatives
================================
Le concept principal de Docker est de concevoir des conteneurs applicatifs : on
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énéralement on ne va
lancer qu'une seule application par conteneur) et concevoir un service complet
en créant un groupe de conteneurs, partageant des données entre eux par des
@ -25,21 +25,21 @@ 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 :
serveur web:
<div lang="en-US">
```bash
docker container run --rm -p 80:80 -v ~/Downloads:/usr/share/nginx/html:ro -d nginx
docker run --rm -p 80:80 -v ~/Downloads:/usr/share/nginx/html:ro -d nginx
```
</div>
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 !
Downloads en renseignant l'IP de votre machine dans son navigateur favori!
Par défaut, `nginx` ne va pas permettre de lister le contenu du répertoire (et
va afficher une page 404, car il cherche un fichier `index.html` dans votre
répertoire). Vous pouvez par contre accéder à un fichier directement, par
exemple : <http://10.42.12.23/dQw4w9WgXcQ.mp4>
exemple: <http://10.42.12.23/dQw4w9WgXcQ.mp4>
## Les volumes
@ -50,7 +50,7 @@ soucier de leur réel emplacement.
Comme il s'agit d'un objet, la première chose à faire va être de créer notre
volume :
volume:
<div lang="en-US">
```bash
@ -59,7 +59,7 @@ docker volume create prod_foodp0m
```
</div>
Ensuite, nous pouvons démarrer un conteneur utilisant, par exemple :
Ensuite, nous pouvons démarrer un conteneur utilisant, par exemple:
<div lang="en-US">
```bash
@ -67,7 +67,7 @@ docker container run --mount source=prod_youp0m,target=/images nemunaire/youp0m
```
</div>
On pourra également faire de même avec un conteneur MySQL :
On pourra également faire de même avec un conteneur MySQL:
<div lang="en-US">
```bash
@ -86,7 +86,7 @@ Lorsque vous n'avez pas besoin de stocker les données et que vous ne désirez
pas qu'elles persistent (des données sensibles par exemple) ou si cela peut
améliorer les performances de votre conteneur, il est possible de créer des
points de montages utilisant le système de fichiers `tmpfs` et donc résidant
exclusivement en RAM\ :
exclusivement en RAM\:
<div lang="en-US">
```bash
@ -106,12 +106,15 @@ pour mettre à jour ou relancer un conteneur, sans perdre les données. Un autre
intérêt est de pouvoir partager des fichiers entre plusieurs conteneurs.
Il est ainsi parfaitement possible de lancer deux conteneurs qui partagent le
même volume :
même volume:
<div lang="en-US">
```bash
docker container run -d --mount source=prod_youp0m,target=/images -p 8080:8080 nemunaire/youp0m
docker container run -d --mount source=prod_youp0m,target=/images -p 8081:8080 nemunaire/youp0m
docker container run -d --mount source=prod_youp0m,target=/images \
-p 8080:8080 nemunaire/youp0m
docker container run -d --mount source=prod_youp0m,target=/images \
-p 8081:8080 nemunaire/youp0m
```
</div>
@ -119,7 +122,7 @@ Dans cet exemple, l'ajout d'une image dans un conteneur l'ajoutera également
dans le second.
Un exemple plus intéressant serait sur une architecture de micro-services
traitant des fichiers de grande taille : plutôt que de faire passer les
traitant des fichiers de grande taille: plutôt que de faire passer les
fichiers par un système de message/socket, on peut partager un volume pour
épargner les coûts de transferts inutiles, lorsqu'ils ne changent pas de
machine.

View file

@ -13,13 +13,13 @@ d'une socket.
Le client peut d'ailleurs ne pas être sur la même machine qui exécutera
effectivement les conteneurs.[^dockermachine]
C'est ce qu'il se passe lorsqu'on utilise *Docker4Windows* ou *Docker4Mac* :
C'est ce qu'il se passe lorsqu'on utilise *Docker4Windows* ou *Docker4Mac*:
une machine virtuelle Linux est lancée parallèlement au système de base et
chaque commande `docker` tapée est passée au deamon dans la machine virtuelle.
[^dockermachine]: Il suffit de modifier la variable d'environnement
`DOCKER_HOST` ou de passer le paramètre `-H` suivi de l'URL de la socket à
`docker`. Voir aussi : <https://docs.docker.com/machine/overview/>
`docker`. Voir aussi: <https://docs.docker.com/machine/overview/>
Commençons par planter le décor, en détaillant les principaux mécanismes de
Docker.
@ -30,17 +30,17 @@ Docker.
Une image Docker est un système de fichiers en lecture seule. Elle est formée
d'un ensemble de couches, agrégées selon le principe d'UnionFS.
Une image peut, par exemple, contenir :
Une image peut, par exemple, contenir:
* un système Ubuntu opérationnel,
* le programme `busybox`,
* un serveur web et votre application web, prêts à l'emploi,
* ...
*...
Les images sont utilisées comme **modèle** qui sera ensuite dupliqué à chaque
fois que l'on démarrera un nouveau conteneur.
Il y a deux méthodes pour obtenir des images Docker : soit les construire avec
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.
@ -50,8 +50,8 @@ 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 envoyer.
Le registre utilisé de base est le [Docker Hub](https://hub.docker.com/) : il
contient à la fois des images officielles (ubuntu, debian, nginx, ...), des
Le registre utilisé de base est le [Docker Hub](https://hub.docker.com/): il
contient à la fois des images officielles (ubuntu, debian, nginx, ...), des
images créées par des utilisateurs, mais aussi des images de grands éditeurs,
payantes, à destination des entreprises.
@ -65,10 +65,10 @@ proposent également.
### 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 : à
sont sa partie vivante. Chaque conteneur est créé à partir d'une image: à
chaque fois que nous lançons un conteneur, une couche lecture/écriture est
ajoutée au dessus de l'image. Cette couche est propre au conteneur et
temporaire : l'image n'est pas modifiée par l'exécution d'un conteneur.
temporaire: l'image n'est pas modifiée par l'exécution d'un conteneur.
![Couches d'un conteneur](layers-multi-container.png "Couches d'un conteneur"){ width=70% }