Table of Contents
Le défi des conteneurs multiplateformes
Les conteneurs Docker promettent une fois lancé-où la portabilité, mais la réalité est plus nuancée lorsque vos cibles de déploiement couvrent les serveurs Windows et Linux. Chaque famille de systèmes d'exploitation expose des interfaces de noyau fondamentalement différentes : les conteneurs Linux dépendent des systèmes de fichiers cgroups, namespaces et Ext4, tandis que les conteneurs Windows nécessitent le noyau Windows NT, l'isolation Hyper-V, et les volumes NTFS ou ReFS. Une image construite sur une base Ubuntu échouera instantanément sur un serveur Windows, et vice versa, à moins que vous ne conçoiviez explicitement la compatibilité entre les plateformes.
Cette incompatibilité se produit parce qu'une image conteneur n'est pas une machine entièrement virtualisée. Elle partage le noyau de l'hôte. Un conteneur Linux utilise le noyau Linux de l'hôte; un conteneur Windows utilise le noyau Windows de l'hôte. Aucune couche d'émulation ou de traduction n'est fournie par défaut. Pour les organisations qui gèrent l'infrastructure hybride, cela crée un besoin pressant d'une approche disciplinée et assistée par des outils pour construire et distribuer des images qui fonctionnent à travers les deux écosystèmes.
Les opérateurs de flotte et les ingénieurs de plateforme doivent donc adopter des stratégies qui produisent des images séparées par plate-forme ou qui tirent parti des capacités de manifeste multi-architecture de Docker pour présenter une seule référence d'image qui résout la variante correcte pour chaque hôte. Le choix dépend de votre modèle de déploiement, support de registre et maturité CI/CD.
Architecture de Windows vs. Images Linux
Couplage du noyau et sélection de l'image de base
Chaque image Docker commence à partir d'une image de base basée sur Linux (par exemple, , , ) ou Windows (par exemple, , . L'image de base détermine l'environnement d'exécution et l'ensemble des bibliothèques système disponibles. Les images Linux peuvent être aussi petites que 5 Mo (Alpine), tandis que les images de base Windows Server commencent autour de 1,5 Go et Nano Server autour de 200 Mo. Cette disparité de taille a des implications opérationnelles pour les temps de tirage d'image, l'utilisation du disque et les coûts de stockage de registre.
Les conteneurs Windows ont aussi une version plus stricte : une image de conteneur Windows construite pour une construction de l'OS hôte (par exemple, 20H2) ne peut pas fonctionner sur une construction différente (par exemple, 21H2). Microsoft atténue cette situation avec le concept d'isolation process vs. Isolation Hyper-V, mais l'image elle-même doit toujours correspondre à la version OS hôte. Les conteneurs Linux sont plus indulgents parce que les API du noyau Linux sont largement compatibles avec les versions mineures.
Système de fichiers et autorisations
Les images de Linux utilisent les permissions POSIX (utilisateur, groupe, autre) et les chemins sensibles aux cas. Les images Windows dépendent des ACL (Liste de contrôle d'accès) et des chemins insensibles aux cas. L'exécution d'une image Linux avec un code qui s'attend à ce que la gestion des fichiers sensibles aux cas sur un hôte Windows (même dans un conteneur) peut conduire à des bogues subtils. Inversement, les chemins avec des backslashs ou des lettres de lecteur (par exemple ) ne seront pas résolus dans un conteneur Linux.
Images multi-architecture avec Docker Buildx
Comment Buildx fonctionne-t-il
Docker Buildx est la façon recommandée de créer des images qui peuvent fonctionner sur plusieurs plateformes à partir d'une seule invocation de construction. Il utilise l'émulation basée sur QEMU (pour la compilation croisée Linux-on-Linux) ou des constructeurs natifs sur des nœuds séparés pour compiler l'image pour chaque architecture cible. Pour les constructions de plate-forme croisée Windows et Linux, vous avez généralement besoin de nœuds de construction natifs Windows et Linux, car QEMU ne peut pas émuler le noyau Windows.
Buildx produit un manifeste multi-architecture (également appelé une liste de manifestes ou fat [) qui fait référence à une ou plusieurs images, chacune étiquetée avec sa plateforme. Lorsqu'un utilisateur exécute sur une machine Windows, Docker sélectionne automatiquement la variante Windows du manifeste. Sur une machine Linux, la variante Linux est sélectionnée. Aucun changement manuel de balise n'est nécessaire.
Configuration d'un buildx Builder pour la plateforme croisée
Pour créer une image multi-architecture qui comprend à la fois des variantes Linux et Windows, vous devez enregistrer un constructeur qui peut accéder à la fois à un hôte Linux et à un hôte Windows. Un modèle commun est d'utiliser un nœud Windows distant comme pilote de construction:
Une fois le constructeur configuré, vous pouvez construire et pousser le manifeste en une seule étape :
Le drapeau pousse automatiquement les images individuelles et la liste de manifestes vers le registre. Aucune commande de création de manifeste supplémentaire n'est nécessaire.
Limitations et Gotchas
- La compilation croisée Windows-on-Linux n'est pas possible parce que vous ne pouvez pas utiliser QEMU pour émuler le noyau Windows. Vous devez avoir un nœud de construction Windows natif accessible au pilote Buildx.
- Le soutien au registre doit inclure des listes de manifestes . La plupart des grands registres (Docker Hub, AWS ECR, Azure ACR, GitHub Container Registry) les supportent. Certains registres privés peuvent vous obliger à vérifier la compatibilité.
- La mise en cache est par plate-forme. La mise en cache construite sur un nœud Linux ne s'applique pas à la construction de Windows. Planifiez des étapes CI séparées ou utilisez un emplacement de cache partagé qui respecte la plate-forme.
- Tag immuabilité[: Une fois que vous appuyez sur une liste de manifestes, vous ne pouvez pas la modifier sans repousser toutes les images référencées. Utilisez toujours une nouvelle balise ou un schéma de version immuable si vous avez besoin de revenir en arrière.
Conception de Dockerfiles pour la multiplateforme
Étapes conditionnelles avec constructions multi-étages
Plutôt que de maintenir deux Dockerfiles complètement séparés, vous pouvez utiliser des arguments de build et des compilations multi-étapes pour gérer les différences de plate-forme dans un seul fichier. Les variables et sont automatiquement définies par Buildx lorsque vous spécifiez le drapeau :
ARG BASE_IMAGE
FROM ${BASE_IMAGE} AS base
FROM base AS install-linux
RUN apt-get update && apt-get install -y libfoo
FROM base AS install-windows
RUN powershell -Command Install-Package -Name Foo
FROM install-${TARGETOS} AS final
COPY app /app
CMD ["/app/start"]
Dans ce modèle, résout ou , et l'étape sélectionne l'étape d'installation appropriée. Vous pouvez également utiliser dans la ligne pour épingler des étapes spécifiques vers Linux ou Windows, bien que cela nécessite Dockerfiles séparés si vous avez besoin d'images de base complètement différentes.
Variables d'environnement et injection de Config
Utilisez des variables d'environnement pour abstractionner des valeurs spécifiques à la plate-forme comme les chemins de fichiers, les terminaisons de lignes ou les noms de commandes.
ARG TARGETOS
ENV CONFIG_DIR=/etc/myapp
ENV CONFIG_DIR=C:\\ProgramData\\MyApp
Cependant, soyez prudent : l'exemple ci-dessus est illustratif mais ne peut pas fonctionner comme-est parce que la directive est évaluée au moment de la construction, mais l'arg est disponible au moment de la construction par plate-forme. Vous pouvez utiliser un "trick de coque" avec un script conditionné par plate-forme ou un modèle de temps de construction. Une approche plus robuste consiste à injecter des répertoires de configuration spécifiques à la plate-forme via un ou Kubernetes ConfigMap par type de nœud, plutôt que de le faire entrer dans l'image.
Manipulation des extrémités de ligne et des bits exécutables
Linux attend des terminaisons de ligne LF dans les scripts shell et les fichiers de configuration; Windows utilise CRLF. Lorsque vous vérifiez les fichiers dans un dépôt Git, définissez pour stocker les scripts comme LF et convertir à la commande uniquement pour les hôtes Windows. Dans le fichier Dockerfile, marquez explicitement les scripts de point d'entrée comme exécutables avec (Linux seulement) ou utilisez une directive qui fonctionne de façon identique sur les deux plateformes (exige Docker BuildKit).
Intégration des pipelines CI/CD
Matrix Builds pour chaque plateforme
Dans GitHub Actions, GitLab CI ou Azure Pipelines, utilisez une stratégie matricielle pour construire et tester séparément l'image sur les piscines de coureurs Linux et Windows. Après chaque construction, poussez l'image spécifique à la plate-forme vers le registre avec une balise qui inclut le suffixe de plate-forme (par exemple , ]. La dernière étape est un travail de création manifeste qui fusionne les deux images en une seule liste de manifestes.
Exemple GitHub Actions Flux de travail (Simplifié)
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
include:
- os: ubuntu-latest
platform: linux/amd64
- os: windows-latest
platform: windows/amd64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Build and push
uses: docker/build-push-action@v5
with:
platforms: ${{ matrix.platform }}
tags: myapp:${{ matrix.platform }}-${{ github.sha }}
push: true
manifest:
needs: build
runs-on: ubuntu-latest
steps:
- uses: docker/setup-buildx-action@v3
- name: Create manifest list
run: |
docker buildx imagetools create \
-t myregistry.io/myapp:latest \
myregistry.io/myapp:linux-amd64-${{ github.sha }} \
myregistry.io/myapp:windows-amd64-${{ github.sha }}
Essais sur les deux plateformes
Par exemple, après avoir construit l'image Windows sur un coureur Windows, exécutez un test de fumée qui vérifie le démarrage de l'application et répond sur le port prévu. Pour Linux, faites de même. Seulement si les deux ensembles de tests passent si la création manifeste se poursuit. Cela empêche une image Windows cassée d'être fusionnée dans une balise "multi-arch" que les consommateurs Linux attendent de travailler.
Conseil: Utilisez pour forcer une variante spécifique de plate-forme lors des tests locaux. C'est inestimable quand vous avez seulement un poste de travail Linux mais que vous voulez vérifier la structure manifeste avant de vous engager.
Débogage des questions de multiplateforme
Modes courants de défaillance
- Inadéquation de l'image de base: La version de Windows Server Core (par exemple, ltsc2022 vs. ltsc2019) ne correspond pas à la version OS hôte. Toujours pin à une balise de sortie Windows spécifique et de coordination avec votre équipe d'infrastructure.
- Les limites de mémoire et les paramètres du noyau: Les conteneurs Windows peuvent nécessiter l'isolement Hyper-V pour imposer des limites de mémoire, tandis que les conteneurs Linux peuvent utiliser CFS (Entièrement Fair Scheduler).
- Différences de réseau: Les conteneurs Windows utilisent un commutateur basé sur NAT par défaut, et la liaison de port se comporte différemment. n'est pas supportée sur Windows. Assurez-vous que votre application ne dépende pas du réseau hôte à moins que vous soyez sur Linux.
- Le verrouillage de fichier et les signaux: Windows ne supporte pas les signaux POSIX de la même manière que Linux. L'envoi d'un SIGTERM à un processus à l'intérieur d'un conteneur Windows ne peut pas déclencher un arrêt gracieux. Concevez votre application pour gérer (Windows) comme un gestionnaire de signal.
Outils d'exploitation et d'introspection
Pour déboger un problème de multiplateforme, utilisez pour vérifier le système d'exploitation et l'architecture de l'image. Regardez les champs et sous :
Si la plate-forme est manquante ou n'affiche qu'une seule variante, l'image n'est pas un manifeste multi-architecture. Pour lister toutes les plates-formes dans un manifeste, utilisez :
Cette commande montre chaque entrée de plate-forme et leur digest. Si vous ne voyez qu'une seule entrée, l'étape de création manifeste était incomplète ou la compilation ne visait pas les deux familles OS.
Les modèles et les pièges du monde réel
Motif : Utilisation de Docker Desktop pour le développement local
Pour le développement de plates-formes croisées, utilisez des constructeurs distants ou des machines virtuelles séparés. La capacité de Docker Desktop à exécuter des conteneurs Linux nativement (via WSL 2) a réduit le besoin de conteneurs Windows sur les postes de travail développeurs, mais vous avez toujours besoin de conteneurs Windows pour tester l'intégration des fonctions d'image uniquement Windows.
Modèle: Alignement LTS pour les images Windows
Microsoft publie une nouvelle version de Windows Server sur le canal de service à long terme (LTSC) environ tous les deux à trois ans. Chaque version LTSC a une image de base de conteneur correspondante. Si votre image de conteneur Windows cible ltsc2022, vous devez la construire sur un hôte ltsc2022 et l'exécuter sur des hôtes ltsc2022. Il n'y a pas de garantie de compatibilité en arrière. Planifiez votre cadence de mise à niveau pour s'aligner sur le cycle de sortie de Microsoft. Pour Linux, cette contrainte est beaucoup plus lâche, mais il faut noter qu'une image construite sur un noyau très ancien () peut fonctionner sur des noyaux plus récents, mais une image construite avec des syscalls plus récents dépendants du noyau (par exemple ) échouera sur des hôtes plus anciens.
Piège: Ignorer ARM64
Alors que l'article se concentre sur Windows et Linux, l'avenir de l'informatique est hétérogène: AWS Graviton, Azure Ampere, Apple Silicon et Raspberry Pi clusters tous exécuter ARM64 Linux. Si vous construisez une image multi-architecture pour Windows et Linux, considérez également l'inclusion dans votre manifeste. De nombreux coureurs CI offrent maintenant des nœuds Linux ARM64 natifs, et l'écosystème Docker Buildx gère la compilation croisée de manière transparente.
Piège : Permissions de système de fichiers en COPY
Lorsque vous utilisez dans un fichier Dockerfile, Docker respecte les métadonnées du système de fichiers de l'hôte source. Si vous COPY un script d'un hôte Linux, il conserve ses terminaisons de bits exécutables et de lignes LF. Si vous COPY d'un hôte Windows, le fichier se trouve sans le bit exécutable et avec les terminaisons CRLF. Pour garantir un comportement cohérent, utilisez et assurez-vous que vos fichiers sources sont vérifiés dans Git avec les terminaisons de lignes LF.
Conclusion
La gestion des images Docker multiplateforme pour la compatibilité Windows et Linux n'est plus une application exotique. C'est une exigence pratique pour toute flotte qui couvre une infrastructure hétérogène, depuis les grappes Windows Server sur site jusqu'aux Kubernetes Linux natifs du cloud. En adoptant Docker Buildx pour les manifestes multi-architectures, en maintenant Dockerfiles conditionnés par la plate-forme, en intégrant un pipeline CI/CD basé sur la matrice, et en testant rigoureusement sur les deux familles d'OS, vous pouvez fournir une seule étiquette d'image qui fonctionne parfaitement sur toute votre flotte.
Les principales options sont simples:
- Utilisez avec les nœuds natifs de Windows et Linux pour produire des listes de manifestes.
- Concevez vos fichiers Docker avec et pour éviter la duplication de code.
- Automatiser les constructions et les tests spécifiques à la plateforme dans CI; fusionner les manifestes seulement après les deux passes.
- Restez à jour avec les cycles de sortie LTSC de Microsoft pour éviter les erreurs de version de base d'image.
Pour plus de détails, consultez la documentation Docker multi-plateforme build , la vue d'ensemble des conteneurs Windows sur Microsoft Learn et le dépôt Buildkit[ pour la configuration avancée des constructeurs. Ces ressources approfondiront votre compréhension des mécanismes sous-jacents et vous prépareront à l'évolution inévitable de l'infrastructure conteneurisée.