You are currently viewing Images Docker : tout comprendre pour bien les utiliser

Images Docker : tout comprendre pour bien les utiliser

  • Auteur/autrice de la publication :
  • Post category:DevOps

Dans cet article

  • Une image Docker est un modèle immuable en couches qui contient tout le nécessaire pour exécuter une application
  • Docker Hub héberge plus de 100 000 images officielles prêtes à l’emploi gratuitement
  • La création d’une image personnalisée passe par un Dockerfile en moins de 10 lignes pour les cas simples
  • Les images Alpine réduisent la taille finale jusqu’à 90 % par rapport à une image Ubuntu
  • Le système de couches permet un cache intelligent qui accélère considérablement les builds successifs
  • Les bonnes pratiques de sécurité incluent le scan régulier avec docker scout ou Trivy

Quand j’ai commencé à enseigner Docker à mes étudiants en BTS SIO, la notion d’images Docker était systématiquement celle qui posait le plus de questions. Pourtant, une fois le concept bien compris, tout le reste de l’écosystème Docker devient limpide. Je vous propose dans ce guide de décortiquer ensemble ce que sont réellement les images Docker, comment les trouver, les créer et les optimiser pour vos projets.

Qu’est-ce qu’une image Docker : définition claire

Une image Docker est un package léger, autonome et immuable qui contient tout ce dont une application a besoin pour s’exécuter : le code source, les dépendances, les bibliothèques système, les variables d’environnement et les fichiers de configuration. Pensez-y comme à une recette figée qui décrit exactement l’état d’un système à un instant donné.

Contrairement à une machine virtuelle qui embarque un système d’exploitation complet, une image Docker ne contient que le strict nécessaire. Elle s’appuie sur le noyau Linux de la machine hôte, ce qui explique sa légèreté remarquable. Une image Node.js basée sur Alpine pèse environ 50 Mo, contre plusieurs Go pour une VM équivalente.

Schéma de couches Docker dessiné sur un tableau blanc en salle de cours
Schéma de couches Docker dessiné sur un tableau blanc en salle de cours

En pratique, une image Docker se définit par trois caractéristiques fondamentales :

  • Immuabilité : une fois construite, elle ne change jamais. Toute modification produit une nouvelle image.
  • Portabilité : elle fonctionne de manière identique sur n’importe quelle machine disposant de Docker.
  • Reproductibilité : à partir du même Dockerfile, vous obtenez toujours le même résultat.

Si vous débutez avec Docker, je vous recommande de consulter d’abord mon tutoriel Docker pour les débutants qui pose les bases de l’écosystème complet.

Image et conteneur : comprendre la différence

La confusion entre image et conteneur est la plus fréquente chez mes étudiants. L’analogie que j’utilise en cours fonctionne à chaque fois : l’image est la classe, le conteneur est l’instance. En programmation orientée objet, vous définissez une classe une seule fois, puis vous créez autant d’objets que nécessaire à partir de cette classe.

Le mécanisme est identique avec Docker. À partir d’une seule image nginx:alpine, vous pouvez lancer 10, 50 ou 100 conteneurs simultanés. Chaque conteneur dispose de son propre espace de stockage en écriture (une couche supplémentaire), tandis que l’image sous-jacente reste intacte et partagée entre tous les conteneurs.

Critère Image Docker Conteneur Docker
État Immuable (lecture seule) Modifiable (lecture/écriture)
Durée de vie Permanente jusqu’à suppression Éphémère par conception
Stockage Registry ou local Mémoire + couche écriture
Création docker build / docker pull docker run / docker create
Analogie Classe / Modèle / Recette Instance / Objet / Plat servi
Partage Partageable via registry Propre à la machine hôte

Cette distinction est cruciale pour comprendre les workflows de déploiement modernes. Dans un pipeline CI/CD, vous construisez l’image une seule fois, vous la poussez dans un registry, puis chaque environnement (staging, production) lance des conteneurs à partir de cette même image. C’est ce qui garantit la cohérence entre vos environnements, un sujet que je développe avec mes étudiants en développement web full stack.

Structure en couches : comment fonctionne une image

Le véritable génie technique des images Docker réside dans leur système de couches (layers). Chaque instruction de votre Dockerfile crée une nouvelle couche qui s’empile sur la précédente. Ce mécanisme s’appuie sur un système de fichiers en union (UnionFS) qui fusionne toutes les couches en un seul système de fichiers cohérent.

Prenons un exemple concret. Un Dockerfile typique pour une application Node.js génère les couches suivantes :

FROM node:20-alpine        # Couche 1 : système Alpine + Node.js (~50 Mo)
WORKDIR /app               # Couche 2 : création du répertoire (quelques octets)
COPY package*.json ./      # Couche 3 : fichiers de dépendances (~5 Ko)
RUN npm ci                 # Couche 4 : node_modules (~80 Mo)
COPY . .                   # Couche 5 : code source (~2 Mo)
RUN npm run build          # Couche 6 : fichiers compilés (~10 Mo)

L’avantage majeur de ce système est le cache. Si vous modifiez uniquement votre code source (couche 5), Docker réutilise les couches 1 à 4 depuis le cache. Le rebuild ne prend que quelques secondes au lieu de plusieurs minutes. C’est pourquoi l’ordre des instructions dans un Dockerfile a une importance capitale : placez toujours les éléments les moins modifiés en premier.

Chaque couche est identifiée par un hash SHA256 unique. Quand deux images partagent les mêmes couches de base (ce qui arrive fréquemment avec les images officielles), Docker ne stocke ces couches qu’une seule fois sur le disque. Sur un serveur hébergeant 20 conteneurs Node.js, la couche Alpine de base n’existe qu’en un seul exemplaire.

Rédaction d'un Dockerfile dans un éditeur de code sur un poste de travail
Rédaction d’un Dockerfile dans un éditeur de code sur un poste de travail

Où trouver les images Docker

Les images Docker sont stockées et distribuées via des registries (registres). Le plus connu et le plus utilisé est Docker Hub, le registry public officiel qui héberge des millions d’images. Mais ce n’est pas la seule option.

Voici les principales sources pour trouver des images Docker :

  • Docker Hub : le registry par défaut. Les images préfixées « Official Image » sont maintenues par Docker et les éditeurs logiciels. Plus de 100 000 images officielles disponibles.
  • GitHub Container Registry (ghcr.io) : intégré à GitHub, idéal pour les projets open source et les pipelines GitHub Actions.
  • Amazon ECR Public : le registry public d’AWS avec des images optimisées pour les services cloud.
  • Google Container Registry (gcr.io) : les images officielles de Google, notamment pour Kubernetes.
  • Registries privés : Harbor, GitLab Container Registry, ou votre propre registry pour les images internes.

Pour rechercher une image depuis le terminal, utilisez la commande :

docker search nginx
docker search --filter is-official=true python

Je recommande systématiquement à mes étudiants de privilégier les images officielles ou vérifiées. Une image communautaire peut contenir du code malveillant ou des vulnérabilités non corrigées. Vérifiez toujours le nombre de téléchargements, la date de dernière mise à jour et la présence d’un Dockerfile public.

Créer une image Docker avec un Dockerfile

La création d’une image Docker personnalisée passe par la rédaction d’un Dockerfile, un fichier texte qui décrit étape par étape la construction de votre image. Voici un exemple complet pour une application web Python avec Flask :

# Image de base officielle Python sur Alpine
FROM python:3.12-alpine

# Métadonnées
LABEL maintainer="[email protected]"
LABEL description="Application Flask de démonstration"

# Répertoire de travail
WORKDIR /app

# Installation des dépendances système
RUN apk add --no-cache gcc musl-dev

# Copie et installation des dépendances Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copie du code source
COPY . .

# Exposition du port
EXPOSE 5000

# Utilisateur non-root pour la sécurité
RUN adduser -D appuser
USER appuser

# Commande de démarrage
CMD ["python", "app.py"]

Pour construire cette image, exécutez :

docker build -t mon-app-flask:1.0 .
docker build -t mon-app-flask:latest .

Le flag -t attribue un tag à votre image (nom:version). Le point final indique que le contexte de build est le répertoire courant. Docker envoie tous les fichiers de ce répertoire au daemon pour la construction, d’où l’importance du fichier .dockerignore pour exclure les fichiers inutiles (node_modules, .git, etc.).

Les instructions Dockerfile les plus courantes sont :

  • FROM : définit l’image de base (obligatoire, toujours en première ligne)
  • RUN : exécute une commande pendant le build
  • COPY / ADD : copie des fichiers dans l’image
  • ENV : définit des variables d’environnement
  • EXPOSE : documente le port utilisé par l’application
  • CMD / ENTRYPOINT : définit la commande exécutée au démarrage du conteneur

Pour aller plus loin sur l’intégration de Docker dans un workflow de développement complet, consultez mon article sur le développement d’applications web sur mesure.

Commandes essentielles pour gérer vos images

Maîtriser les commandes de gestion des images Docker est indispensable au quotidien. Voici les commandes que j’utilise le plus fréquemment et que je considère comme le kit de survie minimum :

# Télécharger une image depuis un registry
docker pull nginx:alpine
docker pull python:3.12-slim

# Lister les images locales
docker images
docker image ls --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

# Inspecter une image (métadonnées, couches, configuration)
docker inspect nginx:alpine
docker history nginx:alpine

# Taguer une image pour un registry distant
docker tag mon-app:latest registry.exemple.fr/mon-app:1.0

# Pousser une image vers un registry
docker push registry.exemple.fr/mon-app:1.0

# Supprimer une image locale
docker rmi nginx:alpine
docker image prune -a  # Supprime toutes les images non utilisées

# Exporter/importer une image (sans registry)
docker save mon-app:latest -o mon-app.tar
docker load -i mon-app.tar

La commande docker image prune est particulièrement utile en développement. Après plusieurs builds successifs, les images intermédiaires (appelées « dangling images ») s’accumulent et consomment de l’espace disque. Sur mes postes de développement, je lance régulièrement un nettoyage qui libère souvent plusieurs Go.

Pour visualiser l’espace consommé par Docker sur votre machine :

docker system df
# TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
# Images          45        12        8.2GB     5.1GB (62%)
# Containers      15        3         250MB     200MB (80%)
# Build Cache     89        0         2.1GB     2.1GB

Quelle image de base choisir selon votre projet

Le choix de l’image de base est une décision architecturale qui impacte la taille, la sécurité et la performance de vos conteneurs. Il n’existe pas de « meilleure image Docker » universelle, mais des choix adaptés à chaque contexte.

Image de base Taille approximative Cas d’usage recommandé Avantages
alpine ~5 Mo Production, microservices Ultra-légère, surface d’attaque minimale
slim (Debian) ~80 Mo Applications nécessitant glibc Bon compromis taille/compatibilité
ubuntu ~75 Mo Développement, CI/CD Familier, large écosystème de paquets
debian (bookworm) ~120 Mo Applications complexes Stabilité, compatibilité maximale
distroless (Google) ~20 Mo Production sécurisée Pas de shell, surface d’attaque quasi nulle
scratch 0 Mo Binaires Go/Rust compilés Image la plus petite possible

Infrastructure serveur hébergeant des conteneurs Docker en production
Infrastructure serveur hébergeant des conteneurs Docker en production

Mon conseil pour les étudiants : commencez avec les variantes slim qui offrent un excellent compromis. Passez à Alpine une fois que vous maîtrisez les subtilités de musl (la bibliothèque C alternative utilisée par Alpine). Pour les applications compilées en Go ou Rust, l’image scratch produit des conteneurs incroyablement légers, parfois sous les 10 Mo.

En production, les images distroless de Google représentent l’état de l’art en matière de sécurité. Elles ne contiennent ni shell, ni gestionnaire de paquets, ni utilitaires système : uniquement votre application et ses dépendances runtime.

Pour les projets qui utilisent Docker Compose avec plusieurs services, le choix cohérent des images de base facilite la maintenance. J’aborde ce sujet dans mon guide Docker complet.

Optimisation et sécurité des images Docker

Une image Docker mal construite peut peser plusieurs Go et contenir des dizaines de vulnérabilités. L’optimisation n’est pas un luxe : c’est une nécessité opérationnelle qui impacte directement vos temps de déploiement et votre posture de sécurité.

Multi-stage builds

La technique du multi-stage build est la plus efficace pour réduire la taille de vos images. Le principe : utiliser une première image volumineuse pour la compilation, puis copier uniquement les artefacts nécessaires dans une image finale légère.

# Étape 1 : compilation
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Étape 2 : image de production
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Résultat : l’image finale ne contient que Nginx et vos fichiers statiques compilés. Les outils de build (Node.js, npm, les node_modules) restent dans l’étape intermédiaire et ne sont jamais inclus dans l’image finale. On passe typiquement de 1,2 Go à moins de 30 Mo.

Scanner les vulnérabilités

Je recommande de scanner systématiquement vos images avec docker scout (intégré à Docker Desktop) ou Trivy (open source) :

# Avec Docker Scout
docker scout cves mon-app:latest

# Avec Trivy
trivy image mon-app:latest

Intégrez ces scans dans votre pipeline CI/CD pour bloquer automatiquement les déploiements contenant des vulnérabilités critiques. C’est un principe fondamental de la sécurité informatique appliqué aux conteneurs.

Réduire la surface d’attaque

  • Exécutez vos applications avec un utilisateur non-root (instruction USER)
  • Utilisez un fichier .dockerignore pour exclure secrets, fichiers .env et répertoires .git
  • Mettez à jour régulièrement vos images de base pour bénéficier des correctifs de sécurité
  • Préférez COPY à ADD sauf si vous avez besoin de la décompression automatique

Pour approfondir les questions de sécurité dans un contexte professionnel, consultez mon guide sur l’audit de sécurité informatique.

Bonnes pratiques pour vos images en production

Après plusieurs années à déployer des images Docker en production et à former des étudiants, voici les règles d’or que j’applique systématiquement :

1. Toujours taguer explicitement vos images. N’utilisez jamais le tag latest en production. Préférez des tags sémantiques (mon-app:2.1.3) ou basés sur le commit Git (mon-app:a1b2c3d). Cela garantit la traçabilité et facilite les rollbacks.

2. Un processus par conteneur. Chaque conteneur doit exécuter un seul processus principal. Si votre application a besoin d’un serveur web et d’une base de données, utilisez deux conteneurs orchestrés avec Docker Compose.

3. Optimisez l’ordre des couches. Placez les instructions qui changent rarement en haut du Dockerfile (installation des dépendances système) et celles qui changent souvent en bas (copie du code source). Cela maximise l’utilisation du cache.

4. Combinez les commandes RUN. Chaque instruction RUN crée une couche. Combinez les commandes avec && et nettoyez les caches dans la même instruction :

RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    rm -rf /var/lib/apt/lists/*

5. Utilisez des fichiers .dockerignore exhaustifs. Excluez systématiquement : .git, node_modules, __pycache__, .env, les fichiers de logs et les artefacts de build locaux.

6. Documentez avec des LABEL. Ajoutez des métadonnées à vos images (mainteneur, version, description) pour faciliter la gestion à grande échelle.

7. Testez vos images localement. Avant de pousser une image, vérifiez qu’elle démarre correctement, que les health checks passent et que les ports sont accessibles. Les outils comme container-structure-test de Google automatisent ces vérifications.

Ces pratiques s’inscrivent dans une démarche DevOps plus large. Si vous envisagez une carrière dans ce domaine, la formation informatique à distance offre des parcours adaptés pour monter en compétence progressivement.

À retenir

  • Privilégiez toujours les images officielles de Docker Hub comme base de vos projets
  • Utilisez des multi-stage builds pour réduire la taille de vos images de 80 à 90 %
  • Scannez vos images avec docker scout ou Trivy avant chaque déploiement en production
  • Taguez explicitement vos images avec des versions sémantiques, jamais uniquement « latest »
  • Exécutez vos conteneurs avec un utilisateur non-root pour limiter la surface d’attaque

Questions fréquentes


Qu’est-ce qu’une image Docker ?

Une image Docker est un package immuable et autonome qui contient tout le nécessaire pour exécuter une application : code source, dépendances, bibliothèques système et configuration. Elle fonctionne comme un modèle à partir duquel on lance des conteneurs. Construite en couches successives via un Dockerfile, elle garantit que l’application s’exécute de manière identique sur n’importe quel environnement disposant de Docker.


Où trouver les images Docker ?

Le principal registry public est Docker Hub (hub.docker.com) qui héberge plus de 100 000 images officielles maintenues par les éditeurs logiciels. D’autres options existent : GitHub Container Registry (ghcr.io), Amazon ECR Public, Google Container Registry. Pour les projets d’entreprise, des registries privés comme Harbor ou GitLab Container Registry permettent de stocker vos images internes de manière sécurisée.


Comment faire une image Docker ?

Pour créer une image Docker, rédigez un fichier nommé Dockerfile qui décrit les étapes de construction : image de base (FROM), installation des dépendances (RUN), copie du code (COPY) et commande de démarrage (CMD). Lancez ensuite la commande « docker build -t nom-image:tag . » depuis le répertoire contenant le Dockerfile. L’image est alors disponible localement et peut être poussée vers un registry avec « docker push ».


Quelle est la meilleure image Docker ?

Il n’existe pas de meilleure image universelle. Le choix dépend du contexte : Alpine (~5 Mo) pour les microservices en production, les variantes slim (~80 Mo) pour un bon compromis taille/compatibilité, distroless pour la sécurité maximale, et scratch (0 Mo) pour les binaires compilés Go ou Rust. Pour débuter, les images slim officielles de votre langage constituent le meilleur point de départ.


Comment réduire la taille d’une image Docker ?

Les techniques les plus efficaces sont : utiliser des multi-stage builds pour séparer la compilation de l’exécution, choisir une image de base légère (Alpine ou slim), combiner les instructions RUN avec && pour limiter le nombre de couches, nettoyer les caches dans la même instruction RUN, et utiliser un .dockerignore strict pour exclure les fichiers inutiles du contexte de build.


Quelle différence entre docker pull et docker build ?

La commande docker pull télécharge une image existante depuis un registry distant (Docker Hub par exemple) vers votre machine locale. La commande docker build crée une nouvelle image à partir d’un Dockerfile que vous avez rédigé. En pratique, docker build exécute souvent un docker pull implicite pour récupérer l’image de base spécifiée dans l’instruction FROM de votre Dockerfile.


Lucie Moreau
Lucie Moreau

Formatrice IT indépendante depuis 2016, ancienne étudiante BTS SIO SLAM. 6 ans d'expérience en entreprise.

Lucie Moreau

Formatrice IT indépendante depuis 2016, ancienne étudiante BTS SIO SLAM. 6 ans d'expérience en entreprise.