Chapitre 1 - Prise en main

Qu'est ce que Docker ?

Docker est une plateforme open-source qui permet aux développeurs de construire, déployer et exécuter des conteneurs.

Les conteneurs combinent :

jose-m-alarcon-lQnGMbSD-5M-unsplash.jpg

Photo de José M. Alarcón sur Unsplash

La métaphore avec un porte conteneur est intéressante.
Les conteneurs se ressemblent d'extérieur. Ils possèdent les mêmes dimensions et les mêmes dispositifs d'attache et d'empilement.
Depuis l'intérieur d'un conteneur fermé, impossible d'accéder à l'extérieur.

Le terme Docker fait généralement référence à Docker Engine, le moteur d'exécution pour la construction et l'exécution des conteneurs.
Docker fait également référence à la société qui vend la version commerciale de Docker ou au projet open source Docker.

Docker a été créé en 2013 avant de devenir rapidement un incontournable dans le monde du développement logiciel.

Conteneurisation vs virtualisation

La conteneurisation de Docker est souvent comparée à de la virtualisation.

Le principe de base est le même : l'application conteneurisée est isolée du reste de la machine et ne peut pas sortir du conteneur, tout comme un système d'exploitation virtualisé ne peut pas sortir de sa machine virtuelle.

La conteneurisation va plus loin : Le conteneur n'embarque pas de système d'exploitation mais il isole l'application du reste de la machine hôte : processus, système de fichiers, réseau, ressources CPU et RAM : tout est délimité et isolé du reste.

La conteneurisation offre tous les avantages de la virtualisation, notamment l'isolation et l'évolutivité, ainsi que d'autres avantages :

La différence peut être schématisée ainsi :

Installation et hello-world

Docker Engine et Docker Desktop

Docker est nativement compatible avec Linux. Il peut être installé et piloté en ligne de commande.

Sous Windows, l'utilisation de Docker Desktop est recommandée, même si elle n'est pas obligatoire.
Il est tout à fait possible d'installer Docker dans WSL, sans Docker Desktop.

Pour la suite de ce cours, nous n'utiliserons que la ligne de commande.

Installation

Linux

La documentation officielle propose une procédure d'installation pour la plupart des distributions : 🔗 Install | Docker Docs

Un exemple sous Debian :

# suppression d'anciennes installations
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done

# Ajout du repository Docker officiel (clé PGP)
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Ajout du repository Docker officiel (source APT)
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

# Installation des paquets
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Démarrage automatique avec systemd (généralement automatique)
sudo systemctl enable docker.service
sudo systemctl enable containerd.service

Par défaut, docker n'est pas utilisable depuis un compte non root. La documentation détaille comment rendre accessible le démon Docker : 🔗 Post-installation steps | Docker Docs

# Create the docker group.
sudo groupadd docker

# Add your user to the docker group.
sudo usermod -aG docker $USER

# Add without reboot
newgrp docker

Windows

Docker préconise l'installation de 🔗 Docker Destkop.

Sous le capot, Docker Desktop installe Docker Engine dans l'environnement virtualisé WSL ou Hyper-V sous Windows.

Il est tout à fait possible d'installer manuellement WSL sous Windows puis de suivre la procédure d'installation de Docker pour un environnement Linux.

MacOS

Voir documentation : 🔗 Docker Desktop Mac

Machine virtuelle Debian

En cas de difficulté, une machine virtuelle Debian 13 prête à l'emploi est disponible ci-dessous.

🔗 Machine virtuelle Debian 13

Hello World

Il est possible de tester l'installation avec la commande suivante :

docker run hello-world

image.png

Commandes de base

Exécuter un conteneur : docker run

Commande de base : 

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Le nom de l'image docker à utiliser doit être spécifié avec le paramètre image. Quelques exemples :

Il existe actuellement 11 millions d'image (août 2025) sur le Docker Hub (que nous approfondirons plus tard).

La commande docker run propose de nombreux paramètres dont voici les principaux :

Paramètre Description Exemple
--name Attribuer un nom au conteneur.
Si il n'est pas défini, Docker générera un nom aléatoire à partir d'un dictionnaire de mots.
docker run ubuntu --name=test1
docker run ubuntu --name=test2
docker run ubuntu --name=test3
-ti Les paramètres -t et -i permettent d’ouvrir un terminal interactif dans le conteneur : -t alloue un pseudo-terminal, et -i garde l’entrée ouverte.
docker run -ti ubuntu
# je suis redirigé dans la console du conteneur
-d, --detached Lance le conteneur en arrière-plan, en mode détaché.
docker run -d ubuntu
# le conteneur se lance en arrière-plan
--rm Supprimer le conteneur lorsqu'il est arrêté.

 

docker run --rm -ti ubuntu
# le conteneur se lance dans la console
# Il sera supprimé après la sorite (exit)
-e, --env Passer une variable d'environnement à l'application conteneurisée
docker run -e VAR1=value1
# la variable VAR1 sera définie dans le conteneur


image.png

Nous approfondirons plus tard d'autres paramètres de la commande docker run.

La commande docker run se termine par la commande à lancer dans le conteneur ainsi que ses paramètres. L'ajout de cette commande est optionnel, il n'est pas toujours nécessaire de l'indiquer.

Certaines images ne lancent pas automatiquement d'invite de commande bash.
Par exemple, l'image officielle python démarre sur une invite de commande python :

image.png

Lister les conteneurs : docker ps

La commande docker ps liste les conteneurs démarrés sur la machine. Le paramètre --all, -a permet d'afficher les conteneurs stoppés.

docker ps
docker ps -a

image.png

Astuce : il est possible de se détacher d'un conteneur sans l'arrêter avec CTRL+P puis CTRL+Q !

image.png

Après avoir pressé CTRL+P puis CTRL+Q, je suis détaché du conteneur test_3 qui tourne encore en arrière-plan.

Arrêt d'un conteneur : docker stop et docker start

docker start MON_CONTENEUR  # démarre le conteneur
docker stop MON_CONTENEUR # arrête le conteneur
docker rm MON_CONTENEUR # supprime le conteneur

image.png

Visualiser les logs : docker logs

docker logs MON_CONTENEUR
docker logs -f MON_CONTENEUR # -f pour --follow, permet de visualiser en direct le log.

image.png

La commande date est lancée au démarrage du conteneur détaché, je ne vois pas le résultat.
J'y accède plus tard avec la commande docker logs.

S'attacher à un conteneur : docker attach

docker attach MON_CONTENEUR

image.png

Le conteneur a été lancé en arrière-plan (mode détaché) avec -d. Je peux y accéder plus tard.

Exécuter une commande : docker exec

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

La syntaxe de cette commande ressemble à docker run. La différence est qu'ici, la commande est lancée dans un conteneur déjà en cours d'exécution.

La commande docker exec est utile pour lancer une invite de commande (bash) dans un conteneur qui n'en propose pas forcément. Exemple avec python :

image.png

Je lance un conteneur python sans préciser de commande. La commande par défaut de l'image docker est utilisée.
Lorsque je m'attache au conteneur avec docker attach, je suis dans une invite de commande python.
Je me détache du conteneur et je lance une invite de commande bash avec docker exec.

La commande docker exec exécute un nouveau processus dans le conteneur. La sortie de ce processus n'est pas visible dans les logs du conteneur !

Images et système de fichiers

Images Docker

Une image Docker est un fichier immuable qui contient tout le nécessaire pour exécuter une application dans un conteneur.
Elle contient le code source, les bibliothèques, les dépendances, les variables d'environnement, les configurations, etc.

L'image Docker est une photographie figée d’un environnement logiciel, garantissant que l'application s’exécutera systématiquement de la même manière, indépendamment de son environnement.

Une image Docker est construite à partir d'un fichier de configuration appelé Dockerfile. Ce fichier décrit étape par étape comment assembler l'image.

Nous reviendrons plus tard sur le Dockerfile.

Une fois construite, une image peut être stockée localement ou poussée vers un registre Docker (comme Docker Hub ou un registre privé), où elle peut être versionnée et partagée.

Pour identifier une image Docker, on utilise la syntaxe suivante :

propriétaire/nom:tag

Certaines images "officielles" ne possèdent pas de propriétaire, donc il n'est pas nécessaire de le préciser.

Quelques exemples :

nginx:latest # image officielle de Nginx, version la plus récente.
thibaud/appli:1.2.0 # image personnalisée appartenant à l’utilisateur thibaud, version 1.2.0.

Registry Docker Hub

Comme expliqué ci-dessus, les images Docker doivent être stockées sur un registre.

Un registre peut être public ou privé, par exemple au sein d'une entreprise afin d'y stocker une application propriétaire.

Le registre public et par défaut est le Docker Hub. 🔗 Docker Hub

La commande docker pull permet de télécharger une image depuis un registre, par défaut le registre public Docker Hub.

image.png

Actuellement, l'image latest d'Ubuntu correspond à la version 24.04 sur le Docker Hub.
Ces trois identifiants retournent la même image, qui n'est téléchargée qu'une seule fois : ubuntu, ubuntu:latest, ubuntu:24.04.

À l'inverse, si je lance un docker run sur une image qui n'est pas déjà stockée localement, le téléchargement est automatique depuis le Docker Hub :

image.png

La commande docker image permet de gérer les images stockées localement.

docker image ls # lister les images
docker image rm ubutu:18.04 # supprimer l'image ubuntu taggée 18.04

image.png

Système de fichiers

L'arborescence des fichiers dans un conteneur Docker est isolé du reste de la machine.

Un conteneur Docker contient une arborescence Linux. Exemple ci-dessous :

image.png

L'arborescence ci-dessus n'est accessible que depuis le conteneur.

image.png

Volatilité

Contrairement à une image docker qui est figée, le contenu d'un container est volatile.

Lorsqu'un container est supprimé, tous les fichiers modifiés sont perdus !

Exemple :

image.png

Les deux conteneurs nommés test à partir de l'image debian ne sont pas les mêmes : ils n'ont pas le même identifiant.

Les données du premier conteneur sont perdues lors de sa suppression.

Nous verrons plus loin les volumes Docker qui permettent de stocker des données persistantes.

Isolation : un exemple avec fastfetch

image.png

L'hôte et le conteneur partagent quelques éléments tels que le noyau Linux, le CPU, la RAM disponible et l'espace disque.
À l'inverse, la distribution Linux, les paquets installés et le système de fichier sont isolés.

Les volumes

Utilisation des volumes

Les volumes sont des répertoires accessibles depuis le conteneur et l'hôte.
Les volumes sont persistants, contrairement aux fichiers des conteneurs docker.

Les volumes sont très utiles avec Docker, ils peuvent servir à stocker, par exemple :

Une application dockerisée correctement configurée doit stocker ses données dans des volumes.

L'avantage des volumes est la sauvegarde : seules les données utiles s'y trouvent et il est possible de dupliquer une application à partir d'une image docker et des volumes associés.

Un volume est accessible depuis le container à partir de son point de montage. Exemple :

image.png

Le dossier /home/debian/test de l'hôte est monté dans /toto au sein du conteneur avec le paramètre -v. L'hôte et le conteneur ont accès au répertoire.

-v /home/debian/test:/toto

Généralement, les images Docker d'applications indiquent les répertoires dans lesquels elles stockent leurs données utiles, par exemple :

Volumes mappés vs. Volumes managés

Il existe deux types de volumes Docker : mappés et managés. Ils diffèrent par leur mode de gestion et leur usage :

L'exemple ci-dessus est un volume mappé.

Gestion des volumes managés

Les volumes managés docker sont gérés avec la commande docker volume.

docker volume create mon_volume # créer un volume
docker volume ls # lister les volumes
docker volume rm mon_volume # supprimer un volume

Lors de l'exécution d'un conteneur, il faut aussi utiliser -v pour monter un volume managé. À l'inverse d'un volume mappé, il faut indiquer le nom du volume plutôt que son chemin.

docker run -v mon_volume:/home/thibaud/volume ubuntu
# Le contenu du volume mon_volume sera monté dans /home/thibaud/volume au sein du conteneur

Le volume est indépendant du conteneur auquel il est attaché :

image.png

Une subtilité des volumes managés est la priorité des données si l'un des deux répertoires est vide lors du lancement d'un conteneur :

Volume Point de montage (conteneur) Action
Si vide Si non vide Les données initialement dans le conteneur sont copiées dans le volume.
Si non vide Si vide Le contenu du volume est monté dans le conteneur, comme dans l'exemple ci-dessus.
Si non vide Si non vide Le contenu du répertoire dans le conteneur est écrasé par celui du volume.

La gestion des ports

Redirection des ports

La plupart des applications dockerisées écoutent sur des ports spécifiques. Par exemple : serveurs web, bases de données, API, etc.

Pour les rendre accessibles depuis l'extérieur, il faut rediriger ces ports avec l'option --port, -p.
Cette option permet de lier un port du conteneur à un port de la machine hôte.

Dans le détail, lorsqu'une requête est envoyée à un port de la machine hôte, Docker la redirige automatiquement vers le port correspondant à l'intérieur du conteneur.

La syntaxe de -p est la suivante :

-p [IP:]PORT_HOTE:PORT_CONTENEUR

La redirection de ports docker permet de répondre à des cas d'usages fréquents : contrôle d'accès aux applications, gestion des conflits de port avec des applications similaires, configuration d'architectures réseaux complexes, etc.

Exemples avec strm/helloworld-http

L'image  🔗 strm/helloworld-http permet d'afficher un message test et écoute sur le port 80, port HTTP par défaut.

Une fois lancé, un docker ps -a nous confirme que le port 80 du conteneur est ouvert.

image.png

image.png

Néanmoins, le port 80 de la machine hôte ne répond pas :

image.png

Le port 80 de la machine hôte n'est pas automatiquement redirigé vers celui du conteneur.

Il faut lancer le container avec l'argument -p. Il est tout à fait possible d'indiquer un autre port pour l'hôte, par exemple 90.

image.png

Un docker ps -a nous confirme que le port 90 de la machine hôte est redirigé vers le port 80 du conteneur.

image.png

La page web est accessible depuis 127.0.0.1:90. Elle est également accessible depuis le LAN, toujours sur le port 90.

image.png

Il est possible de n'écouter que depuis l'IP 127.0.0.1 avec -p 127.0.0.1:90:80.

image.png

Cela peut-être utile pour faire fonctionner une application derrière un reverse proxy (traefik, apache, nginx, etc.) afin de lui attribuer un nom de domaine.

TP : Application PHP

Objectif

L'objectif est de lancer un script PHP dans deux conteneurs avec des versions PHP distinctes.
Il faudra au préalable lancer un conteneur temporaire afin de télécharger le script PHP dans un volume managé.

Aucune connaissance de PHP n'est requise.

Consignes

1 - Récupération du script PHP dans un volume docker

cd /tp_docker
apt update && apt-get install wget -y
wget https://formation-tfrichet-assets.s3.fr-par.scw.cloud/docker-tp-1/index.php 
chmod 777 ./

2 - Exécution avec PHP 8.2

3 - Exécution avec PHP 8.3

Résultat attendu

Les 3 captures d'écran suivantes sont attendues pour valider le TP.

image.png

image.png

image.png