virli/tutorial/dockerfiles/interactive.md
Pierre-Olivier Mercier 7cca585c0f Fix bad command
Thanks-To: <antoine.ducros@epita.fr>
2022-10-13 17:19:41 +02:00

6.4 KiB

Modification interactive

Pour créer une image, commençons par entrer dans un nouveau conteneur :

```bash docker container run -it ubuntu /bin/bash ```

Nous voilà maintenant dans le conteneur ! Il est assez épuré, il n'y a rien de superflu : 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 inclus dans le conteneur.

```bash apt-get update ```

Il peut arriver que des paquets présents dans l'image ne soient pas à jour. De manière générale, il n'est pas recommandé de faire de mises à jour automatiques et systématiques des éléments présents dans l'image, à l'exception des mises à jour de sécurité1. En effet, une mise à jour qui apporte des changements peut altérer le comportement du conteneur, en fonction de la date à laquelle on le construit. Car on ne sait pas d'avance quelles versions de nos dépendances on va récupérer.

Si vous souhaitez disposer d'une nouvelle version de l'image, il est plutôt recommandé de contacter le mainteneur de l'image pour qu'il la mette à jour, en utilisant un nouveau tag s'il le juge nécessaire. Si cette solution n'est pas envisageable, alors il vaut mieux créer votre propre image, à partir de l'image de base : vous serez alors vous-même responsable de la bonne continuité de construction des images issues de votre image, sans que cela soit hasardeux au moment de la construction.\

La liste des paquets récupérés, installons maintenant un programme : notre première image pourrait contenir notre éditeur de texte favori :

```bash apt-get install nano ```

Lorsque l'installation de nano est terminée, quittons l'image en tapant exit.\

Nous allons sauvegarder nos modifications en tant que nouvelle image Docker, avec la commande commit :

```bash 42sh$ docker container ls -a CONTAINER ID IMAGE COMMAND STATUS NAMES 91d17871d730 ubuntu "bash" Exited (0) musing_tu [...]

docker container commit 91d17871d730 my_nano

</div>

en remplaçant `91d17871d730` par le nom ou l'identifiant du container qui
doit servir de modèle. `my_nano` est le nom que vous voudrez utiliser
à la place d'`ubuntu`.

L'action de *commit*, malgré le fait qu'elle crée une nouvelle image est très
rapide : il se trouve que seules les différences avec l'image parente sont
packagées. Les images sont en fait composées de couches : empilant les
différences depuis le système de base !


### À propos des couches

Revenons quelque-peu en arrière : lorsque nous avons fait notre premier `docker
run hello-world`, rappelez-vous, Docker a téléchargé l'image en nous affichant
la progression, juste avant de lancer le conteneur.

Analysons ensemble ces quelques lignes pour mieux comprendre de quoi les images
se composent. Nous allons pour cela utiliser la commande `pull` pour récupérer
une nouvelle image :

<div lang="en-US">
```bash
42sh$ docker image pull python:3
3: Pulling from library/python
23858da423a6: Pull complete
326f452ade5c: Pull complete
a42821cd14fb: Pull complete
8471b75885ef: Pull complete
8ffa7aaef404: Pull complete
15132af73342: Pull complete
aaf3b07565c2: Pull complete
736f7bc16867: Pull complete
94da21e53a5b: Pull complete
Digest: sha256:e9c35537103a2801a30b15a77d4a56b35532c964489b125ec1ff24f3d5b53409
Status: Downloaded newer image for python:3
docker.io/library/python:3

On remarque que plusieurs téléchargement ont lieu, chacun associé à un identifiant particulier. Une image est généralement découpée en plusieurs éléments. On parle en fait de couches puisqu'on les empile, dans un ordre précis.

Les couches sont une astuce formidable pour optimiser tant le téléchargement, l'espace de stockage nécessaire au cache d'images, que la création des conteneurs. De nombreux conteneurs vont utiliser les mêmes images de base : debian, ubuntu, alpine, ... il serait futile de systématiquement récupérer et stocker autant de systèmes de fichiers de base que d'images. Avec les couches, si deux images partagent la même version du système de fichiers de base, il ne sera téléchargé qu'une seule fois. On pourait le schématiser ainsi :

L'héritage des principales images officielles

Dans les faits, cela va même encore plus loin car Docker crée de nombreuses couches intermédiaires, chacune peut être l'occasion d'une bifurcation.\

Chaque couche est en fait un différentiel des dossiers et fichiers qui sont ajoutés, modifiés ou supprimés par rapport à la couche précédente.

::::: {.question}

Comment supprimer les couches d'images que je n'utilise plus ? {-}

Docker gère lui-même les couches, vous n'avez pas à vous en préoccuper. Si une image est mise à jour ou supprimée, toutes les couches rendues inutiles seront automatiquement supprimées.

:::::

Revenons au commit que nous avons fait précédemment. Nous avons ajouté nano par-dessus une image ubuntu. Naturellement, voici ce qu'il s'est passé :

docker commit

Testons alors sans plus attendre notre nouvelle image :

```bash docker container run -it my_nano /bin/bash ```

Vous constatez cette fois que vous pouvez lancer nano !

Nous avons donc créé une couche, elle contient juste le différentiel des fichiers ajoutés, à savoir le binaire nano et sa configuration par défaut (mais aussi le cache du gestionnaire de paquets apt).

Voyons maintenant comment automatiser cela.

Scripté ?

On peut automatiser les étapes ci-dessus avec un script qui ressemblerait à ça :

```bash docker container run ubuntu apt-get update docker container commit $(docker container ls -lq) my_nano_step-1 docker container run my_nano_step-1 apt-get install nano docker container commit $(docker container ls -lq) my_nano ```

On obtiendra de la même manière notre image my_nano :

```bash docker container run -it my_nano /bin/bash ```

contenant notre éditeur de texte favori.\

On ne va pas réaliser ce script ni l'étoffer, car il existe justement un mécanisme de construction d'image : le Dockerfile.