Apprenez à créer, optimiser et publier des images de conteneurs Docker en utilisant des Dockerfiles, avec un focus sur les bonnes pratiques de sécurité et de performance.
Une image suit la spécification OCI (Open Container Initiative).
Ensemble de couches en lecture seule
Chaque couche = delta par rapport à la précédente
Métadonnées séparées (CMD, ENV, labels…)
Nom d’image formel — syntaxe générale : [[registry/][namespace/]repository[:tag][@digest]].
repository : partie obligatoire qui identifie le dépôt (nom du répertoire).
registry : hôte du registre (optionnel); si absent on entend en pratique le registre Docker Hub (docker.io).
namespace : segment optionnel pour regrouper les dépôts (sur Docker Hub, l’espace library est implicite pour les images officielles).
tag : référence optionnelle lisible (ex. :latest, :1.2.3); si aucun tag n’est fourni, latest est couramment utilisé comme valeur par défaut pour l’usage, mais l’absence de tag signifie que l’image peut aussi être désignée par un digest.
digest : identifiant immuable optionnel (forme sha256:<hex>); lorsqu’il est présent (@digest) il prend la priorité sur le tag pour désigner de façon exacte une image. (Les parties entre crochets [] sont optionnelles selon la spécification de référence des images.)
➡️ Une image n’est pas un conteneur mais le modèle de fichier utilisé pour en créer un ou plusieurs.
Exemple : Ubuntu
pull commande pour récupérer une image depuis un registry
Les registries sont des dépôts d’images (Docker Hub, GitHub Container Registry, etc.)
IMAGE CREATED CREATED BY SIZE COMMENT
e8df6c74f650 10 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 10 days ago /bin/sh -c #(nop) ADD file:b0bf3f64519bf10a5… 78.1MB
<missing> 10 days ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 10 days ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B
<missing> 10 days ago /bin/sh -c #(nop) ARG RELEASE 0B
dans docker history (même après un pull)
Docker ne peut pas afficher l’ID d’une couche.
l’historique stocké dans l’image ne contient pas toujours les IDs des couches,
ou Docker n’a pas conservé ces couches dans son cache local.
Architecture en couches
Avantages :
Mutualisation des couches communes
Réduction de l’espace disque
Téléchargement incrémental
Cache efficace lors des builds
Création manuelle d’une image
Méthode possible mais déconseillée :
Lancer un conteneur
Modifier le système de fichiers
Valider avec docker commit
❌ Non reproductible
❌ Historique opaque
❌ Mauvaise pratique en production
Exemple : installer Git manuellement
Lancer un conteneur Ubuntu : docker run --name my-ubuntu --interactive ubuntu:jammy bash
docker run --label ebpro-render=true --rm mygit git --version
git version 2.34.1
Historique de l’image mygit.
docker history mygit
IMAGE CREATED CREATED BY SIZE COMMENT
9d335d8b1a7b 3 seconds ago bash - 156MB
e8df6c74f650 10 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 10 days ago /bin/sh -c #(nop) ADD file:b0bf3f64519bf10a5… 78.1MB
<missing> 10 days ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 10 days ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B
<missing> 10 days ago /bin/sh -c #(nop) ARG RELEASE 0B
➡️ Une seule couche opaque ajoutée
Dockerfile (méthode recommandée)
Fichier texte avec instructions pour construire une image
WORKDIR : Définit le dossier de travail (ex: /app).
COPY : Copie les fichiers locaux dans l’image.
RUN : Exécute des commandes : (ex. Installe les dépendances, pip install).
ENTRYPOINT et CMD : Définit la commande par défaut.
Build d’une image et exécution
Commande docker image build
Contexte de build : répertoire avec Dockerfile ici .
.dockerignore exclure des fichiers du contexte de build ce qui accélère et sécurise la construction,
docker image build -t mon-app:0.0.1 .
docker run --label ebpro-render=true --rm mon-app:0.0.1
2026-10-05 11:17:14,358 INFO Hello John Doe, I'm Python running inside a container!
2026-10-05 11:17:14,358 INFO Here is your DataFrame:
Name Age
0 Pierre 22
1 Paul 35
2 Marie 58
Gestion des tags 1/2
Bonnes pratiques :
Option --tag / -t pour nommer l’image
Tag multiples pour une même image avec versionnage sémantique (semver) :
Versions complètes : 1.2.3
Versions majeures : 1, 1.2
Alias : latest
Format : [registry/][namespace/]repository:tag
Gestion des tags 2/2
Tag à la construction (--tag / -t) :
docker image build \--tag helloworld:0.0.1 \ .
Tag additionnels (docker tag) :
Gestion des versions plus ‘large’
Ajout d’un compte sur un registry pour partage :
${DOCKERHUB_USERNAME} = votre nom d’utilisateur Docker Hub (ou autre registry)
docker image tag helloworld:0.0.1 \ docker.io/${DOCKERHUB_USERNAME}/helloworld:0docker image tag helloworld:0.0.1 \ docker.io/${DOCKERHUB_USERNAME}/helloworld:0.1docker image tag helloworld:0.0.1 \ docker.io/${DOCKERHUB_USERNAME}/helloworld:0.0.1docker image tag helloworld:0.0.1 \ docker.io/${DOCKERHUB_USERNAME}/helloworld:latest
Utilisation de l’image
Commande docker run
-e / --env pour variables d’environnement dans le conteneur
docker run --label ebpro-render=true --rm docker.io/${DOCKERHUB_USERNAME}/helloworld
2026-10-05 11:17:18,917 INFO Hello John Doe, I'm Python running inside a container!
2026-10-05 11:17:18,917 INFO Here is your DataFrame:
Name Age
0 Pierre 22
1 Paul 35
2 Marie 58
docker run --label ebpro-render=true --rm-e NAME=Pierre docker.io/${DOCKERHUB_USERNAME}/helloworld:0.0.1
2026-10-05 11:17:20,994 INFO Hello Pierre, I'm Python running inside a container!
2026-10-05 11:17:20,994 INFO Here is your DataFrame:
Name Age
0 Pierre 22
1 Paul 35
2 Marie 58
L’instruction HEALTHCHECK permet de définir une commande pour vérifier la santé d’un conteneur en cours d’exécution. Docker exécute périodiquement cette commande et utilise son code de retour pour déterminer l’état du conteneur : 0 (sain), 1 (non sain) ou 2 (réservé).
Principes essentiels pour réduire la surface d’attaque et rendre les images sûres :
Images minimalistes : choisir des bases petites (Alpine, distroless) ou builder multi-étapes pour ne garder que l’exécutable final.
Éviter les secrets dans l’image : ne jamais écrire de mots de passe/jetons dans les Dockerfile. Utiliser BuildKit secrets (--mount=type=secret) ou des volumes/variables d’environnement au runtime.
Ne pas exécuter en root : définir un utilisateur non-root dans le Dockerfile.
Pinning & immutabilité : référencer des images par digest (@sha256:...) ou pinner les versions de paquets pour éviter des mises à jour non contrôlées.
Nettoyage des artefacts : supprimer les caches d’installateurs et réduire le nombre de layers (ex. apt-get clean && rm -rf /var/lib/apt/lists/*).
Scanner et vérifier : utiliser des scanners (ex. docker scan, trivy) et générer un SBOM. Ex : trivy image --severity HIGH,CRITICAL myimage:latest.
Limiter les privilèges au runtime : appliquer des profiles seccomp/AppArmor, retirer les capacités inutiles (--cap-drop), monter le FS en lecture seule quand possible (--read-only).
Ressources et isolation : définir limites mémoire/CPU et pids pour limiter l’impact d’un processus compromis.
Utilisateur non-root
RUNadduser-D appuserUSER appuser
Secrets avec BuildKit
Attention : ne pas inclure de secrets dans l’image finale
JAMAIS dans ENV ni non plus dans ARG (persistants dans l’image)
Utiliser les secrets temporaires de BuildKit
FROM alpine:3.18# Dépendance nécessaireRUNapk add --no-cache curl# ARG pour une valeur non sensible (ex : URL ou nom d'environnement)ARG API_URL=https://example.com/secure-data# Utilisation du secret via BuildKitRUN--mount=type=secret,id=api_key\curl--max-time 30 -H"Authorization: Bearer $(cat /run/secrets/api_key)"\${API_URL}-o /tmp/data.json# On peut ajouter un step pour vérifier que le fichier existeRUNtest-f /tmp/data.jsonCMD ["cat", "/tmp/data.json"]