Installation
Un moteur qui tourne, et les commandes qui comptent vraiment.
Installation et premiers pas
Installer Docker prend cinq minutes quand on suit la bonne procédure, et une soirée entière quand on suit la mauvaise. Le piège le plus courant : le paquet docker.io ou docker proposé par le gestionnaire de paquets de votre distribution. Il existe, il s’installe, il fonctionne à peu près — et il est souvent en retard de plusieurs versions majeures, parfois sans le plugin Compose, ce qui vous fera chercher pendant vingt minutes pourquoi une commande de la documentation officielle « n’existe pas » chez vous.
Le deuxième piège est ailleurs, et il touche presque tout le monde une fois : après une installation parfaitement réussie, la première commande répond permission denied while trying to connect to the Docker daemon socket. Ce n’est pas un échec d’installation. C’est une conséquence directe de l’architecture vue à la leçon précédente — le client parle à un daemon privilégié à travers un socket — et cela se règle par une ligne, à condition de comprendre laquelle et pourquoi.
Cette leçon vous fait franchir ces deux obstacles selon votre système, puis se concentre sur ce qui compte réellement : une dizaine de commandes qui couvrent 90 % du travail quotidien. Pas une liste exhaustive d’options — la documentation existe pour ça — mais le petit ensemble que vous taperez chaque jour, avec ce qui se passe derrière chacune.
À la fin, vous saurez démarrer un conteneur, y entrer, lire ses journaux, comprendre pourquoi il s’est arrêté, et récupérer les dizaines de gigaoctets que Docker aura discrètement accumulés sur votre disque.
Installer Docker Engine sur Linux
Sur Linux, Docker tourne nativement : pas de VM intermédiaire, pas de couche de traduction. C’est l’environnement le plus simple et le plus performant. La méthode recommandée passe par le dépôt officiel de Docker, ce qui garantit des mises à jour et la présence des plugins modernes.
Sur Debian et Ubuntu :
# 1. Retirer les paquets anciens ou concurrents, s'ils sont presents
for p in docker.io docker-doc docker-compose podman-docker containerd runc; do
sudo apt-get remove -y "$p"
done
# 2. Ajouter la cle GPG officielle de Docker
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# 3. Declarer le depot (le nom de code de la distribution est detecte)
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 4. Installer le moteur ET les plugins (buildx, compose)
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
Les deux derniers paquets sont ceux qu’on oublie, et ce sont eux qui fournissent docker buildx et docker compose. Pour une Debian, remplacez les deux occurrences de ubuntu par debian dans les URL. Pour Fedora ou RHEL, la procédure équivalente utilise dnf et le dépôt docker-ce.repo ; elle est détaillée sur docs.docker.com/engine/install.
Il reste à s’assurer que le daemon démarre, maintenant et à chaque redémarrage de la machine :
# --now demarre le service, enable l'active au demarrage
sudo systemctl enable --now docker
# Verifier son etat
systemctl status docker --no-pager
Une alternative existe pour un poste jetable ou une machine de test : le script d’installation officiel.
curl -fsSL https://get.docker.com -o get-docker.sh
# Toujours lire un script avant de l'executer en root
less get-docker.sh
sudo sh get-docker.sh
Il est pratique, mais il est explicitement déconseillé en production par Docker : il devine votre distribution et prend des décisions à votre place, ce qu’on ne veut pas sur un serveur qu’on doit pouvoir reconstruire à l’identique.
« permission denied » : le groupe docker
Voici l’erreur qui attend tout le monde à la première commande :
permission denied while trying to connect to the Docker daemon socket
at unix:///var/run/docker.sock
Le daemon écoute sur un socket UNIX, /var/run/docker.sock, dont le propriétaire est root et le groupe docker. Votre utilisateur n’appartient à ce groupe qu’à condition de l’y avoir ajouté.
# Le groupe existe deja apres l'installation ; la commande est idempotente
sudo groupadd -f docker
# Ajouter votre utilisateur (-a = append, indispensable :
# sans lui, usermod REMPLACE la liste des groupes)
sudo usermod -aG docker "$USER"
# L'appartenance a un groupe est lue a l'ouverture de session.
# Ouvrez une nouvelle session, ou forcez-la pour le shell courant :
newgrp docker
# Verifier
id -nG | tr ' ' '\n' | grep docker
docker run --rm hello-world
L’oubli du -a dans usermod -aG est une erreur qui coûte cher : elle retire l’utilisateur de tous ses autres groupes, sudo compris.
Il faut savoir ce que cette manipulation autorise réellement. Le daemon tourne en root, et l’API qu’il expose permet notamment de monter n’importe quel dossier de l’hôte dans un conteneur. Appartenir au groupe docker équivaut donc, en pratique, à disposer d’un accès superutilisateur à la machine. C’est acceptable sur votre poste de travail ; sur un serveur partagé, cela mérite une décision consciente. Pour les cas où cette élévation est inacceptable, Docker propose un mode rootless qui fait tourner le daemon sous votre propre compte.
macOS et Windows : le détour par une machine virtuelle
Rappel de la leçon 1 : une image Linux exige un noyau Linux. Ni macOS ni Windows n’en fournissent. Sur ces systèmes, Docker Desktop installe et pilote pour vous une petite VM Linux ; le client docker de votre terminal parle au daemon qui tourne à l’intérieur. Tout fonctionne de façon transparente, mais deux conséquences se rappellent régulièrement à vous : les entrées-sorties sur les fichiers partagés avec l’hôte sont plus lentes, et la mémoire allouée à la VM est un plafond global.
Sur macOS, l’installation passe par le paquet .dmg téléchargé depuis docs.docker.com/desktop/install/mac-install, ou par Homebrew :
brew install --cask docker
# Puis lancer l'application Docker une premiere fois : c'est elle
# qui installe le daemon et demarre la VM.
docker version
Prenez garde à l’architecture : sur les Mac Apple Silicon (M1 et suivants), le processeur est arm64. Une image publiée uniquement pour amd64 sera émulée, lentement, ou refusera de démarrer. On force l’architecture au besoin :
# Voir l'architecture du daemon
docker info --format '{{.Architecture}}'
# Forcer une plateforme, au prix de l'emulation
docker run --rm --platform linux/amd64 alpine:3.20 uname -m
Sur Windows, la bonne configuration est WSL2 (Windows Subsystem for Linux version 2), qui fournit un vrai noyau Linux. L’ancien mode « Hyper-V » de Docker Desktop est à éviter, et le mode « conteneurs Windows » répond à un besoin différent (images Windows Server).
# Dans PowerShell en administrateur : installe WSL2 et une Ubuntu par defaut
wsl --install
# S'assurer que la version 2 est celle utilisee par defaut
wsl --set-default-version 2
# Verifier : la colonne VERSION doit afficher 2
wsl -l -v
Installez ensuite Docker Desktop, puis activez dans ses réglages Settings > Resources > WSL Integration la distribution que vous utilisez. Vous pourrez alors taper vos commandes docker directement depuis le shell Ubuntu.
Un conseil de performance qui change tout sur Windows : travaillez dans le système de fichiers Linux, c’est-à-dire sous /home/vous/projets, et non sous /mnt/c/Users/.... Les fichiers montés depuis le disque Windows traversent une couche de traduction ; un npm install peut y être dix fois plus lent.
Vérifier que l’installation est saine
Trois commandes suffisent, et chacune répond à une question différente.
# 1. Le client et le daemon se parlent-ils, et en quelle version ?
# Si la section "Server" manque, le daemon est injoignable.
docker version
# 2. Etat detaille : pilote de stockage, nombre de conteneurs, memoire
docker info
# 3. Le chemin complet fonctionne-t-il : pull depuis un registre + execution
docker run --rm hello-world
La troisième est le vrai test de bout en bout : elle valide la résolution DNS, l’accès au registre, l’écriture dans le cache local et la création d’un conteneur. Le --rm supprime le conteneur dès sa sortie — un réflexe à prendre pour tout conteneur jetable, sinon ils s’accumulent.
Anatomie de docker run
docker run est la commande la plus utilisée et la plus dense. Elle enchaîne en réalité trois opérations : télécharger l’image si elle est absente, créer un conteneur, le démarrer.
docker run [OPTIONS] IMAGE [COMMANDE] [ARGUMENTS...]
L’ordre n’est pas négociable : ce qui précède le nom de l’image configure Docker, ce qui le suit est passé au processus dans le conteneur. Placer -p 8080:80 après le nom de l’image ne produit pas une erreur de syntaxe — ça passe -p 8080:80 en argument au programme lancé, qui s’en étonne.
Les options qui comptent, avec ce qu’elles font vraiment :
docker run \
-d \ # detache : rend le terminal, le conteneur tourne en fond
--name api \ # nom stable, sinon Docker en invente un aleatoire
-p 8080:80 \ # publie le port : 8080 sur l'hote -> 80 dans le conteneur
-e LOG_LEVEL=debug \ # variable d'environnement
-v mes-donnees:/data \ # volume nomme monte sur /data
-w /app \ # repertoire de travail initial
--restart unless-stopped \ # relance apres un crash ou un reboot de l'hote
--memory 512m \ # plafond memoire (cgroups)
nginx:1.27-alpine
Deux modes s’opposent et servent des besoins distincts. -d détache : c’est le mode des services. -it combine -i (garder l’entrée standard ouverte) et -t (allouer un pseudo-terminal) : c’est le mode des sessions interactives.
# Une session shell jetable dans une Alpine, supprimee a la sortie
docker run --rm -it alpine:3.20 sh
# Un shell Python temporaire, sans installer Python sur l'hote
docker run --rm -it python:3.12-slim python
# Remplacer la commande par defaut de l'image
docker run --rm nginx:1.27-alpine nginx -v
Cette dernière ligne illustre une idée à retenir : la commande déclarée dans l’image n’est qu’une valeur par défaut, remplaçable au lancement.
Le cycle de vie d’un conteneur
Un conteneur passe par des états, et beaucoup de confusions viennent d’une lecture trop rapide de docker ps.
docker create
(image) ─────────────────────> created
│ docker start
v
docker stop / le processus finit
exited <─────────────────────── running <──> paused
│ │ (pause/unpause)
│ docker start │ docker restart
│ v
└──> docker rm ──> (disparu) running
# Ne montre QUE les conteneurs en cours d'execution
docker ps
# -a montre aussi les conteneurs arretes. C'est la commande a reflexe
# quand "mon conteneur a disparu" : il est la, en statut Exited.
docker ps -a
# Format personnalise, bien plus lisible que la sortie par defaut
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
Le point non intuitif : un conteneur vit aussi longtemps que son processus principal (PID 1). Il ne « contient » pas une machine allumée en attente. Si son processus rend la main, le conteneur passe en Exited, immédiatement.
# Ce conteneur s'arrete instantanement : echo finit son travail.
docker run --name test-court alpine:3.20 echo "bonjour"
docker ps -a --filter name=test-court # Exited (0)
# Celui-la tourne 30 secondes puis sort.
docker run -d --name test-sleep alpine:3.20 sleep 30
C’est l’explication de l’incompréhension classique « mon conteneur s’arrête tout seul » : l’image ne lance aucun service durable, ou le service se met en arrière-plan et rend la main — ce qu’il ne faut jamais faire dans un conteneur.
Les commandes de contrôle :
docker stop api # SIGTERM, puis SIGKILL apres 10 s de grace
docker stop -t 30 api # allonger le delai de grace a 30 s
docker kill api # SIGKILL immediat, aucune chance de finir proprement
docker start api # redemarre un conteneur existant (etat disque conserve)
docker restart api
docker rm api # supprime le conteneur arrete, et sa couche d'ecriture
docker rm -f api # arrete et supprime d'un coup
La différence entre stop et kill n’est pas cosmétique. stop envoie SIGTERM, laissant à l’application le temps de fermer ses connexions et de vider ses tampons ; kill coupe net, avec le risque de corrompre des données en cours d’écriture. Une application conteneurisée correctement doit intercepter SIGTERM.
Entrer dans un conteneur et l’observer
Quand un service ne répond pas, l’instinct est de regarder à l’intérieur. Trois outils, dans cet ordre.
D’abord les journaux, car ils suffisent la plupart du temps. Docker capture la sortie standard et la sortie d’erreur du processus principal.
docker logs api # tout depuis le demarrage
docker logs -f api # suivre en direct (comme tail -f)
docker logs --tail 50 api # les 50 dernieres lignes
docker logs --since 10m api # les 10 dernieres minutes
docker logs --timestamps api # avec horodatage
Corollaire capital : une application conteneurisée doit écrire ses journaux sur la sortie standard, pas dans un fichier interne. Sinon docker logs est vide et ses journaux meurent avec le conteneur.
Ensuite, ouvrir un shell dans un conteneur qui tourne :
# bash quand l'image en dispose (Debian, Ubuntu)
docker exec -it api bash
# sh sur les images Alpine et les images minimales : bash n'y est pas
docker exec -it api sh
# Executer une commande unique sans session interactive
docker exec api ls -la /etc/nginx
docker exec api env
Notez bien la distinction : docker exec ajoute un processus dans un conteneur déjà en cours d’exécution, alors que docker run en crée un nouveau. Et tout ce que vous modifiez pendant cette session vit dans la couche d’écriture du conteneur : ce sera perdu à sa suppression. Ce mode sert à diagnostiquer, jamais à configurer durablement.
Enfin, l’inspection et les mesures :
# Toute la configuration du conteneur, en JSON
docker inspect api
# Cibler une valeur precise avec un modele Go
docker inspect --format '{{.State.Status}}' api
docker inspect --format '{{.State.ExitCode}}' api
docker inspect --format '{{range $p, $c := .NetworkSettings.Ports}}{{$p}} {{end}}' api
# Consommation en direct (CPU, memoire, reseau, E/S)
docker stats
# Processus tournant dans le conteneur
docker top api
# Fichiers modifies par rapport a l'image (A ajoute, C change, D supprime)
docker diff api
# Copier un fichier dans les deux sens
docker cp api:/etc/nginx/nginx.conf ./nginx.conf
docker cp ./nginx.conf api:/etc/nginx/nginx.conf
Le code de sortie mérite l’attention : 137 signifie presque toujours que le processus a reçu un SIGKILL (128 + 9), souvent parce qu’il a dépassé sa limite de mémoire et que le noyau l’a tué. C’est une information qu’aucun message d’erreur applicatif ne vous donnera.
Nettoyer : Docker remplit le disque en silence
Chaque image téléchargée, chaque conteneur arrêté, chaque couche intermédiaire de build reste sur le disque. Sur un poste de développement actif, cela représente très vite des dizaines de gigaoctets.
# Le bilan : ce que Docker occupe, et ce qui est recuperable
docker system df
# Detail par objet
docker system df -v
Le nettoyage se fait par degrés de brutalité croissante.
# 1. Les conteneurs arretes
docker container prune
# 2. Les images sans nom (les "dangling", <none>), produites par les rebuilds
docker image prune
# 3. Les volumes qu'aucun conteneur n'utilise
# ATTENTION : ce sont vos donnees. Verifiez avant.
docker volume ls
docker volume prune
# 4. Le cache de build, souvent le plus gros poste
docker builder prune
# 5. Tout d'un coup, images non utilisees comprises
docker system prune -a
docker system prune -a est la commande à connaître et à manier avec prudence : elle supprime toutes les images qu’aucun conteneur n’utilise, y compris celles que vous rechargerez demain. Sans -a, elle se limite aux objets réellement orphelins.
Quelques enchaînements pratiques, à comprendre avant de les coller :
# Arreter tous les conteneurs en cours (-q ne renvoie que les identifiants)
docker stop $(docker ps -q)
# Supprimer tous les conteneurs, y compris ceux qui tournent
docker rm -f $(docker ps -aq)
# Supprimer les images d'un depot donne
docker images --filter reference='mon-app' -q | xargs -r docker rmi
Une remarque pour macOS et Windows : l’espace occupé par la VM de Docker Desktop ne se rend pas toujours au système hôte après un prune. Le fichier disque de la VM reste dimensionné à son pic. Docker Desktop propose une action de récupération d’espace dans ses réglages.
À retenir
- Sur Linux, installez depuis le dépôt officiel Docker, jamais depuis le paquet de la distribution, et n’oubliez pas
docker-buildx-pluginetdocker-compose-plugin: sans eux,docker composen’existe pas. - L’erreur
permission deniedsur/var/run/docker.sockse règle parsudo usermod -aG docker $USERsuivi d’une nouvelle session. Sachez que cela équivaut à un accès root sur la machine. - Sur macOS et Windows, Docker s’appuie sur une VM Linux. Sur Windows, utilisez WSL2 et rangez vos projets dans le système de fichiers Linux, pas sous
/mnt/c, sous peine de lenteurs importantes. - Un conteneur vit exactement aussi longtemps que son processus PID 1. « Il s’arrête tout seul » veut presque toujours dire que ce processus a rendu la main.
docker ps -amontre les conteneurs arrêtés,docker psnon. - Le quotidien tient dans huit commandes :
run,ps -a,logs -f,exec -it,stop,rm,inspect,system df. Prenez le réflexe--rmpour tout conteneur jetable. - Surveillez
docker system dfrégulièrement : les images, volumes et caches de build remplissent un disque sans prévenir.
Conseil : lancez
docker run --rm -it alpine:3.20 shet explorez librement. Un conteneur jetable est l’environnement d’expérimentation le plus sûr qui existe :exit, et il n’en reste rien.
Commentaires
Les commentaires sont alimentés par GitHub Discussions
Connectez-vous avec GitHub pour participer à la discussion