virli/tutorial/docker-basis/first.md

324 lines
10 KiB
Markdown
Raw Normal View History

2016-09-08 01:44:20 +00:00
Mon premier conteneur
---------------------
2016-09-08 01:44:20 +00:00
2017-10-04 23:42:56 +00:00
Afin de tester la bonne marche de notre installation, lançons notre premier
2022-02-24 19:43:43 +00:00
conteneur avec la commande:
2016-09-08 01:44:20 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
docker container run hello-world
2016-09-08 01:44:20 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2016-09-08 01:44:20 +00:00
2019-10-01 09:03:15 +00:00
Cette commande va automatiquement exécuter une série d'actions pour nous,
2022-02-24 19:43:43 +00:00
comme indiqué dans le message affiché en retour:
2016-09-08 01:44:20 +00:00
D'abord, le daemon va rechercher s'il possède localement l'image
2019-10-01 09:03:15 +00:00
*hello-world*. Si ce n'est pas le cas, il va aller récupérer les différentes
couches de l'image sur le registre par défaut (celui de Docker). Il assemble
ensuite les images en ajoutant une couche en lecture/écriture, propre au
conteneur. Enfin, il lance la commande par défaut, telle que définie dans les
métadonnées de l'image.
2016-09-08 01:44:20 +00:00
Nous pouvons directement utiliser le client pour rechercher une image sur le
2022-02-24 19:43:43 +00:00
registre, en utilisant la commande `search`:
2016-09-08 01:44:20 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
docker search mariadb
2016-09-08 01:44:20 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2016-09-08 01:44:20 +00:00
2019-10-01 09:03:15 +00:00
Il est possible de mettre à jour les images locales, ou télécharger les couches
2022-02-24 19:43:43 +00:00
d'images qui nous intéressent, en utilisant la commande `pull`:
2016-09-08 01:44:20 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
docker image pull ubuntu
2016-09-08 01:44:20 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2016-09-08 01:44:20 +00:00
2019-10-01 09:03:15 +00:00
2022-02-24 19:43:43 +00:00
::::: {.warning}
Les registres publics tels quel le Docker Hub mettent à disposition des images
2022-02-24 19:43:43 +00:00
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éée: 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 couverts 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
2022-02-24 19:43:43 +00:00
peuvent contenir du code malveillant.
2022-02-24 19:43:43 +00:00
**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
2019-10-01 09:03:15 +00:00
2022-02-24 19:43:43 +00:00
Remarquez comment on interagit avec chaque *objet Docker*: dans la ligne de
2017-10-04 23:42:56 +00:00
commande, le premier mot clef est le type d'objet (`container`, `image`,
`service`, `network`, `volume`, ...) ; ensuite, vient l'action que l'on
2017-10-04 23:42:56 +00:00
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
2022-02-24 19:43:43 +00:00
l'ancienne syntaxe, sans le type d'objets: `docker images` au lieu de
`docker image ls`, `docker run` au lieu de `docker container run`, ...
2017-10-04 23:42:56 +00:00
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
2022-02-24 19:43:43 +00:00
nous-même), on utilise la commande `ls` sous le type d'objets `image`:
2016-09-08 01:44:20 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
docker image ls
2016-09-08 01:44:20 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2016-09-08 01:44:20 +00:00
2019-10-01 09:03:15 +00:00
### *Image ID*, nom, tag
2019-10-01 09:03:15 +00:00
2022-02-24 19:43:43 +00:00
Chaque image est identifiable par son *Image ID*: il s'agit d'un long
2021-09-16 01:45:54 +00:00
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.
2022-02-24 19:43:43 +00:00
Pour s'y retrouver, on utilise habituellement les noms des images:
2021-09-16 01:45:54 +00:00
`hello-world` est ainsi le nom de l'image
`1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792`.
2022-02-24 19:43:43 +00:00
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>
2021-09-16 01:45:54 +00:00
Par convention, lorsque l'on souhaite désigner un tag en particulier,
2022-02-24 19:43:43 +00:00
on utilise la syntaxe suivante:
2021-09-16 01:45:54 +00:00
<div lang="en-US">
```
ubuntu:focal
```
</div>
2022-02-24 19:43:43 +00:00
Par exemple, pour lancer un conteneur Ubuntu Focal, on utilisera:
2021-09-16 01:45:54 +00:00
<div lang="en-US">
```
docker container run ubuntu:focal
```
</div>
2016-09-08 01:44:20 +00:00
2022-02-24 19:43:43 +00:00
Chaque nom d'image possède au moins un tag associé par défaut: *latest*. C'est
2017-10-16 20:59:22 +00:00
le tag qui est automatiquement recherché lorsque l'on ne le précise pas en
2017-10-04 23:42:56 +00:00
lançant l'image.
2016-09-08 01:44:20 +00:00
### Exécuter un programme dans un conteneur
2016-09-08 01:44:20 +00:00
Maintenant que nous avons à notre disposition l'image d'un conteneur Ubuntu,
2022-02-24 19:43:43 +00:00
nous allons pouvoir jouer avec!
2016-09-08 01:44:20 +00:00
La commande `run` de Docker prend comme derniers arguments le programme à
lancer dans le conteneur ainsi que ses éventuels arguments. Essayons d'afficher
2022-02-24 19:43:43 +00:00
un Hello World:
2016-09-08 01:44:20 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
docker container run ubuntu /bin/echo "Hello World"
2016-09-08 01:44:20 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2016-09-08 01:44:20 +00:00
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.
2017-10-04 07:00:58 +00:00
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
2019-10-16 01:54:56 +00:00
n'utilisez pas [Alpine Linux](https://www.alpinelinux.org), vous pourriez
2022-02-24 19:43:43 +00:00
tenter d'utiliser son gestionnaire de paquet `apk`, via:
2016-09-08 01:44:20 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
docker container run alpine /sbin/apk stats
2017-10-04 07:00:58 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2017-10-04 07:00:58 +00:00
### Images vs. conteneurs
2017-10-04 07:00:58 +00:00
À chaque fois que nous lançons un `run`, un nouveau conteneur est créé.
L'image fournie comme argument est utilisée comme un modèle de base pour le
2017-10-08 22:08:33 +00:00
conteneur et est recopiée grâce à un mécanisme de *Copy-On-Write*: c'est donc
2017-10-04 07:00:58 +00:00
très rapide et ne consomme pas beaucoup d'espace disque.
Étant donné que chaque conteneur est créé à partir d'un modèle, cela signifie
que lorsque nous exécutons une commande modifiant les fichiers d'un conteneur,
2019-10-01 09:03:15 +00:00
cela ne modifie pas l'image de base. La modification reste contenue dans la
couche propre au conteneur dans l'UnionFS.
2016-09-08 01:44:20 +00:00
2021-09-16 01:45:54 +00:00
Dans le schéma ci-après, on considère les images comme étant la partie figée de
Docker à partir desquelles on peut créer des conteneurs.
2017-10-04 07:00:58 +00:00
Si l'on souhaite qu'une modification faite dans un conteneur (par exemple
l'installation d'un paquet) s'applique à d'autres conteneurs, il va falloir
créer une nouvelle image à partir de ce conteneur.
2021-09-23 00:55:18 +00:00
![Images vs. conteneurs](img-vs-cntr.png "Images vs. conteneurs"){ width=85% }
2017-10-04 07:00:58 +00:00
### Programme par défaut
2017-10-04 07:00:58 +00:00
2020-09-21 21:48:16 +00:00
Chaque image vient avec un certain nombre de métadonnées, notamment le
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
2022-02-24 19:43:43 +00:00
lorsque vous avez lancé l'image `hello-world`:
2017-10-04 07:00:58 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
2020-09-21 21:48:16 +00:00
docker container run hello-world
2017-10-04 07:00:58 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2017-10-04 07:00:58 +00:00
2020-09-21 21:48:16 +00:00
Il est commun que le programme le plus attendu/approprié soit lancé par défaut,
2022-02-24 19:43:43 +00:00
il est donc tout naturel que pour l'image `hello-world`, ce soit `/hello`:
2017-10-04 07:00:58 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
```bash
2020-09-21 21:48:16 +00:00
docker container run hello-world /hello
2017-10-04 07:00:58 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2017-10-04 07:00:58 +00:00
2022-02-24 19:43:43 +00:00
L'image ne contenant que ce programme, vous ne pourrez pas y lancer de shell:
2017-10-04 07:00:58 +00:00
2020-09-21 21:48:16 +00:00
<div lang="en-US">
2022-02-24 19:43:43 +00:00
```
2020-09-21 21:48:16 +00:00
42sh$ docker container run hello-world /bin/sh
2022-02-24 19:43:43 +00:00
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"
2020-09-21 21:48:16 +00:00
```
</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
2022-02-24 19:43:43 +00:00
subtilité: il faut ajouter les options `--interactive` et `--tty` pour ne pas
que `docker` nous rende la main tout de suite:
2020-09-21 21:48:16 +00:00
<div lang="en-US">
```bash
42sh$ docker container run alpine
42sh$ echo $?
0
```
</div>
<div lang="en-US">
```bash
42sh$ docker container run --interactive --tty alpine
/ # _
```
</div>
En fait, comme on a vu que le programme `docker` n'est qu'un client du daemon,
c'est toujours le daemon qui exécute directement les commandes et gère les
entrées et sorties standards et d'erreur. Avec l'option `--interactive`, on
s'assure que l'entrée standard ne sera pas fermée (`close(2)`). Nous demandons
également l'allocation d'un TTY, sans quoi `bash` ne se lancera pas en mode
interractif[^bashnointer].
2017-10-04 07:00:58 +00:00
[^bashnointer]: Mais il sera possible de l'utiliser sans allouer de TTY, comme
2022-02-24 19:43:43 +00:00
dans cet exemple:
2017-10-04 07:00:58 +00:00
2017-10-17 06:29:07 +00:00
<div lang="en-US">
2017-10-04 07:00:58 +00:00
```
42sh$ cat cmd
echo foo
42sh$ cat cmd | docker run -i busybox
foo
2017-10-04 07:00:58 +00:00
```
2017-10-17 06:29:07 +00:00
</div>
2017-10-04 07:00:58 +00:00
L'option `-i` reste néanmoins nécessaire pour que l'entrée standard soit
transmise au conteneur.
2017-10-16 20:59:22 +00:00
2022-02-24 19:43:43 +00:00
Rassurez-vous, on peut les abréger en `-i` et `-t`:
2020-09-21 21:48:16 +00:00
<div lang="en-US">
```bash
42sh$ docker container run -it alpine
/ # _
```
</div>
### Les paramètres
2020-09-21 21:48:16 +00:00
2022-02-24 19:43:43 +00:00
Vous avez remarqué le placement des options `--tty` et `--interactive`? Avant
2020-09-21 21:48:16 +00:00
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
2022-02-24 19:43:43 +00:00
commande peut prendre des paramètres:
2020-09-21 21:48:16 +00:00
<div lang="en-US">
```bash
2022-04-08 13:28:11 +00:00
docker DOCKER_PARAMS container run RUN_OPTS image IMAGE_CMD IMAGE_ARGS …
2020-09-21 21:48:16 +00:00
```
</div>
2022-02-24 19:43:43 +00:00
Par exemple:
2020-09-21 21:48:16 +00:00
<div lang="en-US">
```bash
2022-05-04 09:18:16 +00:00
docker -H unix:///run/docker.sock container run -it alpine /bin/ash -c \
"echo foo"
2020-09-21 21:48:16 +00:00
```
</div>
Ici, l'option `-H` sera traitée par le client Docker (pour définir
l'emplacement du point de communication avec le daemon), tandis que les options
`-it` seront utilisées lors du traitement du `run`. Quant au `-c`, il sera
simplement transmis au conteneur comme argument au premier `execve(2)` du
conteneur.
2017-10-16 20:59:22 +00:00
### Lister les conteneurs
2017-10-16 20:59:22 +00:00
Avant de quitter notre conteneur, regardons, à l'aide d'un autre terminal,
2020-09-21 21:48:16 +00:00
l'état de notre conteneur. La commande suivante permet d'obtenir la liste des
2022-02-24 19:43:43 +00:00
conteneurs en cours d'exécution:
<div lang="en-US">
```
42sh$ docker container ls
2022-05-04 09:18:16 +00:00
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
4c39fc049cd1 ubuntu "/bin/bash" 6 minutes ago Up 5 minutes bold_gates
```
</div>
### Sortir d'un conteneur
Pour mettre fin à l'exécution d'un conteneur, il convient de terminer le
premier processus lancé dans celui-ci.
Si vous faites face à une invite de commande, le classique `exit` ou `^D`
mettra fin au *shell*, qui était le premier processus lancé de notre conteneur,
comme le montre la colonne `COMMAND`. Nous retrouvons juste après notre invite
habituelle, dans l'état où nous l'avions laissée avant de lancer notre
conteneur. En effet, le conteneur était alors le processus fils lancé par notre
shell.