Personnaliser des conteneurs Docker dans Visual Studio

Vous pouvez personnaliser vos images conteneur en modifiant le fichier Dockerfile généré par Visual Studio lorsque vous ajoutez la prise en charge de Docker à votre projet. Que vous génériez un conteneur personnalisé à partir de l’IDE Visual Studio ou que vous configuriez une build de ligne de commande, vous devez savoir comment Visual Studio utilise le fichier Dockerfile pour générer vos projets. Vous devez connaître ces détails, car, pour des raisons de performances, Visual Studio suit un processus spécial pour la création et l’exécution d’applications conteneurisées qui n’est pas évident à partir du fichier Dockerfile.

Supposons que vous souhaitiez apporter une modification au fichier Dockerfile et voir les résultats à la fois dans les conteneurs de débogage et de production. Dans ce cas, vous pouvez ajouter des commandes dans le fichier Dockerfile pour modifier la première étape (généralement base). Consultez Modifier l’image conteneur pour le débogage et la production. Toutefois, si vous souhaitez apporter une modification uniquement lors du débogage, mais pas lors de la production, vous devez créer une autre étape et utiliser le paramètre de génération DockerfileFastModeStage pour indiquer à Visual Studio d’utiliser cette étape pour les builds de débogage. Consultez Modifier l’image conteneur uniquement pour le débogage.

Cet article explique en détail le processus de génération de Visual Studio pour les applications conteneurisées, puis il propose des informations sur la façon de modifier le fichier Dockerfile pour affecter à la fois le débogage et les builds de production, ou simplement pour le débogage.

Générations Dockerfile dans Visual Studio

Remarque

Cette section décrit le processus de génération de conteneur utilisé par Visual Studio lorsque vous choisissez le type de build du conteneur Dockerfile. Si vous utilisez le type de build du Kit de développement logiciel (SDK) .NET, les options de personnalisation sont différentes et les informations contenues dans cette section ne s’appliquent pas. Au lieu de cela, consultez Mettre en conteneur une application .NET avec dotnet publish et utilisez les propriétés décrites dans Personnaliser votre conteneur pour configurer le processus de génération de conteneur.

Génération multi-étapes

Lorsque Visual Studio génère un projet qui n’utilise pas de conteneurs Docker, il appelle MSBuild sur l’ordinateur local et génère les fichiers de sortie dans un dossier (généralement bin) sous votre dossier de solution local. Toutefois, pour un projet conteneurisé, le processus de génération prend en compte les instructions de Dockerfile pour générer l’application conteneurisée. Le fichier Dockerfile utilisé par Visual Studio est divisé en plusieurs étapes. Ce processus s’appuie sur la fonctionnalité de génération multi-étapes de Docker.

La fonctionnalité de génération multi-étapes permet de rendre le processus de création de conteneurs plus efficace et de réduire la taille des conteneurs en leur permettant de contenir uniquement les parties dont votre application a besoin au moment de l’exécution. La génération multi-étapes est utilisée pour les projets .NET Core, et non pour les projets .NET Framework.

La génération multi-étapes permet de créer des images conteneur par étapes qui produisent des images intermédiaires. Prenons l’exemple d’un fichier Dockerfile classique. La première étape est appelée base dans le fichier Dockerfile généré par Visual Studio, bien que les outils n’aient pas besoin de ce nom.

FROM mcr.microsoft.com/dotnet/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

Les lignes du fichier Dockerfile commencent par l’image ASP.NET de Microsoft Container Registry (mcr.microsoft.com) et créent une image base intermédiaire qui expose les ports 80 et 443 et définit le répertoire de travail sur /app.

L’étape suivante est build, qui se présente comme suit :

FROM mcr.microsoft.com/dotnet/sdk:3.1-buster-slim AS build
WORKDIR /src
COPY ["WebApplication43/WebApplication43.csproj", "WebApplication43/"]
RUN dotnet restore "WebApplication43/WebApplication43.csproj"
COPY . .
WORKDIR "/src/WebApplication43"
RUN dotnet build "WebApplication43.csproj" -c Release -o /app/build

Vous pouvez voir que l’étape build commence à partir d’une autre image d’origine du registre (sdk plutôt que aspnet), au lieu de continuer à partir de la base. L’image sdk possède tous les outils de génération, et c’est pourquoi elle est beaucoup plus grande que l’image aspnet, qui contient uniquement les composants de runtime. La raison de l’utilisation d’une image distincte devient claire lorsque vous examinez le reste du fichier Dockerfile :

FROM build AS publish
RUN dotnet publish "WebApplication43.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication43.dll"]

La dernière étape démarre à nouveau à partir de base et inclut le COPY --from=publish pour copier la sortie publiée dans l’image finale. Ce processus permet à l’image finale d’être beaucoup plus petite, car elle n’a pas besoin d’inclure tous les outils de génération qui se trouvaient dans l’image sdk.

MSBuild

Remarque

Cette section explique comment personnaliser vos conteneurs Docker lorsque vous choisissez le type de build du conteneur Dockerfile. Si vous utilisez le type de build du Kit de développement logiciel (SDK) .NET, les options de personnalisation sont différentes et les informations contenues dans cet article ne s’appliquent pas. Au lieu de ça, voir Mettre en conteneur une application .NET avec dotnet publish.

Les fichiers Dockerfile créés par Visual Studio pour les projets .NET Framework (et pour les projets .NET Core créés avec des versions de Visual Studio antérieures à Visual Studio 2017 Update 4) ne sont pas des fichiers Dockerfiles multi-index. Les étapes de ces fichiers Dockerfiles ne compilent pas votre code. Au lieu de cela, quand Visual Studio génère un fichier Dockerfile .NET Framework, il compile d’abord votre projet à l’aide de MSBuild. Lorsque cela réussit, Visual Studio génère ensuite le fichier Dockerfile, qui copie simplement la sortie de génération de MSBuild dans l’image Docker résultante. Étant donné que les étapes de compilation de votre code ne sont pas incluses dans le fichier Dockerfile, vous ne pouvez pas générer des fichiers Dockerfile .NET Framework à l’aide de docker build en ligne de commande. Vous devez utiliser MSBuild pour générer ces projets.

Pour générer une image pour un projet de conteneur Docker unique, vous pouvez utiliser MSBuild avec l’option de commande /t:ContainerBuild. Cette commande indique à MSBuild de générer la cible ContainerBuild plutôt que la cible par défaut Build. Par exemple :

MSBuild MyProject.csproj /t:ContainerBuild /p:Configuration=Release

Une sortie similaire à celle affichée dans la fenêtre Sortie s’affiche lorsque vous générez votre solution à partir de l’IDE Visual Studio. Utilisez toujours /p:Configuration=Release, car dans les cas où Visual Studio utilise l’optimisation de génération multi-étapes, les résultats lors de la génération de la configuration Débogage peuvent ne pas être ceux attendus. Consultez Débogage.

Si vous utilisez un projet Docker Compose, utilisez cette commande pour générer des images :

msbuild /p:SolutionPath=<solution-name>.sln /p:Configuration=Release docker-compose.dcproj

Débogage

Remarque

Cette section explique comment personnaliser vos conteneurs Docker lorsque vous choisissez le type de build du conteneur Dockerfile. Si vous utilisez le type de build du Kit de développement logiciel (SDK) .NET, les options de personnalisation sont différentes et la plupart des informations contenues dans cette section ne s’appliquent pas. Au lieu de ça, voir Mettre en conteneur une application .NET avec dotnet publish.

Lorsque vous effectuez la génération dans la configuration Débogage, Visual Studio réalise plusieurs optimisations qui facilitent les performances du processus de génération pour les projets conteneurisés. Le processus de génération des applications conteneurisées n’est pas aussi évident que le simple suivi des étapes décrites dans le fichier Dockerfile. La création dans un conteneur est beaucoup plus lente que sur l’ordinateur local. Ainsi, lorsque vous générez dans la configuration Débogage, Visual Studio génère vos projets sur l’ordinateur local, puis partage le dossier de sortie dans le conteneur à l’aide du montage de volume. Une build avec cette optimisation activée est appelée build en mode Rapide.

En mode Rapide, Visual Studio appelle docker build avec un argument qui indique à Docker de générer uniquement le premier index du fichier Dockerfile (normalement l’index base). Vous pouvez modifier cela en définissant la propriété MSBuild, DockerfileFastModeStage, décrite dans Propriétés MSBuild des outils de conteneurs. Visual Studio gère le reste du processus sans tenir compte du contenu du fichier Dockerfile. Par conséquent, lorsque vous modifiez votre fichier Dockerfile, par exemple pour personnaliser l’environnement de conteneur ou installer des dépendances supplémentaires, vous devez placer vos modifications dans la première étape. Les étapes personnalisées placées dans les index build, publish ou final du fichier Dockerfile ne sont pas exécutées.

Cette optimisation des performances se produit uniquement lorsque vous générez dans la configuration Débogage. Dans la configuration Mise en production, la génération se produit dans le conteneur comme spécifié dans le fichier Dockerfile.

Si vous souhaitez désactiver l’optimisation des performances et générer comme le spécifie le fichier Dockerfile, définissez la propriété ContainerDevelopmentMode sur Regular dans le fichier projet comme suit :

<PropertyGroup>
   <ContainerDevelopmentMode>Regular</ContainerDevelopmentMode>
</PropertyGroup>

Pour restaurer l’optimisation des performances, supprimez la propriété du fichier projet.

Lorsque vous démarrez le débogage (F5), un conteneur démarré précédemment est réutilisé, si possible. Si vous ne souhaitez pas réutiliser le conteneur précédent, vous pouvez utiliser les commandes Régénérer ou Nettoyer dans Visual Studio pour forcer Visual Studio à utiliser un nouveau conteneur.

Le processus d’exécution du débogueur dépend du type de projet et du système d’exploitation de conteneur :

Scénario Processus du débogueur
Applications .NET Core (conteneurs Linux) Visual Studio télécharge vsdbg et le mappe au conteneur, puis il est appelé avec votre programme et vos arguments (autrement dit, dotnet webapp.dll), puis le débogueur s’attache au processus.
Applications .NET Core (conteneurs Windows) Visual Studio utilise onecoremsvsmon et le mappe au conteneur, l’exécute comme point d’entrée, puis Visual Studio s’y connecte et s’attache au programme. Cela est similaire à la façon dont vous configurez normalement le débogage à distance sur un autre ordinateur ou une machine virtuelle.
Applications .NET Framework Visual Studio utilise msvsmon et le mappe au conteneur, l’exécute dans le cadre du point d’entrée où Visual Studio peut s’y connecter et s’attache au programme.

Pour plus d’informations sur vsdbg.exe, consultez Débogage offroad de .NET Core sur Linux et OS X à partir de Visual Studio.

Modifier l’image conteneur pour le débogage et la production

Pour modifier l’image conteneur à la fois pour le débogage et la production, modifiez l’étape base. Ajoutez vos personnalisations au fichier Dockerfile dans la section de l’étape de base, généralement la première section du fichier Dockerfile. Pour plus d’informations sur les commandes Dockerfile, reportez-vous à la référence Dockerfile dans la documentation Docker.

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
# <add your commands here>

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["WebApplication3/WebApplication3.csproj", "WebApplication3/"]
RUN dotnet restore "WebApplication3/WebApplication3.csproj"
COPY . .
WORKDIR "/src/WebApplication3"
RUN dotnet build "WebApplication3.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "WebApplication3.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication3.dll"]

Modifier l’image conteneur uniquement pour le débogage

Ce scénario s’applique lorsque vous souhaitez faire quelque chose avec vos conteneurs pour vous aider dans le processus de débogage, comme l’installation d’un élément à des fins de diagnostic, mais que vous ne souhaitez pas qu’il soit installé dans les builds de production.

Pour modifier le conteneur uniquement pour le débogage, créez une étape, puis utilisez la propriété MSBuild DockerfileFastModeStage pour indiquer à Visual Studio d’utiliser votre étape personnalisée lors du débogage. Pour plus d’informations sur les commandes Dockerfile, reportez-vous à la référence Dockerfile dans la documentation Docker.

Dans l’exemple suivant, nous installons le package procps-ng, mais uniquement en mode débogage. Ce package fournit la commande pidof, dont Visual Studio a besoin, mais qui n’est pas dans l’image Mariner utilisée ici. L’étape que nous utilisons pour le débogage en mode rapide est debug, une étape personnalisée définie ici. L’index du mode rapide n’a pas besoin d’hériter de l’index build ni publish. Il peut hériter directement de l’index base, car Visual Studio monte un volume qui contient tout ce qui est nécessaire pour exécuter l’application, comme décrit plus haut dans cet article.

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:6.0-cbl-mariner2.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM base AS debug
RUN tdnf install procps-ng -y

FROM mcr.microsoft.com/dotnet/sdk:6.0-cbl-mariner2.0 AS build
WORKDIR /src
COPY ["WebApplication1/WebApplication1.csproj", "WebApplication1/"]
RUN dotnet restore "WebApplication1/WebApplication1.csproj"
COPY . .
WORKDIR "/src/WebApplication1"
RUN dotnet build "WebApplication1.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "WebApplication1.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]

Dans le fichier projet, ajoutez ce paramètre pour indiquer à Visual Studio d’utiliser votre étape debug personnalisée lors du débogage.

  <PropertyGroup>
     <!-- other property settings -->
     <DockerfileFastModeStage>debug</DockerfileFastModeStage>
  </PropertyGroup>

Les sections suivantes comprennent des informations qui peuvent être utiles dans certains cas, par exemple quand vous souhaitez spécifier un autre point d’entrée, ou si votre application est compatible SSL et que vous modifiez un élément susceptible d’affecter la gestion des certificats SSL.

Génération à partir de la ligne de commande

Si vous souhaitez générer un projet conteneur avec un Dockerfile en dehors de Visual Studio, vous pouvez utiliser docker build, MSBuild, dotnet build, ou dotnet publish pour générer à partir de la ligne de commande.

Si vous utilisez le type de build du Kit de développement logiciel (SDK) .NET, vous n’avez pas de fichier Dockerfile donc vous ne pouvez donc pas utiliser docker build; à la place, utiliser MSBuild, dotnet build ou dotnet publish pour générer sur la ligne de commande.

Utiliser le générateur Docker

Pour créer une solution conteneurisée à partir de la ligne de commande, vous pouvez généralement utiliser la commande docker build <context> pour chaque projet de la solution. Vous fournissez l’argument de contexte de génération. Le contexte de génération d’un fichier Dockerfile est le dossier sur l’ordinateur local utilisé comme dossier de travail pour générer l’image. Par exemple, il s’agit du dossier à partir duquel vous copiez les fichiers lorsque vous copiez dans le conteneur. Dans les projets .NET Core, utilisez le dossier qui contient le fichier de solution (.sln). Exprimé sous la forme d’un chemin d’accès relatif, cet argument est généralement « . » pour un fichier Dockerfile dans un dossier de projet et le fichier solution dans son dossier parent. Pour les projets .NET Framework, le contexte de génération est le dossier du projet, et non le dossier de solution.

docker build -f Dockerfile ..

Échauffement du projet

L’échauffement de projet fait référence à une série d’étapes qui se produisent lorsque le profil Docker est sélectionné pour un projet (c’est-à-dire, lorsqu’un projet est chargé ou que la prise en charge de Docker est ajoutée) afin d’améliorer les performances des exécutions suivantes (F5 ou Ctrl+F5). Ce comportement est configurable sous Outils>Options>Outils de conteneurs. Voici les tâches qui s’exécutent en arrière-plan :

  • Vérifiez que Docker Desktop est installé et en cours d’exécution.
  • Vérifiez que Docker Desktop est défini sur le même système d’exploitation que le projet.
  • Extrayez les images dans la première étape du fichier Dockerfile (l’étape base pour la plupart des fichiers Dockerfile).
  • Générez le fichier Dockerfile et démarrez le conteneur.

La préparation n’a lieu qu’en mode Rapide. Par conséquent, le conteneur en cours d’exécution dispose du volume monté du dossier de l’application. Cela signifie que les modifications apportées à l’application n’invalident pas le conteneur. Ce comportement améliore considérablement le niveau de performance de débogage et réduit le temps d’attente pour les tâches durables comme l’extraction d’images volumineuses.

Mappage de volume

Pour que le débogage fonctionne dans des conteneurs, Visual Studio utilise le mappage de volume pour mapper le débogueur et les dossiers NuGet à partir de l’ordinateur hôte. Le mappage de volume est décrit dans la documentation Docker ici. Vous pouvez afficher les mappages de volumes pour un conteneur à l’aide de la fenêtre Conteneurs dans Visual Studio.

Voici les volumes montés dans votre conteneur :

Volume Description
Dossier d’application Contient le dossier de projet où se trouve le fichier Dockerfile.
Dossiers de packages NuGet Contient les packages NuGet et les dossiers de secours qui sont lus à partir du fichier obj{project}.csproj.nuget.g.props dans le projet.
Débogueur distant Contient les éléments nécessaires pour exécuter le débogueur dans le conteneur en fonction du type de projet. Consultez la section Débogage.
Dossier source Contient le contexte de génération qui est passé aux commandes Docker.

Voici les volumes montés dans votre conteneur. Ce que vous voyez dans vos conteneurs peut différer en fonction de la version mineure de Visual Studio 2022 que vous utilisez.

Volume Description
Dossier d’application Contient le dossier de projet où se trouve le fichier Dockerfile.
HotReloadAgent Contient les fichiers de l’agent de rechargement à chaud.
HotReloadProxy Contient les fichiers requis pour exécuter un service qui permet à l’agent de rechargement de l’hôte de communiquer avec Visual Studio sur l’hôte.
Dossiers de packages NuGet Contient les packages NuGet et les dossiers de secours qui sont lus à partir du fichier obj{project}.csproj.nuget.g.props dans le projet.
Débogueur distant Contient les éléments nécessaires pour exécuter le débogueur dans le conteneur en fonction du type de projet. La section Débogage contient une explication plus détaillée à ce sujet.
Dossier source Contient le contexte de génération qui est passé aux commandes Docker.
TokenService.Proxy Contient les fichiers nécessaires pour exécuter un service qui permet à VisualStudioCredential de communiquer avec Visual Studio sur l’hôte.

Pour .NET 8, des points de montage supplémentaires à la racine et pour l'utilisateur de l'application qui contiennent des secrets d'utilisateur et le certificat HTTPS peuvent également être présents. Dans la version préliminaire de Visual Studio 17.10, les volumes Hot Reload et Token Service, ainsi qu'un autre composant, Distroless Helper, sont regroupés sous le même point de montage : /VSTools.

Remarque

Visual Studio 17.10 en préversion Si vous utilisez Docker Engine dans le Sous-système Windows pour Linux (WSL) sans Docker Desktop, définissez la variable d'environnement VSCT_WslDaemon=1 pour que Visual Studio utilise des chemins WSL lors de la création de montages de volumes. Le package NuGet Microsoft.VisualStudio.Azure.Containers.Tools.Targets 1.20.0-Préversion 1 est également requis.

Pour les applications web ASP.NET Core, il peut y avoir deux dossiers supplémentaires pour le certificat SSL et les secrets utilisateur, ce qui est expliqué plus en détail dans la section suivante.

Activer des journaux des outils de conteneur détaillés

À des fins de diagnostic, vous pouvez activer certains journaux d’outils de conteneur. Vous pouvez activer ces journaux en définissant certaines variables d’environnement. Pour des projets de conteneur unique, la variable d’environnement est MS_VS_CONTAINERS_TOOLS_LOGGING_ENABLED, qui se connecte ensuite à %tmp%\Microsoft.VisualStudio.Containers.Tools. Pour les projets Docker Compose, il s’agit de MS_VS_DOCKER_TOOLS_LOGGING_ENABLED qui se connecte ensuite à %tmp%\Microsoft.VisualStudio.DockerCompose.Tools.

Attention

Lorsque la journalisation est activée et que vous utilisez un proxy de jeton pour l’authentification Azure, les informations d’identification d’authentification peuvent être enregistrées en tant que texte brut. Voir Configurer l’authentification Azure.

Point d’entrée du conteneur

Visual Studio utilise un point d’entrée de conteneur personnalisé en fonction du type de projet et du système d’exploitation du conteneur. Voici les différentes combinaisons :

Type de conteneur Point d’entrée
Conteneurs Linux Le point d’entrée est tail -f /dev/null, qui est une attente infinie pour maintenir le conteneur en cours d’exécution. Lorsque l’application est lancée via le débogueur, c’est lui qui est chargé d’exécuter l’application (autrement dit, dotnet webapp.dll). S’ils sont lancés sans débogage, les outils exécutent un docker exec -i {containerId} dotnet webapp.dll pour exécuter l’application.
Conteneurs Windows Le point d’entrée est similaire à C:\remote_debugger\x64\msvsmon.exe /noauth /anyuser /silent /nostatus, qui exécute le débogueur. Il est donc à l’écoute des connexions. Cette méthode s’applique lorsque le débogueur exécute l’application. Lorsqu’elle est lancée sans débogage, une commande docker exec est utilisée. Pour les applications web .NET Framework, le point d’entrée est légèrement différent ; ServiceMonitor est ajouté à la commande.

Le point d’entrée du conteneur ne peut être modifié que dans les projets docker-compose, pas dans les projets à conteneur unique.

Applications ASP.NET Core compatibles SSL

Les outils de conteneur dans Visual Studio prennent en charge le débogage d’une application ASP.NET Core compatible SSL avec un certificat de développement, de la même façon que vous vous attendiez à ce qu’elle fonctionne sans conteneurs. Pour ce faire, Visual Studio ajoute quelques étapes supplémentaires pour exporter le certificat et le rendre disponible dans le conteneur. Voici le flux que Visual Studio gère pour vous lors du débogage dans le conteneur :

  1. Vérifie que le certificat de développement local est présent et approuvé sur l’ordinateur hôte via l’outil dev-certs.

  2. Exporte le certificat vers %APPDATA%\ASP.NET\Https avec un mot de passe sécurisé stocké dans le magasin de secrets utilisateur pour cette application particulière.

  3. Le volume monte les répertoires suivants :

    • *%APPDATA%\Microsoft\UserSecrets
    • *%APPDATA%\ASP.NET\Https

ASP.NET Core recherche un certificat qui correspond au nom de l’assembly sous le dossier Https. C’est pourquoi il est mappé au conteneur dans ce chemin d’accès. Le chemin d’accès et le mot de passe du certificat peuvent également être définis à l’aide de variables d’environnement (à savoir ASPNETCORE_Kestrel__Certificates__Default__Path et ASPNETCORE_Kestrel__Certificates__Default__Password) ou dans le fichier JSON de secrets utilisateur, par exemple :

{
  "Kestrel": {
    "Certificates": {
      "Default": {
        "Path": "c:\\app\\mycert.pfx",
        "Password": "strongpassword"
      }
    }
  }
}

Si votre configuration prend en charge les builds conteneurisées et non conteneurisées, vous devez utiliser les variables d’environnement, car les chemins d’accès sont spécifiques à l’environnement de conteneur.

Pour plus d’informations sur l’utilisation de SSL avec des applications ASP.NET Core dans des conteneurs, consultez Hébergement d’images ASP.NET Core avec Docker sur HTTPS.

Pour obtenir un exemple de code illustrant la création de certificats personnalisés pour une application multiservice qui sont approuvés sur l’hôte et dans les conteneurs pour la communication de service à service HTTPS, consultez CertExample.