Introduction à Docker – Partie 3

Docker

Cette série de tutoriels vous illustrera comment utiliser Docker avec un ordinateur sous Linux. Cette partie est dédiée à la création d’un Dockerfile.

Le Dockerfile

Dans le tutoriel précédent, nous avions constaté qu’à chaque nouvelle création de conteneur, on perdait toutes les modifications que l’on aurait pu faire dans un conteneur issu de la même image, puisque l’image de base restait inchangée.

Pour faire des changements permantents à une image, l’idée est de créer une image customisée sur la base de l’image existante. C’est précisément le rôle du Dockerfile.

Le Dockerfile est un fichier texte contenant une série d’instructions permettant de construire une nouvelle image Docker. Grâce à lui, tous les conteneurs lancés à partir de l’image customisée inclueront déjà les modifications spécifiées dans le Dockerfile. Regardons plus en détail comment le rédiger.

Préparation des fichiers

L’exemple qui va suivre montre comment réaliser un Dockerfile pour une version antérieure d’Ubuntu, par exemple la version 20.04.

Vous pouvez vérifer la version de votre machine avec la commande cat /etc/os-release.

Exemple :

Terminal
mowibox@chroma:~$ cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.2 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu

On voit ici que la version d’Ubuntu est 24.04. Regardons comment faire pour créer une image basée sur la version 20.04.

Choissisez un emplacment et créez-y un dossier au nom de votre choix (manuellement ou via un terminal avec la commande mkdir <folder_name>). Dans cet exemple, je vais sobrement le nommer “docker_folder/”.

Dans ce dossier :

  • À la racine, créez un fichier nommé Dockerfile.
  • Créez un dossier et ajoutez-y à l’intérieur un fichier de votre choix, ça peut être un fichier texte, markdown, etc. Pour ma part je vais créer le dossier “my_folder/” et y intégrer le fichier Python my_python_file.py :
my_python_file.py
1# Un affichage simple
2print("Hello, World!")
3
4# Une addition simple (j'espère)
5a = 1
6b = 2
7c = a + b
8print(f"{a} + {b} = {c}")

L’arborescense de votre dossier devrait donc ressembler à celle-ci :

docker_folder/
├── Dockerfile
└── my_folder/
    └── my_python_file.py

Contenu du Dockerfile

Ouvrez le fichier Dockerfile dans un éditeur de texte ou un IDE comme Visual Studio Code.

Voilà le contenu que vous devez mettre au sein du fichier :

Dockerfile
 1FROM ubuntu:20.04
 2
 3# Mise à jour de Linux et installation d'outils de dev
 4RUN apt-get update && apt-get upgrade -y
 5RUN apt-get install -y git python3-pip nano
 6
 7# Nettoyage des fichiers temporaires
 8RUN rm -rf /var/lib/apt/lists/*
 9
10# Copie du dossier vers le conteneur
11COPY my_folder/ my_image_folder
12
13# Création d'un dossier de travail
14RUN mkdir -p /workspace

Regardons en détail les lignes du fichier pour bien comprendre ce qui s’y passe :

1FROM ubuntu:20.04
  • La commande FROM permet de spécifier à partir de quelle image de base notre image va être créée, ici, ce sera Ubuntu 20:04.
4RUN apt-get update && apt-get upgrade -y
  • RUN permet de lancer une commande, ici, on met à jour et installe les paquets disponibles d’Ubuntu.

Pourquoi utilise-t-on le flag ‘-y’ ?

Le flag -y permet de répondre automatiquement “yes” à toutes les confirmations demandées par la commande. Cela permet d’automatiser le processus sans intervention de votre part.

5RUN apt-get install -y git python3-pip nano
  • Ici, on installe des outils qui peuvent s’avérer utiles pour le développement:
    • git : Pour pouvoir utiliser GitHub/GitLab.
    • python3-pip : Pour installer des paquets Python.
    • nano pour l’édition de texte dans le terminal.
8RUN rm -rf /var/lib/apt/lists/*
  • Cette ligne permet de supprimer les fichiers temporaires d’APT, afin de réduire la taille de l’image finale Docker.
11COPY my_folder/ my_image_folder
  • La commande COPY vous permet de copier le contenu du dossier “my_folder/” de la machine hôte vers le conteneur, sous le nom “my_image_folder/”.

Attention

Si le dossier que vous avez créé précédemment ne s’appelle pas “my_folder”, n’oubliez pas de modifier la commande dans le Dockerfile pour la faire correspondre au vôtre !

14RUN mkdir -p /workspace
  • Cette ligne de commande va créer un dossier nommé “/workspace” à la racine de votre conteneur.

Construction de l’image

Maintenant que le Dockerfile est prêt, nous allons pouvoir procéder à la construction de l’image Docker.

Ouvrez un terminal à l’emplacement de votre Dockerfile, (par exemple dans le dossier “docker_folder/”) et exécutez la commande :

docker build -t <image_name> .

en remplaçant <image_name> par le nom que vous voulez donner à votre image. Le deuxième argument correspond au chemin pour accéder au Dockerfile, comme nous sommes déjà à l’emplacement du fichier, il suffit de mettre un . pour dire à Docker d’utiliser le répertoire actuel comme répertoire de construction.

Vous verrez ainsi toutes les couches de votre Dockerfile s’exécuter les unes après les autres :

Terminal
mowibox@chroma:~$ docker build -t my_custom_ubuntu .
[+] Building 8.1s (5/10)
 => [internal] load build definition from Dockerfile
 => transferring dockerfile: 355B
 => [internal] load metadata for docker.io/library/ubuntu:20.04
 => [internal] load .dockerignore
 => transferring context: 2B
 => [1/6] FROM docker.io/library/ubuntu:20.04@sha256:8feb4d8ca5354def3d8fce243717141ce31e2c428701f6682b
 => resolve docker.io/library/ubuntu:20.04
 => sha256:8feb4d8ca5354def3d8fce243717141ce31e2c428701f6682bd2bfae15388214 6.69kB / 6.69kB
 => sha256:c664f8f86ed5a386b0d9818f81714e21a8b9c73f568c4bea56aa179d54a 424B / 424B
 => sha256:b7ba04fd9aa0c77fc0cc7bf993fd6946545983d9096126e5a4f45d713 2.30kB / 2.30kB
 => sha256:13b7e930469f6d3575a320709035c6ac6fcf5485a76abcf03d1b92a64c09c2476 27.51MB / 27.51MB
 => extracting sha256:13b7e930469f6d3575a320709035c6ac6fcf5485a76abcf03d1b92a64c09c2476
 => [internal] load build context
 => transferring context: 77B
 => [2/6] RUN apt-get update && apt-get upgrade -y
 => # Fetched 35.7 MB in 2s (15.0 MB/s)
 => # Reading package lists...
 => # Building dependency tree...

La construction de l’image peut prendre un moment. Une fois terminée, vous pourrez voir votre nouvelle image dans la liste des images (docker images).

Exemple :

Terminal
mowibox@chroma:~$ docker images
REPOSITORY         TAG      IMAGE ID       CREATED          SIZE
my_custom_ubuntu   latest   a67e56745215   43 seconds ago   980MB

Exécution du conteneur

Comme dans le tutoriel précédent, vous pouvez démarrer un conteneur de votre image :

docker run -it <image_name>

Exemple :

root@3d18c90647a5:/
mowibox@chroma:~$ docker run -it my_custom_ubuntu
root@3d18c90647a5:/#

Vous pouvez vérifier que vous êtes bien dans un conteneur basé sur Ubuntu 20.04 avec la commande utilisée au début du tutoriel :

Exemple :

root@3d18c90647a5:/
root@3d18c90647a5:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.6 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.6 LTS"
VERSION_ID="20.04"

Vous pouvez aussi regarder avec la commande ls si vos dossiers sont présents :

Exemple :

root@3d18c90647a5:/
root@3d18c90647a5:/# ls
bin   dev  home  lib32  libx32  media  my_image_folder  proc  ros_entrypoint.sh  sbin  sys  usr  workspace
boot  etc  lib   lib64  log     mnt    opt              root  run                srv   tmp  var

On constate notamment que les dossiers “my_image_folder/” et “workspace/” sont bien inclus dans le conteneur.

Si je navigue vers le dossier « my_image_folder/ », je retrouve mon fichier Python que je peux exécuter :

root@3d18c90647a5:/
root@3d18c90647a5:/# cd my_image_folder/
root@3d18c90647a5:/my_image_folder# ls
my_python_file.py

root@3d18c90647a5:/my_image_folder# python3 my_python_file.py
Hello, World!
1 + 2 = 3

Puisque nano a été installé au préalable sur l’image, je peux aussi éditer mon fichier et voir qu’il est identique à celui créé sur ma machine :

nano my_python_file.py

Displaying nano

Pour tester, je peux modifier le résultat de l’addition et relancer le code :

Editing nano

root@3d18c90647a5:/
root@3d18c90647a5:/my_image_folder# python3 my_python_file.py
Hello, World!
5 + 5 = 10

Et voilà ! vous avez réalisé une image customisée fonctionnelle et prête à être utilisée. Si quelqu’un veut l’utiliser, il suffira simplement de transmettre le Dockerfile et de suivre les mêmes étapes de construction sur sa machine pour obtenir une image identique.

Pour aller plus loin

Avec ce tutoriel, vous avez pu appréhender les bases de Docker : création d’images, exécution de conteneurs, et personnalisation via un Dockerfile. Mais Docker ne s’arrête pas là : il y’a encore plein d’autres fonctionnalités qui peuevent être explorées au besoin.

Vous pouvez, par exemple, partager des dossiers/fichiers directement entre la machine hôte et le conteneur en temps réel, plutôt que d’en faire une copie.

On constate également que dans un conteneur Docker, vous êtes définis par défaut en tant que super-utilisateur (root), c’est pourquoi il n’y pas besoin d’ajouter sudo dans vos commandes (apt install au lieu de sudo apt install). Avoir les pleins pouvoirs peut poser des problèmes de sécurité, c’est pourquoi il est recommandé de définir des utilisateurs non privilégiés avec la commande USER.

RUN useradd -m username
USER username

Pour finir, voici une excellente vidéo (en anglais) d’Articulated Robotics pour apprendre à bien construire un Dockerfile : YouTube


Crédits