Développement web

Docker : la différence entre image et conteneur expliquée avec des commandes

Une image Docker est un modèle en lecture seule ; un conteneur est une instance en cours d’exécution. La différence, les commandes de base et les erreurs courantes.

Une image Docker est un modèle immuable, en lecture seule, qui contient un système de fichiers avec tout le nécessaire pour exécuter une application (code, dépendances, configuration). Un conteneur est une instance en cours d’exécution de cette image, avec sa propre couche d’écriture. L’analogie la plus utile vient de la programmation orientée objet : l’image est la classe et le conteneur est l’objet. À partir d’une même image, vous pouvez lancer autant de conteneurs que vous voulez, chacun isolé des autres.

Si vous débutez avec Docker, c’est cette distinction qui évite la plupart des confusions : ce qui se télécharge, ce qui s’exécute, ce qui occupe de l’espace et ce qui se perd à la suppression.

Ce qu’est une image

Une image est construite par couches. Chaque instruction d’un Dockerfile (FROM, RUN, COPY…) produit une couche, et les couches s’empilent : celle du bas est généralement un système de base (Debian, Alpine, Ubuntu), au-dessus viennent les dépendances et en haut le code de votre application. Les couches sont en lecture seule et partagées entre images : si dix images partent de la même base, cette base n’occupe de l’espace disque qu’une seule fois.

Les images s’identifient par un nom et un tag (node:22-alpine, nginx:1.27) et se distribuent via des registres comme Docker Hub.

# Télécharger une image
docker pull nginx:1.27

# Lister les images locales
docker images

# Construire une image à partir du Dockerfile du répertoire courant
docker build -t mon-app:1.0 .

# Supprimer une image (seulement si aucun conteneur ne l’utilise)
docker rmi mon-app:1.0

Ce qu’est un conteneur

Un conteneur est un processus (ou un groupe de processus) qui s’exécute isolé du reste du système, en utilisant l’image comme système de fichiers de base et en ajoutant par-dessus une couche d’écriture. Tout ce que l’application écrit pendant son exécution (journaux, fichiers temporaires, données) va dans cette couche. Quand le conteneur est supprimé, la couche d’écriture disparaît avec lui ; l’image reste intacte.

# Créer et démarrer un conteneur à partir d’une image
docker run -d --name web -p 8080:80 nginx:1.27

# Lister les conteneurs en cours d’exécution (-a inclut les arrêtés)
docker ps
docker ps -a

# Voir les journaux et entrer dans le conteneur
docker logs web
docker exec -it web sh

# Arrêter, redémarrer et supprimer
docker stop web
docker start web
docker rm web

docker run fait deux choses à la fois : il crée le conteneur (docker create) et le démarre (docker start). C’est pourquoi, si vous exécutez docker run trois fois avec la même image, vous obtenez trois conteneurs distincts, pas un seul.

La relation entre les deux, en un tableau

Image Conteneur
Ce que c’est Modèle en lecture seule Instance en cours d’exécution (ou arrêtée) d’une image
Se crée avec docker build, docker pull docker run, docker create
Se liste avec docker images docker ps -a
Se supprime avec docker rmi docker rm
Change à l’exécution ? Non Oui, dans sa couche d’écriture
Combien peut-il y en avoir ? Un par nom:tag Autant que vous voulez par image

Où sont stockées les données : les volumes

Comme la couche d’écriture meurt avec le conteneur, toute donnée qui doit survivre (une base de données, des fichiers envoyés par des utilisateurs) doit vivre à l’extérieur, dans un volume ou dans un répertoire de l’hôte monté dans le conteneur :

# Volume géré par Docker
docker run -d --name db -v donnees-db:/var/lib/postgresql/data postgres:16

# Répertoire de l’hôte (bind mount), pratique en développement
docker run -d --name web -v "$(pwd)/html:/usr/share/nginx/html:ro" -p 8080:80 nginx:1.27

Vous pouvez ainsi supprimer et recréer le conteneur sans perdre les données. La documentation sur les volumes détaille les différences entre les deux options.

Erreurs fréquentes

  1. Croire que docker stop libère l’espace. Un conteneur arrêté existe toujours avec sa couche d’écriture. Pour libérer l’espace, il faut le supprimer avec docker rm (ou utiliser docker run --rm pour qu’il se supprime seul à la fin).
  2. Stocker des données dans le conteneur. Ça marche jusqu’à ce que vous le recréiez. Utilisez des volumes dès le début.
  3. Modifier un conteneur et attendre que l’image change. Ça n’arrive pas. Si une modification doit faire partie de l’image, faites-la dans le Dockerfile et reconstruisez. docker commit existe, mais il produit des images non reproductibles et il vaut mieux l’éviter.
  4. Accumuler des images et conteneurs orphelins. docker system df montre ce qu’ils occupent ; docker system prune supprime les conteneurs arrêtés, les réseaux inutilisés et les images sans tag (il demande confirmation).
  5. Utiliser le tag latest en production. latest change avec le temps ; fixez une version précise (node:22.12-alpine) pour que le déploiement soit reproductible.

Conclusion

L’image est le modèle ; le conteneur, l’exécution. Les images se construisent et se téléchargent, les conteneurs se démarrent, s’arrêtent et se suppriment, et les données qui doivent durer vont dans des volumes. Avec ces trois concepts clairs, le reste de Docker (réseaux, Compose, registres) se comprend comme des combinaisons de la même chose.

Sources et références

  1. Docker Docs : What is an image? docs.docker.com
  2. Docker Docs : What is a container? docs.docker.com
  3. Docker Docs : docker container run docs.docker.com
  4. Docker Docs : Dockerfile reference docs.docker.com
  5. Docker Docs : Volumes docs.docker.com