📍 Article principal du parcours : Docker de zéro : comprendre et utiliser les conteneurs
Ce tutoriel ouvre le parcours « Docker de zéro ». Pour la vue d’ensemble, lisez d’abord le guide principal.
Avant d’écrire la moindre ligne de configuration, il faut se faire la main sur deux objets et un seul réflexe : une image, qu’on télécharge, et un conteneur, qu’on lance à partir d’elle. Tant que ces deux notions restent floues, toute la suite paraît magique. Une fois qu’on les a manipulées de ses propres mains, le reste s’enchaîne naturellement. C’est exactement ce que vous allez faire ici : tirer des images publiques, démarrer des conteneurs, les inspecter, les arrêter et les supprimer — sans rien installer d’autre que Docker sur votre machine.
🎯 Ce que vous allez apprendre
- vérifier votre installation Docker et lire les informations du moteur ;
- télécharger une image depuis Docker Hub et lancer un conteneur à partir d’elle ;
- distinguer concrètement une image d’un conteneur, et un conteneur actif d’un conteneur arrêté ;
- publier un port, nommer un conteneur, le lancer en arrière-plan et consulter ses journaux ;
- entrer dans un conteneur en marche pour l’explorer, puis faire le ménage proprement.
🛠️ Ce que vous allez construire
Pas encore l’API « Garde » — d’abord les fondations. Vous ferez tourner un serveur web nginx accessible depuis votre navigateur, puis une base PostgreSQL en arrière-plan, uniquement à partir d’images officielles. L’objectif est d’acquérir les gestes de base qui reviendront dans tous les tutoriels suivants.
Prérequis
- Docker installé : Docker Desktop sous Windows ou macOS, Docker Engine sous Linux.
- Un terminal (PowerShell, Terminal macOS, ou un shell Linux).
- Niveau débutant. Test express : si vous savez ouvrir un terminal et taper une commande, vous êtes prêt.
- ⏱️ Temps estimé : ~30 minutes.
Étape 1 — Vérifier que Docker répond
Avant tout, assurons-nous que le moteur tourne et que la commande docker communique bien avec lui. Cette première vérification évite de chercher des heures pourquoi « rien ne marche » alors que le daemon n’était simplement pas démarré.
docker version
docker info
docker version affiche deux blocs : le Client (la CLI que vous tapez) et le Server (le daemon). Si le bloc Server apparaît avec un numéro de version — au moment d’écrire, Docker Engine est en version 29.x — c’est que tout communique. Si vous voyez une erreur du type « Cannot connect to the Docker daemon », c’est que le moteur n’est pas lancé : démarrez Docker Desktop, ou sous Linux lancez le service avec sudo systemctl start docker. docker info, lui, résume l’état du moteur : nombre d’images, de conteneurs, pilote de stockage. Inutile de tout déchiffrer pour l’instant.
✅ Point d’étape — Vous devez voir un bloc « Server » avec une version. Si oui, le moteur tourne et vous pouvez continuer. Sinon, démarrez Docker avant d’aller plus loin.
Étape 2 — Lancer votre premier conteneur
Le rituel d’initiation de Docker consiste à lancer une image de test minuscule, hello-world, qui ne fait qu’afficher un message puis s’arrête. C’est le moyen le plus simple de vérifier toute la chaîne : téléchargement depuis le registre, création du conteneur, exécution.
docker run hello-world
Plusieurs choses se passent en une commande. Docker cherche l’image hello-world en local, ne la trouve pas, la télécharge depuis Docker Hub (« Unable to find image locally » suivi de « Pull complete »), crée un conteneur, l’exécute. Le conteneur affiche un paragraphe expliquant que l’installation fonctionne, puis se termine. Vous venez d’assister, en miniature, à tout le cycle. Notez bien le message : il décrit exactement les étapes que le daemon vient d’enchaîner.
✅ Point d’étape — Le texte « Hello from Docker! » s’affiche. Votre installation est pleinement opérationnelle.
Étape 3 — Différencier image et conteneur
C’est le moment de regarder ce que cette première exécution a laissé derrière elle. Deux commandes répondent à la question « qu’est-ce qui existe sur ma machine ? » : l’une liste les images, l’autre les conteneurs.
docker images
docker ps -a
docker images montre l’image hello-world téléchargée : c’est le modèle figé, toujours présent. docker ps seul ne montrerait rien, car il ne liste que les conteneurs en cours d’exécution ; or notre conteneur s’est arrêté aussitôt. En ajoutant -a (pour all), on voit aussi les conteneurs arrêtés : votre hello-world y figure, avec un statut « Exited ». Voilà la distinction rendue tangible : une image reste sur le disque, et un conteneur (arrêté) en a été dérivé. Si vous relancez docker run hello-world trois fois, vous obtiendrez trois conteneurs distincts issus de la même image unique.
✅ Point d’étape — Vous voyez une ligne dans
docker imageset au moins une ligne « Exited » dansdocker ps -a. La différence image/conteneur n’est plus abstraite.
Étape 4 — Un vrai service : nginx avec un port publié
hello-world s’arrête tout de suite ; un serveur web, lui, doit rester allumé et être joignable. On va lancer nginx, le serveur web le plus répandu, et le rendre accessible depuis notre navigateur. C’est ici qu’intervient la publication de port : par défaut, ce qui tourne dans un conteneur est invisible de l’extérieur ; il faut explicitement relier un port de la machine hôte à un port du conteneur.
docker run -d --name web-garde -p 8080:80 nginx:alpine
Décortiquons chaque option, car ces drapeaux reviendront sans cesse. -d (detached) lance le conteneur en arrière-plan et rend la main au terminal. --name web-garde donne un nom lisible au conteneur au lieu d’un identifiant aléatoire. -p 8080:80 relie le port 8080 de votre machine au port 80 du conteneur (où nginx écoute). Enfin nginx:alpine est l’image, dans sa variante alpine, beaucoup plus légère. Ouvrez maintenant http://localhost:8080 dans votre navigateur : la page d’accueil de nginx s’affiche. Votre premier service tourne dans un conteneur.
✅ Point d’étape —
http://localhost:8080affiche « Welcome to nginx! ». Si la page ne répond pas, vérifiez avecdocker psqueweb-gardeest bien « Up », et qu’aucun autre programme n’occupe déjà le port 8080.
Étape 5 — Observer, inspecter, entrer dans un conteneur
Un conteneur en marche n’est pas une boîte noire. On peut lire ses journaux, voir ce qu’il consomme, et même ouvrir un shell à l’intérieur pour explorer son système de fichiers. Ces gestes sont vos outils de diagnostic quotidiens.
docker logs web-garde
docker exec -it web-garde sh
docker logs affiche la sortie du conteneur — ici, les requêtes HTTP reçues par nginx. docker exec -it web-garde sh ouvre un shell dans le conteneur en marche : les options -i et -t rendent la session interactive. Vous vous retrouvez avec une invite à l’intérieur du conteneur ; tapez ls /usr/share/nginx/html pour voir les fichiers servis par nginx, puis exit pour ressortir sans arrêter le conteneur. Vous venez de constater qu’un conteneur a bien son propre système de fichiers isolé.
✅ Point d’étape — Vous avez vu les journaux d’nginx et obtenu une invite shell à l’intérieur du conteneur, puis vous en êtes ressorti avec
exit, le conteneur toujours actif.
Étape 6 — Une base de données en arrière-plan
Pour préparer le terrain des prochains tutoriels, lançons une base PostgreSQL — celle qui servira plus tard à l’API « Garde ». Une base a besoin d’au moins un mot de passe pour démarrer ; on le passe par une variable d’environnement avec l’option -e.
docker run -d --name db-garde -e POSTGRES_PASSWORD=motdepasse_demo -p 5432:5432 postgres:17
L’option -e POSTGRES_PASSWORD=... fournit la variable que l’image PostgreSQL officielle attend pour s’initialiser. Le port 5432 (port standard de PostgreSQL) est publié pour pouvoir s’y connecter depuis l’hôte. Vérifiez que la base a bien démarré en lisant ses journaux : docker logs db-garde doit se terminer par « database system is ready to accept connections ». Vous avez maintenant deux conteneurs qui tournent en parallèle, chacun issu d’une image officielle, sans avoir installé ni nginx ni PostgreSQL sur votre système.
✅ Point d’étape —
docker psliste deux conteneurs « Up » :web-gardeetdb-garde. La ligne « ready to accept connections » confirme que PostgreSQL est prêt.
Étape 7 — Arrêter et nettoyer
Apprendre à faire le ménage est aussi important que savoir lancer. Les conteneurs arrêtés et les images inutilisées s’accumulent et finissent par saturer le disque. Arrêtons et supprimons proprement ce que nous avons créé.
docker stop web-garde db-garde
docker rm web-garde db-garde
docker ps -a
docker stop arrête en douceur les conteneurs (il leur laisse le temps de se terminer), docker rm les supprime définitivement. Le dernier docker ps -a ne doit plus mentionner ni web-garde ni db-garde. Les images, elles, restent en cache — c’est voulu, pour ne pas avoir à les retélécharger. Pour libérer de l’espace plus tard, docker system prune retire d’un coup les conteneurs arrêtés et les couches orphelines.
✅ Point d’étape —
docker ps -ane liste plus vos deux conteneurs. La machine est propre, les images conservées en cache.
Comprendre l’isolation d’un conteneur
Vous avez constaté qu’un conteneur a son propre système de fichiers et son propre réseau. Il vaut la peine de préciser ce qu’il isole réellement, car c’est cette frontière qui explique à la fois la légèreté de Docker et certaines de ses limites. Un conteneur isole l’espace utilisateur : ses processus, son arborescence de fichiers, ses ports, ses variables d’environnement. Deux conteneurs ne se voient pas l’un l’autre par défaut, ne partagent pas leurs fichiers, et croient chacun être seuls sur la machine. En revanche, ils partagent le noyau du système hôte. C’est là toute la différence avec une machine virtuelle : pas de second système d’exploitation à démarrer, donc un lancement quasi instantané et une empreinte mémoire minime.
Cette conception a une conséquence directe et utile : un conteneur n’est pas censé contenir « une machine », mais un seul processus — un serveur web, une base, une API. On ne met pas nginx et PostgreSQL dans le même conteneur ; on en fait deux, qu’on relie par un réseau. Cette règle « un conteneur, une responsabilité » déroute au début, surtout quand on vient des serveurs traditionnels où tout cohabite. Mais elle rend chaque brique remplaçable, observable et redéployable indépendamment. C’est exactement ce qui rendra naturel, dans les tutoriels suivants, le fait de décrire l’API et sa base comme deux services distincts plutôt que comme un bloc unique.
Un dernier point sur l’isolation du système de fichiers éclaire ce qui suit. Quand un conteneur écrit un fichier, il l’écrit dans sa couche éphémère, qui disparaît à sa suppression. C’est pourquoi la base PostgreSQL que vous venez de lancer perdrait toutes ses données si vous supprimiez son conteneur. Pour conserver des données au-delà de la vie d’un conteneur, on monte un volume — un espace de stockage géré séparément. Vous n’en avez pas eu besoin ici puisqu’on faisait juste des essais, mais ce sera la première chose à régler dès qu’une vraie base entre en jeu.
🐞 Pièges fréquents
| Symptôme / erreur | Cause probable | Correctif |
|---|---|---|
| « Cannot connect to the Docker daemon » | Le moteur n’est pas démarré | Lancer Docker Desktop, ou sudo systemctl start docker sous Linux. |
| « port is already allocated » | Le port hôte (8080, 5432) est déjà occupé | Choisir un autre port à gauche du :, ex. -p 8081:80. |
Le conteneur s’arrête aussitôt après run |
Son processus principal s’est terminé | Normal pour hello-world ; pour un service, vérifier la commande de démarrage et les journaux. |
« permission denied » sur docker sous Linux |
Utilisateur pas dans le groupe docker |
sudo usermod -aG docker $USER puis se reconnecter, ou préfixer par sudo. |
docker ps ne montre pas mon conteneur arrêté |
docker ps ne liste que l’actif |
Ajouter -a : docker ps -a. |
Tirer ses images sur une connexion limitée
Le premier docker pull d’une image peut être lent sur une connexion modeste à Lomé ou Niamey : l’image postgres:17 pèse plusieurs centaines de méga-octets. La bonne nouvelle, c’est qu’on ne la télécharge qu’une fois — ensuite elle vit dans votre cache local et chaque docker run est instantané. Préférez systématiquement les variantes alpine quand elles existent (nginx:alpine fait quelques méga-octets contre des dizaines pour la version standard) : sur un forfait data limité, l’économie est réelle. Et si vous travaillez en équipe sur un même réseau local, sachez qu’on peut monter un cache d’images partagé (un registry miroir) pour ne télécharger chaque image qu’une seule fois pour tout le bureau — un sujet que le tutoriel sur les registres effleure.
✅ Récapitulatif
Vous savez désormais vérifier votre moteur, tirer une image, lancer un conteneur en arrière-plan, publier un port, lire des journaux, entrer dans un conteneur et nettoyer. Surtout, la distinction fondatrice est acquise : une image est un modèle figé en lecture seule, un conteneur en est une instance vivante et jetable. Ces gestes sont le socle de tout ce qui suit. Dans le prochain tutoriel, vous cesserez de consommer des images publiques pour construire la vôtre.
🧾 Aide-mémoire
| Commande | Rôle |
|---|---|
docker run -d --name X -p 8080:80 img |
Lancer un conteneur nommé en arrière-plan, port publié |
docker ps / docker ps -a |
Lister les conteneurs actifs / tous (y compris arrêtés) |
docker images |
Lister les images locales |
docker logs X |
Afficher les journaux d’un conteneur |
docker exec -it X sh |
Ouvrir un shell dans un conteneur en marche |
docker stop X / docker rm X |
Arrêter / supprimer un conteneur |
docker system prune |
Nettoyer conteneurs arrêtés et couches orphelines |
💪 À vous de jouer
Lancez deux conteneurs nginx en même temps, sur deux ports différents (8080 et 8081), avec des noms distincts. Vérifiez que les deux pages répondent dans votre navigateur, puis arrêtez et supprimez les deux d’une seule commande.
Voir une solution
docker run -d --name web1 -p 8080:80 nginx:alpine
docker run -d --name web2 -p 8081:80 nginx:alpine
# Vérifier http://localhost:8080 et http://localhost:8081
docker rm -f web1 web2 # -f arrête puis supprime en une fois
L’option -f (force) combine l’arrêt et la suppression. Les deux conteneurs partagent la même image nginx:alpine : une seule image, deux instances indépendantes.
Tutoriels frères
- Écrire son premier Dockerfile — construire votre propre image après avoir consommé celles des autres.
- Débuter avec Docker Compose — lancer plusieurs conteneurs d’une seule commande.
Pour aller plus loin
- 🔝 Retour au guide principal : Docker de zéro : comprendre et utiliser les conteneurs
- Documentation officielle : Docker Get started
- Étape suivante du parcours : écrire son premier Dockerfile.
Ressources et références
- Référence de la CLI
docker - Image officielle nginx sur Docker Hub
- Image officielle PostgreSQL sur Docker Hub
FAQ
Quelle différence entre docker run et docker start ?docker run crée un nouveau conteneur à partir d’une image. docker start relance un conteneur existant qui était arrêté, sans en créer un nouveau. Si vous tapez docker run trois fois, vous obtenez trois conteneurs.
Que signifie le tag après le nom d’image, comme :alpine ou :17 ?
Le tag précise une variante ou une version de l’image. postgres:17 demande PostgreSQL 17 ; nginx:alpine demande la version d’nginx basée sur Alpine Linux. Sans tag, Docker utilise :latest, ce qui est pratique mais imprévisible dans le temps — d’où l’intérêt de toujours épingler une version.
Pourquoi mon conteneur hello-world est-il « Exited » et pas « Up » ?
Parce que son rôle est seulement d’afficher un message puis de se terminer. Un conteneur vit tant que son processus principal vit ; celui de hello-world rend la main immédiatement, donc le conteneur s’arrête. Un serveur comme nginx, lui, garde son processus actif et reste « Up ».
Supprimer un conteneur supprime-t-il son image ?
Non. docker rm ne touche qu’au conteneur. L’image reste dans le cache local. Pour supprimer une image, on utilise docker rmi, à condition qu’aucun conteneur ne l’utilise encore.