Docker pour les développeurs : Conteneurs, Images et Compose

· 12 min de lecture

Table des matières

Comprendre Docker : Pourquoi c'est important

Docker a fondamentalement changé la façon dont les développeurs construisent, livrent et exécutent des applications. Avant Docker, la configuration des environnements de développement était un cauchemar de conflits de dépendances, d'incompatibilités de versions et du fameux problème « ça marche sur ma machine ».

Docker résout ce problème en empaquetant votre application avec tout ce dont elle a besoin pour fonctionner — code, environnement d'exécution, outils système, bibliothèques et paramètres — dans une unité standardisée appelée conteneur. Ce conteneur s'exécute de manière identique sur votre ordinateur portable, la machine de votre collègue et les serveurs de production.

Les avantages sont immédiats et tangibles :

Pour les développeurs, Docker signifie que vous pouvez démarrer une pile d'applications complète — serveur web, base de données, cache, file d'attente de messages — avec une seule commande. Plus besoin de passer des heures à installer PostgreSQL ou à déboguer des problèmes de configuration Redis.

Concepts fondamentaux expliqués

Comprendre les concepts fondamentaux de Docker est essentiel avant de plonger dans l'utilisation pratique. Ces éléments de base fonctionnent ensemble pour créer l'écosystème Docker.

Concept Ce que c'est Analogie Caractéristiques clés
Image Modèle en lecture seule avec app + dépendances Une définition de classe en POO Immuable, en couches, partageable
Conteneur Instance en cours d'exécution d'une image Un objet (instance de classe) Isolé, éphémère, sans état
Dockerfile Instructions pour construire une image Une recette ou un plan Fichier texte, sous contrôle de version
Volume Stockage persistant en dehors du conteneur Un disque dur externe Survit à la suppression du conteneur
Réseau Communication entre conteneurs Un réseau local (LAN) Isolé, configurable, sécurisé
Registre Stockage pour les images (Docker Hub) npm/PyPI pour les conteneurs Public ou privé, versionné

Images vs Conteneurs : La distinction critique

C'est là que de nombreux débutants se perdent. Une image est un instantané statique — considérez-la comme un modèle figé. Un conteneur est ce que vous obtenez lorsque vous exécutez cette image — c'est un processus en direct et en cours d'exécution.

Vous pouvez créer un nombre illimité de conteneurs à partir d'une seule image, tout comme vous pouvez créer plusieurs objets à partir d'une classe. Chaque conteneur est isolé des autres, même s'ils sont tous basés sur la même image.

Conseil de pro : Les images sont construites en couches. Chaque instruction dans votre Dockerfile crée une nouvelle couche. Docker met en cache ces couches, donc reconstruire une image ne reconstruit que les couches qui ont changé. Cela rend les constructions incroyablement rapides.

Volumes : Résoudre le problème de persistance

Les conteneurs sont éphémères par conception — lorsque vous supprimez un conteneur, tout ce qu'il contient disparaît. C'est excellent pour les applications sans état mais problématique pour les bases de données ou toute donnée que vous devez conserver.

Les volumes résolvent ce problème en stockant les données en dehors du système de fichiers du conteneur. Les données persistent même lorsque les conteneurs sont supprimés et recréés. Il existe trois types de montages :

Anatomie et structure d'un Dockerfile

Un Dockerfile est un document texte contenant des instructions pour construire une image Docker. Chaque instruction crée une couche dans l'image, et Docker met en cache ces couches pour plus d'efficacité.

Voici une répartition des instructions Dockerfile les plus courantes :

Instruction Objectif Exemple Meilleure pratique
FROM Image de base à partir de laquelle construire FROM node:22-alpine Utiliser des versions spécifiques, préférer alpine
WORKDIR Définir le répertoire de travail WORKDIR /app Utiliser des chemins absolus
COPY Copier des fichiers de l'hôte vers l'image COPY package.json . Copier d'abord les dépendances pour la mise en cache
RUN Exécuter des commandes pendant la construction RUN npm install Enchaîner les commandes avec && pour réduire les couches
EXPOSE Documenter le port sur lequel l'app écoute EXPOSE 3000 Documentation uniquement, ne publie pas le port
ENV Définir des variables d'environnement ENV NODE_ENV=production Utiliser pour la configuration
USER Définir l'utilisateur pour les commandes suivantes USER node Ne jamais exécuter en tant que root en production
CMD Commande par défaut au démarrage du conteneur CMD ["node", "server.js"] Utiliser le format tableau JSON

Comprendre la mise en cache des couches

Docker construit les images couche par couche, de haut en bas. Chaque instruction crée une nouvelle couche. Si une couche n'a pas changé, Docker réutilise la version mise en cache au lieu de la reconstruire.

C'est pourquoi vous devriez structurer votre Dockerfile pour placer les instructions qui changent rarement en haut et celles qui changent fréquemment en bas. Par exemple, vos dépendances changent moins souvent que votre code source, donc installez les dépendances avant de copier les fichiers sources.

# Mauvais : Copie tout d'abord, puis installe
COPY . .
RUN npm install

# Bon : Installe d'abord les dépendances, exploite le cache
COPY package*.json ./
RUN npm install
COPY . .

Meilleures pratiques pour les Dockerfiles

Écrire des Dockerfiles efficaces est un art. Voici un exemple prêt pour la production qui démontre plusieurs meilleures pratiques :

# Construction multi-étapes : étape de construction
FROM node:22-alpine AS builder
WORKDIR /app

# Copier d'abord les fichiers de dépendances pour une meilleure mise en cache
COPY package*.json ./
RUN npm ci --production

# Copier le code source et construire
COPY . .
RUN npm run build

# Construction multi-étapes : étape de production
FROM node:22-alpine
WORKDIR /app

# Copier uniquement ce qui est nécessaire depuis le builder
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./

# Sécurité : exécuter en tant qu'utilisateur non-root
USER node

# Documenter le port (ne le publie pas réellement)
EXPOSE 3000

# Vérification de santé pour l'orchestration de conteneurs
HEALTHCHECK --interval=30s --timeout=3s \
  CMD node healthcheck.js || exit 1

# Démarrer l'application
CMD ["node", "dist/server.js"]

Constructions multi-étapes : Réduction spectaculaire de la taille

Les constructions multi-étapes vous permettent d'utiliser plusieurs instructions FROM dans un seul Dockerfile. Chaque FROM démarre une nouvelle étape, et vous pouvez copier des artefacts des étapes précédentes.

La magie se produit parce que seule l'étape finale devient votre image. Les outils de construction, les compilateurs et les fichiers intermédiaires restent dans les étapes précédentes et n'arrivent jamais en production. Cela peut réduire la taille des images de 10 fois ou plus.

Conseil rapide : Nommez vos étapes avec AS builder afin de pouvoir les référencer plus tard avec COPY --from=builder. Cela rend votre Dockerfile plus lisible et maintenable.

Images Alpine : Petites mais puissantes

Alpine Linux est une distribution Linux minimale qui ne fait que 5 Mo. Comparez cela aux images basées sur Ubuntu à plus de 900 Mo. Pour la plupart des applications, Alpine fournit tout ce dont vous avez besoin.

Le compromis est qu'Alpine utilise musl libc au lieu de glibc, ce qui peut occasionnellement causer des problèmes de compatibilité avec les binaires précompilés. Pour 95 % des cas d'utilisation, Alpine fonctionne parfaitement et réduit considérablement la taille de l'image, le temps de téléchargement et la surface d'attaque.

Le fichier .dockerignore

Tout comme .gitignore, un fichier .dockerignore indique à Docker quels fichiers exclure lors de la construction d'images. Cela accélère les constructions et réduit la taille de l'image.

# Exemple de .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.env.local
dist
coverage
.vscode
.idea
*.log
.DS_Store

Meilleures pratiques de sécurité

La sécurité doit être intégrée dans vos Dockerfiles dès le départ :

Besoin d'aide pour générer des Dockerfiles optimisés ? Essayez notre outil Générateur de Dockerfile.

Commandes Docker essentielles

Maîtriser ces commandes couvrira 90 % de votre utilisation quotidienne de Docker. Chaque commande inclut des exemples pratiques et des drapeaux courants.

Construction et exécution

# Construire une image à partir du Dockerfile dans le répertoire actuel
docker build -t myapp:1.0 .

# Construire avec des arguments de construction
docker build --build-arg NODE_ENV=production -t myapp:1.0 .

# Construire sans cache (forcer la reconstruction)
docker build --no-cache -t myapp:1.0 .

# Exécuter un conteneur en mode détaché
docker run -d -p 3000:3000 --name myapp myapp:1.0

# Exécuter avec des variables d'environnement
docker run -d -p 3000:3000 -e NODE_ENV=production --name myapp myapp:1.0

# Exécuter avec montage de volume
docker run -d -p 3000:3000 -v $(pwd)/data:/app/data --name myapp myapp:1.0

# Exécuter de manière interactive avec accès au shell
docker run -it --rm myapp:1.0 sh

Gestion des conteneurs

# Lister les conteneurs en cours d'exécution
docker ps

# Lister tous les conteneurs (y compris arrêtés)
docker ps -a

# Afficher les journaux du conteneur
docker logs myapp

# Suivre les journaux en temps réel
docker logs -f myapp

# Afficher les 100 dernières lignes des journaux
docker logs --tail 100 myapp

# Exécuter une commande dans un conteneur en cours d'exécution
docker exec -it myapp sh

# Exécuter une commande ponctuelle
docker exec myapp npm test

# Arrêter un conteneur gracieusement
docker stop myapp

# Tuer un conteneur immédiatement
docker kill myapp

# Supprimer un conteneur arrêté
docker rm myapp

# Arrêter et supprimer en une seule commande
docker stop myapp && docker rm myapp

# Supprimer tous les conteneurs arrêtés
docker container prune

Travailler avec les images

# Lister toutes les images
docker images

# Lister les images avec un format personnalisé
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

# Supprimer une image
docker rmi myapp:1.0

# Supprimer toutes les images inutilisées
docker image prune -a

# Étiqueter une image
docker tag myapp:1.0 myapp:latest

# Pousser vers le registre
docker push myregistry.com/myapp:1.0

# Tirer depuis le registre
docker pull myregistry.com/myapp:1.0

# Sauvegarder l'image dans un fichier tar
docker save myapp:1.0 > myapp.tar

# Charger l'image depuis un fichier tar
docker load < myapp.tar

Gestion du système

# Afficher l'utilisation du disque
docker system df

# Supprimer toutes les données inutilisées (conteneurs, réseaux, images, cache)
docker system prune -a

# Afficher les statistiques des conteneurs en temps réel
docker stats

# Inspecter les détails du conteneur (sortie JSON)
docker inspect myapp

# Afficher les processus du conteneur
docker top myapp

Conseil de pro : Ajoutez le drapeau --rm lors de l'exécution de conteneurs pour les tests. Cela supprime automatiquement le conteneur lorsqu'il s'arrête, gardant votre système propre : docker run --rm -it myapp:1.0 sh

Docker Compose pour les applications multi-conteneurs

Docker Compose est un outil pour définir et exécuter des applications multi-conteneurs. Au lieu d'exécuter plusieurs commandes docker run, vous définissez tout dans un seul fichier YAML.

C'est essentiel pour les applications modernes qui se composent généralement de plusieurs services : un serveur web, une base de données, un cache, une file d'attente de messages, et plus encore.

Exemple complet de Docker Compose

# docker-compose.yml
version: '3.8'

services:
  # W