Maîtriser la création et l’optimisation d’un Dockerfile Windows n’a rien de théorique : déployer des containers Windows stables et rapides, c’est une histoire de syntaxe précise, de gestion des images et d’astuces trop souvent zappées dans les guides. Beaucoup pensent encore que Docker, c’est juste pour Linux ; pourtant, les environnements Windows s’ouvrent aux containers depuis plusieurs années et les entreprises s’arrachent les compétences sur ce créneau. Dans ce tour d’horizon, les instructions types, les vrais exemples de Dockerfile, les pièges de la gestion de couches ou encore l’optimisation de la taille prennent vie à coup de cas concrets et de conseils de terrain.
En bref :
- Un Dockerfile Windows gère étape par étape la construction d’images adaptées à des containers Windows Server ou Windows Nano Server : choix d’image de base, instructions RUN, COPY, EXPOSE, CMD et variables d’environnement doivent suivre une syntaxe adaptée au monde Windows.
- Les principales différences avec Linux ? Des chemins, des commandes, parfois le shell, et des problématiques de taille d’image plus importantes dues à la base Windows.
- Le vrai défi, c’est d’optimiser : bien choisir entre images « core » ou « nano », limiter les couches, exclure les fichiers inutiles grâce à .dockerignore, et appliquer les meilleures pratiques (combiner RUN, usage rigoureux d’ENTRYPOINT vs CMD Windows Dockerfile, multi-stage build).
- Partager et déployer ses images Docker Windows, ça passe par Docker Hub, des « tagging » précis et une maîtrise du docker pull/push — tout en gardant un œil sur les questions de sécurité, de reproductibilité et d’empreinte disque.
Les fondamentaux d’un Dockerfile Windows et leurs différences avec Linux
Dès qu’on parle de containers, la plupart visualisent un flot d’images basées sur Alpine, Debian ou Ubuntu. Pourtant, le monde Windows Server a rapidement rattrapé son retard et propose désormais des images de base taillées pour des usages pro, de la base Core jusqu’à Nano Server. Le Dockerfile Windows joue le même rôle que sur Linux : il décrit couche par couche la construction de l’image qui ira alimenter votre container. La logique de build reste la même, mais quelques subtilités Windows peuvent piéger les admins pressés.
Un point souvent mal compris : contrairement à Linux, où chaque RUN utilise Bash/Shell par défaut, sous Windows, chaque instruction RUN s’exécute par Powershell ou cmd.exe suivant le contexte ou la syntaxe (précisée par SHELL). Cela change radicalement la manière d’écrire les scripts d’installation, la gestion des variables et la manipulation de fichiers système.
Un exemple Dockerfile minimaliste pour Windows peut ressembler à ça :
FROM mcr.microsoft.com/windows/servercore:ltsc2022 WORKDIR C:app COPY . . RUN powershell -Command "echo Hello from Windows Dockerfile > log.txt" EXPOSE 8080 CMD ["cmd", "/c", "type log.txt && timeout /t 3600"]
En comparant avec l’équivalent Linux, c’est la gestion des chemins (toujours C:, pas de /app) qui frappe, mais aussi le fait que COPY et RUN s’ajustent à l’environnement Windows Server.
Les images Windows Docker sont plus lourdes : là où une image Alpine ne pèse même pas 10 Mo, un Nano Server fait facilement 200 Mo, et une base Server Core dépasse 2 Go. Le choix de l’image est donc un premier levier d’optimisation. Le contexte l’impose : en entreprise, Server Core reste courant pour la compatibilité legacy, Nano pour les nouveaux microservices. On ne déploie pas un environnement ASP.NET ou IIS de la même façon qu’un microservice en Go.
Quant à la gestion du port exposé, la commande EXPOSE fonctionne pareil, mais l’ouverture est purement déclarative : il faut bien publier (-p) le port à l’exécution. Sur Windows, certains ports (ex : 445, 139) posent davantage de contraintes de sécurité à cause des services systèmes. À surveiller particulièrement en contexte production.

Synthèse des particularités du Dockerfile Windows
Pour clarifier, voici un tableau des différences les plus marquantes entre Dockerfile Windows et Linux :
| Aspect | Dockerfile Windows | Dockerfile Linux |
|---|---|---|
| Instruction RUN | Powershell ou cmd.exe | Bash / sh |
| Chemins | C:cheminversapp | /chemin/vers/app |
| Taille des images | > 200 Mo (Nano), > 2 Go (Core) | 10-100 Mo (Alpine/Ubuntu) |
| Fichiers temporaires | Gestion via Del ou Remove-Item | rm, unlink |
| Services par défaut | IIS, .NET, legacy Windows stuff | nginx, Apache, Node, etc. |
En entreprise, un bon Dockerfile Windows vaut bien une doc linuxienne complète, si on veut des containers fiables et des builds rapides à maintenir. À ce stade, comprendre la syntaxe et les différences prépare le terrain pour déployer ou migrer ses apps .NET, IIS ou autres vers des images Docker Windows prêtes à l’emploi.
Maîtriser la syntaxe Dockerfile Windows : structures, instructions clés et bonnes pratiques
L’écriture d’un Dockerfile Windows repose sur une poignée d’instructions essentielles, dont la syntaxe doit absolument être adaptée à la stack Microsoft. Le premier piège, c’est de recopier un Dockerfile Linux sans tenir compte du shell ni de la gestion des chemins. Certains outils d’automatisation génèrent du code qui plante à l’exécution, tout simplement parce qu’ils oublient que la syntaxe diffère dès la moindre commande système.
L’instruction FROM indique la base : images publiées sur mcr.microsoft.com/windows/nginx, servercore, nanoserver, etc. Privilégier les tags (ex : windowsservercore:ltsc2022) garantit que la version reste maîtrisée. Oublier le tag latest évite bien des surprises lorsqu’un build saute une version de Windows sous le capot.
Voyons l’enchaînement classique dans un exemple Dockerfile Windows :
FROM mcr.microsoft.com/windows/nanoserver:20H2 WORKDIR C:service COPY service.exe C: RUN powershell -Command "Set-ExecutionPolicy Bypass -Scope Process -Force; New-Item -Path C:servicedata -ItemType Directory" EXPOSE 9090 ENV ENVIRONMENT=production CMD ["service.exe"]
Chaque instruction mérite sa place :
- WORKDIR crée (si besoin) et place les instructions suivantes dans ce dossier.
- COPY transfert binaire, scripts ou autres fichiers avec la même syntaxe mais en pensant au séparateur d’arborescence Windows.
- RUN nécessite powershell -Command « … » ou cmd /S /C suivant le shell choisi : oublie bash ou les pipes UNIX classiques.
- EXPOSE reste une documentation de port, souvent 80 ou 443 pour IIS, mais tout service custom y a droit.
- ENV pour injecter des variables lisibles à l’exécution ou en build.
- CMD Windows Dockerfile opère souvent avec une exécutable unique ou un script d’entrée ; privilégier la forme tableau (exec) plutôt que shell (sinon gestion de guillemets et chemins casse-gueule).
Point notable : Powershell permet bien plus de finesse que cmd.exe pour manier des fichiers, installer des modules ou gérer les permissions. Rien n’interdit d’installer Chocolatey dans le RUN pour des installateurs MSI, mais attention à la durée de build et à la taille des couches. Règle de base : le RUN n’est pas fait pour empiler 15 lignes, mieux vaut les chaîner proprement si les opérations vont ensemble.
Ce qui régit la syntaxe Dockerfile Windows, ce ne sont pas juste les instructions, c’est surtout leur ordre, la logique des couches et ce que Microsoft documente sur son portail. Les erreurs classiques : mauvais séparateur de chemin, RUN qui tente bash, ou COPY d’un fichier absent par mauvaise récursion.
Exemple de build multi-stage spécifique Windows
Le multi-stage build, popularisé chez les devs Node ou Java, est aussi possible sur Windows. Voici un cas d’école :
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src COPY MyApp.sln . COPY src/ ./src RUN dotnet publish -c Release -o C:out FROM mcr.microsoft.com/dotnet/runtime:6.0 WORKDIR /app COPY --from=build C:out . CMD ["MyApp.exe"]
Ici, la première phase compile, la seconde n’embarque que le résultat. Une image finale plus légère, conforme aux meilleures pratiques Dockerfile Windows en matière de performance et de sécurité. Cette approche est devenue standard depuis que Microsoft a optimisé ses images de build, mais elle mérite d’être soulignée : la séparation claire build/runtime réduit la surface d’attaque et le coût disque.
Optimisation des images Docker Windows : taille, performance et gestion des couches
Optimiser ses images Docker Windows, ça veut dire réduire drastiquement la taille des builds, accélérer les transferts et rendre la vie plus simple en production comme en CI/CD. Le constat : la plupart des images Windows dépassent 1 Go, mais on voit croître des labs ou prod avec des dizaines de containers pas moins efficaces que sous Linux, à condition de viser juste sur les méthodes.
D’abord, bien choisir entre servercore et nanoserver : l’image Nano Server, plus fine et rapide, conviendra aux microservices ou aux apps qui n’ont pas besoin de .NET Framework complet, tandis que Server Core est là pour le legacy, IIS ou SQL Server. Les versions « slim » ou « alpine » sur Windows commencent seulement à émerger, et encore, avec des limitations. Donc, on limite le poids en ne prenant que ce dont on a besoin côté stack système.
Le RUN groupé est LA pratique à assimiler. Cumuler plusieurs installations dans une même commande via ‘&&’ ou ‘;’ (suivant le shell choisi), comme :
RUN powershell -Command « Install-PackageProvider -Name NuGet -Force ;
Install-Module -Name PSScriptAnalyzer -Force »
Un RUN = une couche, donc un RUN minimal, une couche en moins.
Pour éviter d’importer git, logs ou dossiers redondants, le .dockerignore est indispensable. Un exemple typique :
.git/ obj/ bin/ Dockerfile *.md
En production, ne pas oublier que le cache pip, npm ou nuget, laissé dans l’image, peut tripler sa taille sans qu’on s’en rende compte. Nettoyer dès le RUN ou dans un RUN dédié : « del /q *.tmp » ou Remove-Item pour Powershell. Les fichiers inutiles, ce sont autant de Mo économisés… et moins de surface d’exposition potentielle.
Voici un extrait de bonnes pratiques Dockerfile orientées containers Windows :
- Préférer des FROM avec version précise, pas latest – par expérience, un build peut casser du jour au lendemain à cause d’une base qui change suite à un Patch Tuesday inattendu (déjà vu chez un client bancaire…)
- Privilégier COPY à ADD – sauf cas de besoin précis (archives, téléchargements distants)
- Supprimer toute trace de test, backup, doc inutile dans la phase finale de la build
- Multi-stage build dès que possible : oui, ça double la ligne de FROM, mais la couche runtime n’embarque plus rien de la build !
Tableau comparatif de l’impact des choix de build sur la taille d’image
| Scénario | Image de base | Couches RUN | .dockerignore | Taille estimée |
|---|---|---|---|---|
| Mauvaise pratique | servercore:ltsc2022 (latest) | Multiples, non groupées | Aucun | 2,8 Go |
| Optimisé, mono-stage | nanoserver:20H2 (fixé) | RUN groupées | Basique | 550 Mo |
| Optimisé, multi-stage | sdk:6.0 + runtime:6.0 | RUN groupées + clean | Complet | 290 Mo |
Ce n’est pas un hasard si la taille finale varie du simple au triple. Les admins et devs aguerris le voient en pratique, et dans un projet de plusieurs containers, l’empreinte disque globale devient vite critique sur des infrastructures mutualisées ou des clusters Windows.
Déploiement, publication et partage d’images Docker Windows sur Docker Hub
Construire une image Docker Windows, c’est bien, mais la rendre disponible, traçable et réutilisable, c’est encore mieux. Docker Hub s’est imposé comme le point de rencontre des équipes, mais les problématiques Windows rajoutent une couche de complexité, surtout : gestion des tags, authentification, et rappels réguliers sur la sécurité.
Après un docker build qui marche, Docker Hub attend une image avec le préfixe lier au compte. Typiquement :
docker tag mon-app-windows monuser/mon-app-windows:1.0
docker push monuser/mon-app-windows:1.0
Gardez en tête que la version/tag est OBLIGATOIRE : publier latest sans suivi, c’est s’exposer à des surprises lors d’un docker pull – pas seulement chez vous, mais chez tous ceux qui exploitent la même image dans leur environnement. En 2026, cette règle reste d’actualité, rien n’a changé sur cette bonne pratique !
Prendre l’habitude de publier des images propres, multi-arch (x64/ARM si pertinent), et surtout documentées (ex : README sur Docker Hub, labels explicites dans le Dockerfile) permet d’éviter le syndrome de l’image oubliée, vieille de deux ans, dont personne ne sait ce qu’elle contient.
Le docker pull ensuite redescend la bonne image sur n’importe quel hôte compatible ; reste à lancer le container, par exemple :
docker run -d -p 5000:80 –name mon-service-windows monuser/mon-app-windows:1.0
Les erreurs classiques ici : oublier d’ouvrir les ports côté firewall Windows, mal gérer les droits sur le filesystem, ou sous-estimer la couche d’isolation entre les containers (Hyper-V vs Process Isolation). Toujours tester sur un lab avant la prod, surtout pour vérifier la compatibilité des images entre différentes éditions Windows Server (l’API surface change d’une update à l’autre, c’est du vécu).
Pour l’anecdote, une équipe projet s’est retrouvée avec une trentaine d’images Windows publiées sans versionnage ni documentation – résultat : impossible d’identifier la dernière image saine, la restauration de prod a pris 8 heures au lieu de 20 minutes. L’histoire tourne encore aujourd’hui dans beaucoup de régies qui pilotent des clusters Windows.
Pièges fréquents, sécurité et maintenance autour des Dockerfiles Windows
Construire le Dockerfile Windows idéal ne protège pas de tous les tracas : la sécurité reste un domaine où l’erreur est vite faite. Premier piège : travailler systématiquement en compte administrateur dans le container. Rien de tel pour exposer la surface d’attaque. Sur Windows, comme sur Linux, le principe du moindre privilège s’applique : créez un utilisateur dédié dans le Dockerfile, exécutez le service à ce niveau (cf USER dans le Dockerfile), ne laissez jamais tourner IIS ou une app .NET avec les droits SYSTEM sauf exception.
Autre oubli classique : ne pas mettre à jour l’image de base. Les correctifs de sécurité de Windows Server Core ou Nano Server paraissent tous les mois ; rebuilder les images dès la disponibilité des updates limite le risque. Côté maintenance, le nettoyage des images, la purge des anciennes versions et l’audit régulier du contenu (commande docker history) permettent d’éviter la propagation d’images obsolètes ou vulnérables.
Un Dockerfile Windows doit intégrer les variables d’environnement critiques via ENV, exploiter ENTRYPOINT quand la commande principale ne doit pas être surchargée et soigner la forme CMD tableau chaque fois que possible. Là encore, sur l’aspect documentation : EXPOSE et commentaire à chaque étape s’imposent si d’autres membres d’équipe doivent s’y retrouver trois mois après.
Enfin, côté build, le .dockerignore reste le grand oublié : sans lui, chaque build embarque par mégarde des fichiers de build, des scripts secrets ou des revendications de droits qui ne doivent jamais sortir de la phase dev. Prendre le réflexe de compléter ce fichier pour chaque projet n’est pas du luxe, c’est vital.
Sur un retour d’expérience récent, une agence a vu son SI pollué par une fuite de clé API embarquée dans un container. Leur oubli ? Un simple .dockerignore absent, un Dockerfile qui copiait toute l’arborescence du git, y compris les fichiers de config sensibles… et une image publiée sur un registre trop ouvert. Un classique dont plus personne ne veut faire les frais encore en 2026.
Points essentiels de maintenance et sécurité Dockerfile Windows
- Écrire un fichier .dockerignore complet dès le début du projet
- Vérifier les droits utilisateurs dans le container (USER non-admin recommandé)
- Rebuilder les images à chaque Patch Tuesday ou disponible update critique
- Ajouter systématiquement ENV pour les variables sensibles (jamais dans le code source ou le Dockerfile en clair)
- Documenter CMD Windows Dockerfile et la logique des RUN pour éviter tout doute lors des audits
En gardant une rigueur sur ces aspects, la maîtrise du Dockerfile Windows s’affirme, et toute la chaîne de containers profite d’une meilleure sécurité et d’une maintenance simplifiée, même plusieurs mois après le déploiement initial. La confiance dans vos images Windows, c’est aussi la confiance dans l’ensemble des build scripts qui régissent leur vie.
Comment choisir entre Windows Server Core et Nano Server dans un Dockerfile Windows ?
Le choix dépend du besoin fonctionnel : Server Core offre un support large (IIS, .NET Framework complet, legacy), mais pèse plusieurs Go. Nano Server est beaucoup plus léger et rapide, mais ne convient qu’aux applications .NET Core, microservices, outils modernes. Pour optimiser, choisissez la version minimale qui remplit vos besoins : moins de surface d’attaque, moins de ressources consommées.
Pourquoi utiliser la forme tableau pour CMD et ENTRYPOINT dans un Dockerfile Windows ?
La forme tableau évite les pièges de parsing du shell Windows (espaces, guillemets, caractères spéciaux) et garantit que la commande principale est exécutée proprement, sans être interprétée ou segmentée comme le ferait la forme shell. C’est LE réflexe pour des builds stables et reproductibles.
Quelles sont les erreurs récurrentes lors de la création d’un Dockerfile Windows ?
Oublier le .dockerignore, copier des fichiers inutiles ou sensibles, écrire des RUN non groupés, utiliser latest pour FROM sans versionner, lancer les services en admin au lieu d’un utilisateur restreint, négliger le rebuiling après les mises à jour Windows et oublier de documenter les ports exposés ou la logique de build.
Un build multi-stage est-il vraiment utile avec Dockerfile Windows ?
Oui, même sur Windows, séparer phase build (outils, compilation) et phase runtime (exécutable ou app finale) permet de produire des images moitié moins lourdes, sécurisées et plus rapides à déployer. Les gains sont visibles à partir d’un certain volume d’images ou si le code doit être maintenu à long terme.
Quels sont les outils pour analyser et optimiser une image Docker Windows ?
Docker desktop fournit déjà les commandes docker image ls, docker history, et docker inspect. Sur Windows, ajoutez des outils comme Dive ou DockerSlim pour visualiser les couches et nettoyer le superflu. Un audit régulier du build est la meilleure garantie d’éviter l’accumulation de failles ou de déchets techniques.