Une image Docker, c'est un modèle figé qui contient tout le nécessaire pour exécuter une application : code, dépendances, configuration et système de fichiers. Chaque image est construite couche par couche, et comprendre cette architecture est la clé pour créer des images optimisées, légères et rapides à builder.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Comprendre le système de couches et comment chaque instruction Dockerfile crée une nouvelle layer
- Explorer la structure interne d'une image (manifest.json, blobs, config)
- Maîtriser le cache de build pour accélérer vos pipelines CI/CD
- Analyser une image existante pour comprendre sa composition
Prérequis : avoir lu l'introduction à la conteneurisation et connaître les bases de Docker.
Comment est construite une image de conteneur ?
Section intitulée « Comment est construite une image de conteneur ? »Pour bien comprendre ce qu’on fait quand on écrit un Dockerfile, il faut
savoir ce que Docker fabrique réellement à chaque instruction. Construire une
image Docker, ce n’est pas juste enchaîner des commandes. C’est empiler des
couches, chacune résultant d’une instruction, à partir d’une image de
base.
Tout commence par une image de base
Section intitulée « Tout commence par une image de base »L’image de base, c’est le point de départ. Elle peut être :
- Une distribution minimaliste comme
alpine - Une image préconfigurée comme
python:3.11-slimounginx - Ou même
scratch, qui signifie... aucune base du tout
| Type d'image | Exemple | Taille typique | Shell inclus | Cas d'usage |
|---|---|---|---|---|
| Standard | python:3.12 | 900+ Mo | ✅ Oui | Dev, debug |
| Slim | python:3.12-slim | ~150 Mo | ✅ Oui | Production générale |
| Alpine | python:3.12-alpine | ~50 Mo | ✅ Oui (busybox) | Contraintes de taille |
| Distroless | gcr.io/distroless/python3 | ~20 Mo | ❌ Non | Sécurité maximale |
| Chainguard | cgr.dev/chainguard/python | ~30 Mo | ❌ Non | Sécurité + zero CVE |
On construit une nouvelle image à partir de cette base
Section intitulée « On construit une nouvelle image à partir de cette base »Pour construire une image, on va ajouter des couches à cette image de base.
Chaque couche est le résultat d’une instruction dans le Dockerfile. Ces
instructions sont exécutées dans l’ordre, et celles qui modifient le système
de fichiers (FROM, RUN, COPY, ADD) créent une nouvelle couche.
Qu'est-ce qu'un Dockerfile ?
Section intitulée « Qu'est-ce qu'un Dockerfile ? »Un Dockerfile est un fichier texte qui définit une suite d'instructions qui vont permettre d'installer tous les éléments nécessaires à l'exécution de notre application.
Nous avons à notre disposition une dizaine d'instructions. Si peu ? Oui et c'est suffisant. À cela s'ajoute aussi la possibilité de mettre des commentaires.
Prenons un exemple simple :
FROM debian:bullseye-slim@sha256:cba95a21c96c1f5fc2470081829363eed57706634f7dc26e8c6712934303d57aCette instruction dit à Docker : « télécharge cette image de base depuis un registre » (par défaut Docker Hub). C’est la première couche, sur laquelle on va construire tout le reste.
Chaque instruction crée une nouvelle couche
Section intitulée « Chaque instruction crée une nouvelle couche »À chaque ligne du Dockerfile, Docker va :
- Créer un conteneur temporaire
- Exécuter l’instruction (par exemple une commande
RUN) - Capturer la différence de fichiers
- La stocker comme une nouvelle couche (en tar.gz dans les blobs)
Prenons ce Dockerfile :
FROM python:3.11-slim@sha256:db3ff2e1800a8581e2c48a27c3995339d47bdf046da21c7627accd3d51053a93COPY . /appRUN pip install --no-cache-dir -r /app/requirements.txtVoici ce que fait Docker :
- 1re couche : image de base
python:3.11-slim - 2e couche : copie de vos fichiers dans
/app - 3e couche : installation des dépendances Python
Chaque couche est immutabilité et cacheable. Si on relance le build sans changer les fichiers copiés, Docker réutilisera les couches précédentes.
Content-Addressable Storage : la déduplication intelligente
Section intitulée « Content-Addressable Storage : la déduplication intelligente »Docker utilise un stockage adressable par contenu (Content-Addressable Storage). Chaque couche est identifiée par le hash SHA256 de son contenu, pas par son nom ou sa position. Concrètement :
- Si deux images partagent la même couche de base (ex:
alpine:3.19), Docker ne la stocke qu'une seule fois sur le disque - Lors d'un
docker pull, seules les couches manquantes sont téléchargées - La déduplication fonctionne aussi bien localement que sur les registries
Cette approche permet d'économiser énormément d'espace disque et de bande passante, surtout quand vous gérez plusieurs images basées sur les mêmes fondations.
Union Filesystem et Copy-on-Write
Section intitulée « Union Filesystem et Copy-on-Write »Pour assembler les couches en un système de fichiers cohérent, Docker utilise un Union Filesystem (généralement OverlayFS via le driver overlay2). Ce système :
- Superpose les couches read-only les unes sur les autres
- Présente une vue unifiée au conteneur (comme un seul système de fichiers)
- Utilise le mécanisme Copy-on-Write (CoW) pour les modifications
Quand un conteneur modifie un fichier existant dans une couche read-only :
- Le fichier est copié dans la couche d'écriture du conteneur
- La modification s'applique sur cette copie
- La couche originale reste intacte
C'est pourquoi les modifications dans un conteneur ne persistent pas après sa suppression, sauf si vous utilisez des volumes.
Comment une image est-elle structurée ?
Section intitulée « Comment une image est-elle structurée ? »Pour aller plus loin, on peut extraire une image Docker pour voir comment
elle est structurée. Par exemple, prenons l’image nginx:alpine :
docker save nginx:alpine -o nginx-alpine.tarmkdir nginx-image && tar -xf nginx-alpine.tar -C nginx-imageUne fois extraite, on y trouve :
Répertoireblobs/
Répertoiresha256/
- 08000c18d16dadf9553d747a58cf44023423a9ab010aab96cf263d2216b8b350
- 0bf5be05f1809d9c54b50ef92deba77c37c22d875842d556edd4ad202b61d033
- 1ff4bb4faebcfb1f7e01144fa9904a570ab9bab88694457855feb6c6bba3fa07
- 252b6db79fae151ab547c0f86a873dc97274d8b61f3921158d480b4242fef957
- 252e179fd8212a3dc5b070bb4d702df97f20b4b52aa65a59cf61c4d85e138b55
- 4b6e8e243d7d2a5c7af927e2137d9426d039591b0b24a368c6f9d5a3e80132e1
- 540b632878f7db4231da7c610f2b3271efba724392e56da1569c1d94900870b4
- 60531a653758d21ddd46bf4c65e7beec5f0e35332409fccf4500e5a02dae1c53
- 80a2d6b308417d56c551f88704e46ab844d0db3db9ad7f2b5e283da916312e65
- 84e2259b5616d28e968f0f5162447105736880570791aadcd4be9dabd23a2bbc
- 8f3c313eb1240a3b86e0c76d0abda7a6fa7df30ad3151e98c4e3725a3fb710dc
- 9af9e76ea07fe05a1f7660b80ec2417bc3fe500991df4995b0adfa13aade20b6
- bbf43b514ee66a048d0b4cd55e455bf91481f1c04252e4c1564cf9fc7b3f0213
- c1761f3c364a963ec0ebd4d728cb6dd5aa24273f7dba0c3dd2fdb8411682ef0a
- c18897d5e3dd125d3d9f2ca7f361cb6b05cf7fad8ef9bc00548f3eb6f3def644
- c9ce8cb4e76a801ef89c226cb8657556e62e3bb962b3641b051bb25f13dd1a26
- f1f70b13aacc43849d4f4ab87a889304a4300210ecd32be5a55305486af5f1ea
- fabf3656cbba722e0a4e35f33a5d2b67eb772a6608e467014787d0a637d7ea55
- index.json
- manifest.json
- oci-layout
- repositories
manifest.json: décrit les couches et la configuration.repositories: indique le nom de l’image et son tag.- Un ou plusieurs dossiers avec des noms hashés : ce sont les couches,
chacune contenant :
layer.tar: la vraie couche de fichiers- des métadonnées (
VERSION,json, etc.)
Dans le format OCI Image Layout, chaque élément de l’image est identifié par un digest SHA256. Les fichiers qui sont dans blobs/sha256/, sont des blobs binaires compressés représentant soit :
- des couches de fichiers (layer.tar.gz)
- des manifests JSON
- des configurations de conteneur
Chaque fichier est nommé par le digest SHA256 de son contenu, ce qui garantit l’intégrité et la déduplication.
On peut alors voir les fichiers ajoutés/modifiés à cette étape. En répétant ça pour chaque couche, on comprend exactement ce que chaque commande du Dockerfile a produit.
C’est aussi ce que fait automatiquement l’outil
dive : il
lit les couches d’une image et affiche ce qui a été ajouté ou modifié, couche
par couche.
Description du fichier manifest.json
Section intitulée « Description du fichier manifest.json »Ce fichier manifest.json est un élément clé d'une image Docker exportée au
format OCI. Il décrit la composition complète de l'image, notamment :
- le fichier de configuration (
Config) - les couches de fichiers (
Layers) - les informations sur chaque blob (
LayerSources) - les tags associés à l'image (
RepoTags)
Notre exemple de manifest.json :
[ { "Config": "blobs/sha256/1ff4bb4faebcfb1f7e01144fa9904a570ab9bab88694457855feb6c6bba3fa07", "RepoTags": [ "nginx:alpine" ], "Layers": [ "blobs/sha256/08000c18d16dadf9553d747a58cf44023423a9ab010aab96cf263d2216b8b350", "blobs/sha256/c1761f3c364a963ec0ebd4d728cb6dd5aa24273f7dba0c3dd2fdb8411682ef0a", "blobs/sha256/8f3c313eb1240a3b86e0c76d0abda7a6fa7df30ad3151e98c4e3725a3fb710dc", "blobs/sha256/c9ce8cb4e76a801ef89c226cb8657556e62e3bb962b3641b051bb25f13dd1a26", "blobs/sha256/252b6db79fae151ab547c0f86a873dc97274d8b61f3921158d480b4242fef957", "blobs/sha256/f1f70b13aacc43849d4f4ab87a889304a4300210ecd32be5a55305486af5f1ea", "blobs/sha256/9af9e76ea07fe05a1f7660b80ec2417bc3fe500991df4995b0adfa13aade20b6", "blobs/sha256/c18897d5e3dd125d3d9f2ca7f361cb6b05cf7fad8ef9bc00548f3eb6f3def644" ], "LayerSources": { "sha256:08000c18d16dadf9553d747a58cf44023423a9ab010aab96cf263d2216b8b350": { "mediaType": "application/vnd.oci.image.layer.v1.tar", "size": 8120832, "digest": "sha256:08000c18d16dadf9553d747a58cf44023423a9ab010aab96cf263d2216b8b350" }, "sha256:252b6db79fae151ab547c0f86a873dc97274d8b61f3921158d480b4242fef957": { "mediaType": "application/vnd.oci.image.layer.v1.tar", "size": 2560, "digest": "sha256:252b6db79fae151ab547c0f86a873dc97274d8b61f3921158d480b4242fef957" }, "sha256:8f3c313eb1240a3b86e0c76d0abda7a6fa7df30ad3151e98c4e3725a3fb710dc": { "mediaType": "application/vnd.oci.image.layer.v1.tar", "size": 3584, "digest": "sha256:8f3c313eb1240a3b86e0c76d0abda7a6fa7df30ad3151e98c4e3725a3fb710dc" }, "sha256:9af9e76ea07fe05a1f7660b80ec2417bc3fe500991df4995b0adfa13aade20b6": { "mediaType": "application/vnd.oci.image.layer.v1.tar", "size": 7168, "digest": "sha256:9af9e76ea07fe05a1f7660b80ec2417bc3fe500991df4995b0adfa13aade20b6" }, "sha256:c1761f3c364a963ec0ebd4d728cb6dd5aa24273f7dba0c3dd2fdb8411682ef0a": { "mediaType": "application/vnd.oci.image.layer.v1.tar", "size": 4504064, "digest": "sha256:c1761f3c364a963ec0ebd4d728cb6dd5aa24273f7dba0c3dd2fdb8411682ef0a" }, "sha256:c18897d5e3dd125d3d9f2ca7f361cb6b05cf7fad8ef9bc00548f3eb6f3def644": { "mediaType": "application/vnd.oci.image.layer.v1.tar", "size": 36649472, "digest": "sha256:c18897d5e3dd125d3d9f2ca7f361cb6b05cf7fad8ef9bc00548f3eb6f3def644" }, "sha256:c9ce8cb4e76a801ef89c226cb8657556e62e3bb962b3641b051bb25f13dd1a26": { "mediaType": "application/vnd.oci.image.layer.v1.tar", "size": 4608, "digest": "sha256:c9ce8cb4e76a801ef89c226cb8657556e62e3bb962b3641b051bb25f13dd1a26" }, "sha256:f1f70b13aacc43849d4f4ab87a889304a4300210ecd32be5a55305486af5f1ea": { "mediaType": "application/vnd.oci.image.layer.v1.tar", "size": 5120, "digest": "sha256:f1f70b13aacc43849d4f4ab87a889304a4300210ecd32be5a55305486af5f1ea" } } }]Voici une explication détaillée de chacune des parties de ce fichier manifest.json :
"Config" : métadonnées de l’image
Section intitulée « "Config" : métadonnées de l’image »"Config": "blobs/sha256/1ff4bb4faebcfb1f7e01144fa9904a570ab9bab88694457855feb6c6bba3fa07"Ce fichier (un blob JSON) contient toutes les instructions du Dockerfile
compilées : la commande par défaut (CMD), les variables d’environnement, les
volumes, les labels, etc. C’est ce blob que le moteur de conteneurs lit au
docker run pour savoir quel processus démarrer et dans quel environnement,
une fois les couches empilées. La valeur est un chemin relatif à l’intérieur
de l’archive : vous pouvez extraire ce fichier et l’ouvrir pour lire la
configuration réelle de l’image.
"RepoTags" : nom et version de l’image
Section intitulée « "RepoTags" : nom et version de l’image »"RepoTags": ["nginx:alpine"]Cela indique que l’image correspond au tag nginx:alpine. C’est le nom que vous
verriez avec docker images.
"Layers" : couches empilées de l’image
Section intitulée « "Layers" : couches empilées de l’image »"Layers": [ "blobs/sha256/08000c18d16da...", "blobs/sha256/c1761f3c364a...", ...]Chaque fichier listé ici correspond à une couche de fichiers
(layer.tar) ajoutée lors du docker build. Elles sont appliquées dans
l’ordre, de la base vers le haut. Le contenu de ces archives représente les
ajouts ou suppressions de fichiers à chaque étape du build.
"LayerSources" : métadonnées des couches
Section intitulée « "LayerSources" : métadonnées des couches »Cette section associe à chaque digest :
- le type MIME du fichier (
mediaType) - la taille en octets
- le digest SHA256, qui sert d’identifiant unique
Exemple :
"sha256:c18897d5e3dd125...": { "mediaType": "application/vnd.oci.image.layer.v1.tar", "size": 36649472, "digest": "sha256:c18897d5e3dd125..."}Cela indique que la couche contient une archive .tar, non compressée ici, de
36 Mo environ.
En résumé
Section intitulée « En résumé »Cette image est donc composée de :
- 8 couches, empilées dans un ordre précis
- Un fichier de configuration global
- Un tag
nginx:alpineassocié - Des métadonnées bien définies pour chaque élément
Et techniquement, Docker ou un autre moteur (comme containerd) reconstruit le
système de fichiers final en appliquant ces couches les unes après les autres,
sur la base des instructions du Config.
Mettre en pratique
Section intitulée « Mettre en pratique »Manipulez des images de conteneurs sur une VM : les récupérer (pull), les taguer, les sauvegarder (save) et les inspecter, les gestes de base de la gestion d'images.
À retenir
Section intitulée « À retenir »Testez vos connaissances
Section intitulée « Testez vos connaissances »Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
FAQ : questions fréquentes sur les images Docker
Section intitulée « FAQ : questions fréquentes sur les images Docker »Ces réponses courtes reprennent les questions les plus posées sur la structure des images : ce qu'est réellement une couche, la différence entre une image et un conteneur, et comment réduire la taille finale. Elles complètent le guide sans le répéter.
Caractéristiques
- Immuable : une fois construite, elle ne change plus.
- En couches : empilement d'instructions du
Dockerfile. - Portable : elle tourne à l'identique sur tout hôte disposant d'un moteur compatible OCI.
Image ou conteneur
| Image | Conteneur | |
|---|---|---|
| État | Figé (lecture seule) | En exécution |
| Nombre | Un modèle | Plusieurs instances |
docker run, et une même image peut démarrer autant de conteneurs que voulu.| Aspect | Image | Conteneur |
|---|---|---|
| Nature | Modèle figé, en lecture seule | Instance vivante |
| Couches | Uniquement read-only | Read-only + une couche d'écriture |
| Multiplicité | Un patron | N instances depuis la même image |
| Cycle de vie | Stockée, versionnée | Créé, démarré, stoppé, supprimé |
docker run, le moteur empile une couche d'écriture par-dessus les couches immuables de l'image. Toutes les modifications du conteneur vont dans cette couche, qui disparaît à la suppression du conteneur, sauf si vous utilisez un volume.Dockerfile qui modifie le système de fichiers.Quelles instructions créent une couche ?
| Crée une couche | Ne crée pas de couche |
|---|---|
FROM, RUN, COPY, ADD |
ENV, LABEL, CMD, EXPOSE, WORKDIR |
0B : elles ne touchent pas au système de fichiers.Propriétés d'une couche
- Identifiée par un hash SHA256 de son contenu.
- Mise en cache : réutilisée si rien ne change en amont.
- Dédupliquée : stockée une seule fois, même partagée entre images.
# Comparer instructions et couches réelles
podman history -q mon-image | wc -l
podman inspect -f '{{len .RootFS.Layers}}' mon-image
Pour optimiser une image, on réduit le nombre et le poids des couches (RUN, COPY, ADD), pas le nombre d'instructions.Leviers principaux
| Levier | Effet |
|---|---|
| Image de base légère | -slim, alpine, distroless |
| Regrouper les RUN | Moins de couches, caches nettoyés |
| Multi-stage build | Ne garde que l'artefact final |
.dockerignore |
Exclut les fichiers inutiles du contexte |
Nettoyage dans la même couche
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
Supprimer le cache dans une instruction séparée ne réduit rien : la couche précédente conserve les fichiers. Il faut nettoyer dans le même RUN.Multi-stage
FROM golang:1.24 AS build
WORKDIR /src
COPY . .
RUN go build -o app .
FROM gcr.io/distroless/static
COPY --from=build /src/app /app
ENTRYPOINT ["/app"]
Seul le binaire compilé arrive dans l'image finale, sans la chaîne de compilation.manifest.json décrit la composition complète d'une image exportée au format OCI.Ce qu'il contient
| Champ | Rôle |
|---|---|
Config |
Blob JSON avec les instructions compilées (CMD, ENV, labels) |
Layers |
Liste ordonnée des couches de fichiers |
LayerSources |
Métadonnées par blob (type MIME, taille, digest) |
RepoTags |
Nom et tag de l'image |
L'obtenir
docker save nginx:alpine -o nginx-alpine.tar
mkdir nginx-image && tar -xf nginx-alpine.tar -C nginx-image
cat nginx-image/manifest.json
Le moteur (Docker, containerd) lit ce manifest pour reconstruire le système de fichiers final, en appliquant les couches dans l'ordre puis en lisant le blob Config pour savoir quel processus démarrer.1. Historique des couches
docker history nginx:alpine
Affiche chaque couche, sa taille et l'instruction qui l'a produite.2. Extraction de l'archive
docker save nginx:alpine -o nginx-alpine.tar
mkdir nginx-image && tar -xf nginx-alpine.tar -C nginx-image
Vous retrouvez manifest.json, les blobs et les layer.tar.3. L'outil dive
dive lit les couches et montre, couche par couche, les fichiers ajoutés ou modifiés, ainsi que l'espace gaspillé. C'est l'outil le plus lisible pour repérer une couche trop lourde ou un fichier oublié.overlay2).Fonctionnement
- Les couches de l'image sont superposées en lecture seule.
- Le conteneur voit une vue unifiée, comme un seul système de fichiers.
- Quand il modifie un fichier existant, celui-ci est d'abord copié dans sa couche d'écriture, puis modifié.
- La couche d'origine reste intacte.
Conséquence pratique
Les modifications d'un conteneur vivent dans sa couche d'écriture éphémère. Elles disparaissent à la suppression du conteneur, sauf si vous montez un volume pour persister les données.Comparaison
| Type | Exemple | Shell | Cas d'usage |
|---|---|---|---|
| Standard | python:3.12 |
Oui | Dev, debug |
| Slim | python:3.12-slim |
Oui | Production générale |
| Alpine | python:3.12-alpine |
Oui (busybox) | Contrainte de taille |
| Distroless | gcr.io/distroless/python3 |
Non | Sécurité maximale |
| Chainguard | cgr.dev/chainguard/python |
Non | Sécurité, peu de CVE |