Développement Web

Publier et optimiser ses images Docker

13 دقائق للقراءة

📍 Article principal du parcours : Docker de zéro : comprendre et utiliser les conteneurs
Cinquième étape du parcours « Docker de zéro », après volumes et réseaux Docker.

Votre image « Garde » vit sur votre machine. Pour la déployer ailleurs — sur le serveur de production, ou sur le poste d’un collègue — il faut la publier sur un registre, exactement comme on pousse du code sur un dépôt Git. Et tant qu’à la transporter, autant qu’elle soit légère : une image de 1 Go se tire lentement et coûte cher en bande passante, là où la même application tient parfois en 80 Mo. Ce tutoriel couvre les deux faces d’une même pièce : publier ses images et les optimiser.

🎯 Ce que vous allez apprendre

  • étiqueter (tag) une image selon la convention d’un registre ;
  • vous authentifier sur Docker Hub et y pousser votre image ;
  • la tirer depuis un autre poste et comprendre le rôle des couches dans le transfert ;
  • mesurer la taille d’une image et identifier ce qui la gonfle ;
  • réduire l’image avec une base légère, un bon .dockerignore et l’idée du build multi-étapes.

🛠️ Ce que vous allez construire

Vous publierez l’image garde-api sur Docker Hub sous votre propre compte, puis vous la réduirez sensiblement. À la fin, n’importe qui (vous, sur un serveur) pourra la récupérer d’un simple docker pull, et son poids aura fondu par rapport à une version naïve.

Prérequis

  • L’image garde-api des tutoriels précédents.
  • Un compte Docker Hub gratuit (créé sur le site de Docker Hub).
  • Niveau intermédiaire. Test express : si vous avez construit une image avec docker build, vous êtes prêt.
  • ⏱️ Temps estimé : ~45 minutes.

Étape 1 — Comprendre le nommage d’une image de registre

Avant de pousser, il faut nommer correctement. Une image destinée à Docker Hub suit la convention utilisateur/depot:tag. Le préfixe utilisateur est votre identifiant Docker Hub ; sans lui, Docker suppose qu’il s’agit d’une image officielle, et le push échouera. On (re)tague donc l’image locale.

docker tag garde-api:2.0 votre_pseudo/garde-api:2.0

Cette commande ne duplique pas l’image : elle lui ajoute un second nom pointant vers le même contenu. Remplacez votre_pseudo par votre identifiant Docker Hub réel. Vérifiez avec docker images : vous voyez désormais deux entrées (garde-api et votre_pseudo/garde-api) avec le même identifiant d’image — preuve qu’il s’agit du même objet sous deux étiquettes.

Point d’étapedocker images montre l’image taguée votre_pseudo/garde-api:2.0, prête à être publiée.

Étape 2 — S’authentifier sur Docker Hub

Publier exige de prouver son identité. La commande docker login ouvre une session avec votre compte Docker Hub. Pour la sécurité, on recommande un jeton d’accès (access token) plutôt que le mot de passe du compte — il se crée dans les paramètres de sécurité de Docker Hub et se révoque à tout moment.

docker login -u votre_pseudo

Docker demande ensuite votre mot de passe ou, mieux, votre jeton d’accès. Un message « Login Succeeded » confirme l’authentification. Les identifiants sont alors mémorisés localement pour les prochaines commandes. Si vous travaillez sur une machine partagée, pensez à docker logout en fin de session. N’inscrivez jamais vos identifiants en clair dans un script ou un Dockerfile.

Point d’étape — Le message « Login Succeeded » s’affiche. Vous êtes authentifié auprès du registre.

Étape 3 — Pousser l’image sur le registre

Tout est prêt pour la publication. La commande docker push envoie l’image, couche par couche, vers Docker Hub. Seules les couches absentes du registre sont transférées — un gain de temps notable lors des mises à jour.

docker push votre_pseudo/garde-api:2.0

Vous voyez chaque couche être poussée (« Pushed ») ou reconnue comme déjà présente (« Layer already exists »). À la fin, l’image est disponible publiquement sur votre profil Docker Hub. Cette logique de couches est la même qu’au téléchargement : si vous ne modifiez que votre code, seule la petite couche de code est renvoyée, pas l’image entière. C’est exactement pourquoi un bon ordonnancement du Dockerfile accélère aussi les publications, pas seulement les builds.

Point d’étape — Le push se termine sans erreur. Votre image apparaît sur votre profil Docker Hub, prête à être tirée de n’importe où.

Étape 4 — Tirer l’image ailleurs

Vérifions que la boucle est complète en simulant un autre poste : on supprime l’image locale, puis on la retire du registre. C’est exactement ce que fera votre serveur de production.

docker rmi votre_pseudo/garde-api:2.0
docker pull votre_pseudo/garde-api:2.0
docker run -d --name garde -p 3000:3000 votre_pseudo/garde-api:2.0

Après suppression, docker pull récupère l’image depuis Docker Hub, et docker run la lance. Sur une nouvelle machine, c’est tout ce qu’il faut : aucune installation de Node, aucune copie de code source, juste l’image tirée du registre. Vous tenez là le mécanisme central du déploiement conteneurisé — on transporte des images, pas des installations.

Point d’étape — L’image tirée du registre démarre et répond sur le port 3000, sans aucune dépendance installée localement.

Étape 5 — Mesurer ce qui pèse

Place à l’optimisation. On ne réduit bien que ce qu’on mesure. Deux commandes révèlent la taille d’une image et, surtout, la contribution de chaque couche — donc l’instruction du Dockerfile qui l’a alourdie.

docker images votre_pseudo/garde-api
docker history votre_pseudo/garde-api:2.0

docker images affiche la taille totale. docker history détaille chaque couche avec sa taille et l’instruction qui l’a créée : on repère immédiatement qu’une grosse couche correspond à l’installation des dépendances ou à la copie d’un dossier trop large. Si votre image dépasse plusieurs centaines de méga-octets pour une API aussi simple, c’est le signal qu’une optimisation s’impose. L’analyse de l’historique guide précisément où agir.

Point d’étape — Vous lisez la taille de l’image et identifiez, via docker history, les couches les plus lourdes.

Étape 6 — Les trois leviers d’allègement

Trois actions, par ordre d’impact, réduisent une image. La première est le choix de la base : partir de node:24-alpine plutôt que de node:24 fait gagner des centaines de méga-octets, car Alpine est une distribution minimale. La deuxième est le .dockerignore, qui évite de copier node_modules, les fichiers Git et autres déchets dans le contexte de build. La troisième, plus avancée, est le build multi-étapes.

# .dockerignore
node_modules
.git
*.md
.env
npm-debug.log

Vérifiez que votre Dockerfile part bien de node:24-alpine et que npm install utilise --omit=dev pour ne pas embarquer les dépendances de développement. Ces deux réglages, combinés au .dockerignore, suffisent souvent à ramener l’image « Garde » sous les 200 Mo. Reconstruisez, puis comparez avec docker images : la différence est immédiate. Le build multi-étapes, qui sépare l’environnement de construction de l’image finale, pousse l’optimisation encore plus loin — c’est l’objet d’un tutoriel dédié aux builds multi-étapes, à lire une fois ces bases acquises.

Point d’étape — Après reconstruction avec une base alpine, --omit=dev et un .dockerignore complet, la taille de l’image a nettement diminué.

Étape 7 — Publier la version optimisée

Bouclons en publiant l’image allégée sous un nouveau tag, pour pouvoir comparer et revenir en arrière au besoin. Conserver des tags distincts est une bonne discipline de versionnage.

docker build -t votre_pseudo/garde-api:2.1-slim .
docker push votre_pseudo/garde-api:2.1-slim

Vous disposez maintenant de deux versions sur le registre : l’originale et l’optimisée. Lors du push, Docker ne renvoie que les couches nouvelles — l’opération est rapide. En production, vous déploierez la version slim, plus rapide à tirer, surtout sur une liaison modeste. Vous tenez là le cycle complet : construire, taguer, publier, optimiser, republier.

Point d’étape — Les deux tags coexistent sur Docker Hub. La version slim, plus légère, est prête pour le déploiement.

Comprendre le paysage des registres

Docker Hub n’est pas le seul registre, et il est utile de savoir où l’on met les pieds. Un registre est simplement un service qui stocke et distribue des images selon un protocole standardisé par l’Open Container Initiative — ce qui signifie qu’ils sont largement interchangeables. Docker Hub est le registre par défaut et le plus fourni en images officielles ; c’est la porte d’entrée naturelle. Mais il en existe d’autres tout aussi valables : le registre intégré à GitHub (GitHub Container Registry), celui de GitLab, ou un registre privé que vous hébergez vous-même avec l’image officielle registry. Tous parlent le même langage : docker login, docker push, docker pull fonctionnent à l’identique, seule l’adresse du registre change dans le nom de l’image.

Cette interchangeabilité a une conséquence pratique. Docker Hub applique des limites de téléchargement pour les utilisateurs non authentifiés ; si vous les atteignez sur un serveur partagé, deux parades existent. La première est simplement de vous authentifier, ce qui relève les seuils. La seconde est de basculer une partie de vos images vers un registre alternatif — celui de votre forge logicielle, par exemple, souvent gratuit pour les dépôts associés à votre code. Pour une équipe, un registre privé auto-hébergé sur le réseau local joue en plus le rôle de cache : les images officielles n’y sont téléchargées qu’une fois depuis l’extérieur, puis servies en local à tout le monde. C’est un investissement modeste qui paie vite quand la bande passante est comptée.

Reste la question de la confiance. Tirer une image, c’est exécuter du code écrit par quelqu’un d’autre. Privilégiez les images officielles (celles sans préfixe d’utilisateur, comme postgres ou node) et les éditeurs vérifiés, dont la chaîne de fabrication est tracée. Épinglez toujours une version précise plutôt que :latest : non seulement pour la reproductibilité, mais aussi pour ne pas tirer à votre insu une version modifiée. Sur vos propres dépôts publics, n’oubliez jamais que tout ce qui entre dans une couche y reste visible — un secret oublié dans une image publiée est un secret compromis. Ces réflexes de prudence ne coûtent rien et vous évitent les ennuis les plus courants de la chaîne d’approvisionnement logicielle.

🐞 Pièges fréquents

Symptôme / erreur Cause probable Correctif
« denied: requested access to the resource is denied » Image mal taguée ou pas connecté Taguer en pseudo/depot:tag et faire docker login.
« repository does not exist » Préfixe utilisateur manquant Inclure votre identifiant : votre_pseudo/garde-api.
Image énorme malgré alpine Dépendances de dev ou fichiers copiés npm install --omit=dev + .dockerignore ; vérifier docker history.
Push très lent Couches volumineuses retransférées Optimiser la taille ; le cache de couches limite les retransferts ensuite.
Identifiants en clair dans un script Mauvaise pratique de sécurité Utiliser un jeton d’accès révocable, jamais le mot de passe en dur.

Quand chaque méga-octet se paie en data

C’est ici que l’optimisation cesse d’être théorique. Tirer une image de 1 Go sur une liaison partagée à Bamako ou Kaolack peut prendre de longues minutes et grignoter un forfait data ; la même application en 80 Mo se télécharge en quelques secondes. Chaque méga-octet économisé sur l’image se paie en temps et en argent réels à chaque déploiement. Pour une équipe, monter un registre miroir sur le réseau local (un cache d’images partagé) évite que chacun retélécharge les mêmes images officielles depuis Docker Hub. Et si Docker Hub vous impose des limites de téléchargement, sachez qu’il existe des registres alternatifs gratuits — celui intégré à GitHub ou à GitLab, par exemple — qui rendent les mêmes services. L’essentiel reste le même partout : une image légère est une image qu’on déploie sereinement, même quand le réseau est capricieux.

✅ Récapitulatif

Vous savez taguer une image selon la convention d’un registre, vous authentifier, pousser et tirer, comprendre le rôle des couches dans le transfert, mesurer la taille avec docker history et l’alléger par trois leviers : base minimale, .dockerignore, et l’ouverture vers les builds multi-étapes. L’image « Garde » est désormais publiée et légère — transportable d’un poste à un serveur. La dernière étape du parcours consiste à la mettre réellement en ligne, proprement, sur un serveur de production.

🧾 Aide-mémoire

Commande Rôle
docker tag local pseudo/depot:tag Étiqueter pour un registre
docker login -u pseudo S’authentifier sur le registre
docker push pseudo/depot:tag Publier l’image
docker pull pseudo/depot:tag Récupérer l’image
docker images / docker history img Taille totale / par couche
npm install --omit=dev Exclure les dépendances de développement
docker logout Fermer la session du registre

💪 À vous de jouer

Comparez chiffres en main une image basée sur node:24 et une basée sur node:24-alpine, pour la même API. Notez l’écart de taille, puis ne publiez que la plus légère.

Voir une solution
# Version lourde
# (changer temporairement FROM node:24 dans le Dockerfile)
docker build -t garde-api:lourde .
# Version legere
# (FROM node:24-alpine)
docker build -t garde-api:legere .
docker images garde-api

La colonne SIZE montre typiquement autour d’un giga-octet pour lourde contre environ 150 Mo pour legere. Sur un déploiement répété, l’écart se chiffre en minutes et en data économisées. On publie évidemment la version legere.

Tutoriels frères

Pour creuser le sujet

Ressources et références

FAQ

Docker Hub est-il gratuit ?
Oui pour un usage de base : dépôts publics illimités et un dépôt privé sur le plan gratuit, avec des limites de téléchargement pour les comptes anonymes. Se connecter avec un compte gratuit relève déjà ces limites. Pour des besoins plus importants, des plans payants ou des registres alternatifs existent.

Quelle différence entre un dépôt et une image ?
Un dépôt (repository) regroupe toutes les versions d’une même image sous différents tags. votre_pseudo/garde-api est le dépôt ; :2.0 et :2.1-slim en sont deux tags. On pousse des tags dans un dépôt.

Faut-il toujours optimiser au maximum ?
En développement, non : la rapidité d’itération prime. En production et pour tout ce qu’on transporte souvent, oui : une image légère se déploie plus vite, consomme moins de bande passante et offre une surface d’attaque réduite. Le bon réflexe est de viser une base minimale et un .dockerignore dès le départ, puis d’aller vers le multi-étapes si besoin.

Mon image publique est-elle visible par tous ?
Oui, un dépôt public sur Docker Hub est accessible à quiconque. N’y mettez jamais de secrets, de clés ou de données sensibles — ni dans l’image, ni dans son historique de couches. Pour du code propriétaire, utilisez un dépôt privé.

مشاركة