Tutoriel : Créer une application multiconteneur avec Docker Compose
Dans ce tutoriel, vous allez apprendre à gérer plusieurs conteneurs et à communiquer entre eux lors de l’utilisation de Container Tools dans Visual Studio. La gestion de plusieurs conteneurs nécessite l’orchestration de conteneurs et un orchestrateur tel que Docker Compose ou Service Fabric. Pour ces procédures, vous utilisez Docker Compose. Docker Compose est idéal pour le débogage et les tests locaux au cours du cycle de développement.
L’exemple terminé que vous créez dans ce didacticiel se trouve sur GitHub à https://github.com/MicrosoftDocs/vs-tutorial-samples
dans le dossier docker/ComposeSample.
Conditions préalables
- Docker Desktop
- Visual Studio 2019 avec la charge de travail Développement web, Outils Azure et/ou la charge de travail Développement multiplateforme .NET Core installée
- Docker Desktop
- Visual Studio 2022 avec la charge de travail Développement web, Outils Azure et/ou la charge de travail Développement multiplateforme .NET Core installée. Cette installation inclut les outils de développement .NET 8.
Créer un projet d’application web
Dans Visual Studio, créez un projet ASP.NET Core Web App, nommé WebFrontEnd
, pour créer une application web avec des pages Razor.
capture d’écran
Ne sélectionnez pas Activer la prise en charge de Docker. Vous ajoutez la prise en charge de Docker plus loin dans le processus.
Ne sélectionnez pas Activer la prise en charge de Docker. Vous ajoutez la prise en charge de Docker plus loin dans le processus.
Créer un projet d’API web
Ajoutez un projet à la même solution et appelez-le MyWebAPI. Sélectionnez API comme type de projet, puis décochez la case Configurer pour HTTPS. Dans cette conception, nous utilisons uniquement SSL pour la communication avec le client, et non pour la communication entre les conteneurs dans la même application web. Seul WebFrontEnd
a besoin du protocole HTTPS et du code dans les exemples suppose que vous avez décoché cette case. En général, les certificats de développeur .NET utilisés par Visual Studio ne sont pris en charge que pour les requêtes externes à conteneur, et non pour les requêtes conteneur à conteneur.
Ajoutez un projet à la même solution et appelez-le MyWebAPI. Sélectionnez API comme type de projet, puis décochez la case Configurer pour HTTPS.
Remarque
Dans cette conception, nous utilisons uniquement HTTPS pour la communication avec le client, et non pour la communication entre les conteneurs dans la même application web. Seul
WebFrontEnd
a besoin du protocole HTTPS et du code dans les exemples suppose que vous avez décoché cette case. En général, les certificats de développeur .NET utilisés par Visual Studio ne sont pris en charge que pour les requêtes externes à conteneur, et non pour les requêtes conteneur à conteneur.Ajoutez la prise en charge d’Azure Cache pour Redis. Ajoutez le package NuGet
Microsoft.Extensions.Caching.StackExchangeRedis
(pasStackExchange.Redis
). Dans Program.cs, ajoutez les lignes suivantes, juste avantvar app = builder.Build()
:builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = "redis:6379"; // redis is the container name of the redis service. 6379 is the default port options.InstanceName = "SampleInstance"; });
Ajoutez des directives using dans
Program.cs
pourMicrosoft.Extensions.Caching.Distributed
etMicrosoft.Extensions.Caching.StackExchangeRedis
.using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.StackExchangeRedis;
Dans le projet d’API web, supprimez les
WeatherForecast.cs
et Contrôleurs/WeatherForecastController.csexistants, puis ajoutez un fichier sous Contrôleurs, CounterController.cs, avec le contenu suivant :using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; using StackExchange.Redis; namespace WebApi.Controllers { [ApiController] [Route("[controller]")] public class CounterController : ControllerBase { private readonly ILogger<CounterController> _logger; private readonly IDistributedCache _cache; public CounterController(ILogger<CounterController> logger, IDistributedCache cache) { _logger = logger; _cache = cache; } [HttpGet(Name = "GetCounter")] public string Get() { string key = "Counter"; string? result = null; try { var counterStr = _cache.GetString(key); if (int.TryParse(counterStr, out int counter)) { counter++; } else { counter = 0; } result = counter.ToString(); _cache.SetString(key, result); } catch(RedisConnectionException) { result = "Redis cache is not found."; } return result; } } }
Le service incrémente un compteur chaque fois que la page est accessible et stocke le compteur dans le cache.
Ajouter du code pour appeler l’API web
Dans le projet
WebFrontEnd
, ouvrez le fichier Index.cshtml.cs et remplacez la méthodeOnGet
par le code suivant.public async Task OnGet() { ViewData["Message"] = "Hello from webfrontend"; using (var client = new System.Net.Http.HttpClient()) { // Call *mywebapi*, and display its response in the page var request = new System.Net.Http.HttpRequestMessage(); request.RequestUri = new Uri("http://mywebapi/WeatherForecast"); // request.RequestUri = new Uri("http://mywebapi/api/values/1"); // For ASP.NET 2.x, comment out previous line and uncomment this line. var response = await client.SendAsync(request); ViewData["Message"] += " and " + await response.Content.ReadAsStringAsync(); } }
Remarque
Dans le code réel, vous ne devez pas supprimer
HttpClient
après chaque requête. Pour obtenir les meilleures pratiques, consultez Utiliser HttpClientFactory pour implémenter des requêtes HTTP résilientes.Dans le fichier
Index.cshtml
, ajoutez une ligne pour afficherViewData["Message"]
afin que le fichier ressemble au code suivant :@page @model IndexModel @{ ViewData["Title"] = "Home page"; } <div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about <a href="/aspnet/core">building Web apps with ASP.NET Core</a>.</p> <p>@ViewData["Message"]</p> </div>
(ASP.NET 2.x uniquement) Maintenant, dans le projet d’API web, ajoutez du code au contrôleur Valeurs pour personnaliser le message retourné par l’API pour l’appel que vous avez ajouté à partir de webfrontend.
// GET api/values/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { return "webapi (with value " + id + ")"; }
Remarque
Dans .NET Core 3.1 et versions ultérieures, vous pouvez utiliser l’API WeatherForecast fournie plutôt que ce code supplémentaire. Toutefois, vous devez commenter l’appel à UseHttpsRedirection dans le projet d’API web, car le code utilise HTTP pour effectuer l’appel plutôt que HTTPS.
//app.UseHttpsRedirection();
Ajouter la prise en charge de Docker Compose
Dans le projet
WebFrontEnd
, choisissez Ajouter > Prise en charge de l’orchestrateur de conteneurs. La boîte de dialogue Options de prise en charge de Docker s’affiche.Choisissez Docker Compose.
Choisissez votre système d’exploitation cible, par exemple Linux.
capture d’écran
Visual Studio crée un fichier docker-compose.yml et un fichier
.dockerignore
dans le nœud docker-compose de la solution, et ce projet s’affiche en police gras, ce qui montre qu’il s’agit du projet de démarrage.Le docker-compose.yml s'affiche comme suit :
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
La
version
spécifiée dans la première ligne est la version du fichier Docker Compose . Vous ne devez normalement pas le modifier, car il est utilisé par les outils pour comprendre comment interpréter le fichier.Le fichier
.dockerignore
contient des types de fichiers et des extensions que vous ne souhaitez pas inclure dans le conteneur. Ces fichiers sont généralement associés à l’environnement de développement et au contrôle de code source, et non à l’application ou au service que vous développez.Examinez la section Container Tools du volet de sortie pour plus d’informations sur les commandes en cours d’exécution. Vous pouvez voir l’outil en ligne de commande
docker-compose
est utilisé pour configurer et créer les conteneurs d’exécution.Dans le projet d’API web, cliquez de nouveau avec le bouton droit sur le nœud du projet, puis choisissez Ajouter >Prise en charge de l’orchestrateur de conteneurs. Choisissez Docker Compose, puis sélectionnez le même système d’exploitation cible.
Remarque
Dans cette étape, Visual Studio propose de créer un fichier Dockerfile. Si vous effectuez cette opération sur un projet qui dispose déjà de la prise en charge de Docker, vous êtes invité à remplacer le fichier Dockerfile existant. Si vous avez apporté des modifications dans votre fichier Dockerfile que vous souhaitez conserver, choisissez non.
Visual Studio apporte des modifications à votre fichier YML Docker Compose. Les deux services sont désormais inclus.
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfile
Le premier projet auquel vous ajoutez l’orchestration de conteneur est configuré pour être lancé lorsque vous exécutez ou déboguez. Vous pouvez configurer l’action de lancement dans les propriétés du projet Docker-Compose. Sur le nœud du projet Docker Compose, cliquez avec le bouton droit pour ouvrir le menu contextuel, puis choisissez Propriétés, ou utilisez Alt+Entrée. La capture d’écran suivante montre les propriétés souhaitées pour la solution utilisée ici. Par exemple, vous pouvez modifier la page chargée en personnalisant la propriété URL du service .
Voici ce que vous voyez lors du lancement (version .NET Core 2.x) :
Capture d’écran
L’application web pour .NET 3.1 affiche les données météorologiques au format JSON.
Supposons maintenant que vous n’êtes intéressé que par l’attachement du débogueur à WebFrontEnd, et non au projet d’API web. Dans la barre de menus, vous pouvez utiliser la liste déroulante en regard du bouton Démarrer pour afficher un menu des options de débogage ; choisissez Gérer les paramètres de lancement de Docker Compose.
La boîte de dialogue Gérer les paramètres de lancement de Docker Compose s’affiche. Avec cette boîte de dialogue, vous pouvez contrôler quel sous-ensemble de services est lancé pendant une session de débogage, lancée avec ou sans le débogueur attaché, ainsi que le service de lancement et l’URL. Consultez Démarrer un sous-ensemble de services Compose.
Choisissez Nouveau pour créer un profil et nommez-le
Debug WebFrontEnd only
. Ensuite, définissez le projet d’API web sur Démarrer sans débogage, laissez le projet WebFrontEnd défini pour commencer par le débogage, puis choisissez Enregistrer.La nouvelle configuration est choisie comme valeur par défaut pour la prochaine F5.
Appuyez sur F5 pour confirmer qu’elle fonctionne comme prévu.
Félicitations, vous exécutez une application Docker Compose avec un profil Docker Compose personnalisé.
Dans le projet
WebFrontEnd
, ouvrez le fichier Index.cshtml.cs et remplacez la méthodeOnGet
par le code suivant.public async Task OnGet() { // Call *mywebapi*, and display its response in the page using (var client = new System.Net.Http.HttpClient()) { var request = new System.Net.Http.HttpRequestMessage(); // A delay is a quick and dirty way to work around the fact that // the mywebapi service might not be immediately ready on startup. // See the text for some ideas on how you can improve this. // Uncomment if not using healthcheck (Visual Studio 17.13 or later) // await System.Threading.Tasks.Task.Delay(10000); // mywebapi is the service name, as listed in docker-compose.yml. // Docker Compose creates a default network with the services // listed in docker-compose.yml exposed as host names. // The port 8080 is exposed in the WebAPI Dockerfile. // If your WebAPI is exposed on port 80 (the default for HTTP, used // with earlier versions of the generated Dockerfile), change // or delete the port number here. request.RequestUri = new Uri("http://mywebapi:8080/Counter"); var response = await client.SendAsync(request); string counter = await response.Content.ReadAsStringAsync(); ViewData["Message"] = $"Counter value from cache :{counter}"; } }
Remarque
Dans le code réel, vous ne devez pas supprimer
HttpClient
après chaque requête. Pour obtenir les meilleures pratiques, consultez Utiliser HttpClientFactory pour implémenter des requêtes HTTP résilientes.L’URI donné fait référence à un nom de service défini dans le fichier docker-compose.yml. Docker Compose configure un réseau par défaut pour la communication entre les conteneurs à l’aide des noms de service répertoriés en tant qu’hôtes.
Le code présenté ici fonctionne avec .NET 8 et versions ultérieures, qui configure un compte d’utilisateur dans le fichier Dockerfile sans privilèges d’administrateur et expose le port 8080, car le port HTTP par défaut 80 n’est pas accessible sans privilège élevé.
Dans le fichier
Index.cshtml
, ajoutez une ligne pour afficherViewData["Message"]
afin que le fichier ressemble au code suivant :@page @model IndexModel @{ ViewData["Title"] = "Home page"; } <div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about <a href="/aspnet/core">building Web apps with ASP.NET Core</a>.</p> <p>@ViewData["Message"]</p> </div>
Ce code affiche la valeur du compteur retourné par le projet d’API web. Il incrémente chaque fois que l’utilisateur accède ou actualise la page.
Ajouter la prise en charge de Docker Compose
Dans le projet
WebFrontEnd
, choisissez Ajouter > Prise en charge de l’orchestrateur de conteneurs. La boîte de dialogue Options de support Docker s’affiche.Choisissez Docker Compose.
Visual Studio 17.12 et versions ultérieures Choisissez les options d'échafaudage pour le projet WebFrontEnd.
Visual Studio 17.11 et versions antérieures Choisir votre système d’exploitation cible, par exemple Linux.
capture d’écran
Visual Studio crée un fichier docker-compose.yml et un fichier
.dockerignore
dans le nœud de projet docker-compose dans la solution, et ce projet s’affiche en caractères gras, ce qui montre qu'il est le projet de démarrage.Le fichier docker-compose.yml s’affiche comme suit :
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
Le fichier
.dockerignore
contient des types de fichiers et des extensions que vous ne souhaitez pas inclure dans le conteneur. Ces fichiers sont généralement associés à l’environnement de développement et au contrôle de code source, et non à l’application ou au service que vous développez.Examinez la section Container Tools du volet de sortie pour plus d’informations sur les commandes en cours d’exécution. Vous pouvez voir l’outil en ligne de commande
docker-compose
est utilisé pour configurer et créer les conteneurs d’exécution.Dans le projet d’API web, cliquez de nouveau avec le bouton droit sur le nœud du projet, puis choisissez Ajouter >Prise en charge de l’orchestrateur de conteneurs. Choisissez Docker Compose, puis sélectionnez le même système d’exploitation cible.
Remarque
Dans cette étape, Visual Studio propose de créer un fichier Dockerfile. Si vous effectuez cette opération sur un projet qui dispose déjà de la prise en charge de Docker, vous êtes invité à remplacer le fichier Dockerfile existant. Si vous avez apporté des modifications dans votre fichier Dockerfile que vous souhaitez conserver, choisissez non.
Visual Studio apporte des modifications à votre fichier YML
docker-compose
. Les deux services sont désormais inclus.services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfile
Ajoutez le cache au fichier
docker-compose.yml
:redis: image: redis
Assurez-vous que la mise en retrait est au même niveau que les deux autres services.
(Visual Studio 17.13 ou version ultérieure) Les services dépendants présentent un problème courant. La requête HTTP dans la page principale du serveur frontal peut s’exécuter immédiatement lors du lancement de l’application, avant que le service
mywebapi
soit prêt à recevoir des requêtes web. Si vous utilisez Visual Studio 17.13 ou une version ultérieure, vous pouvez utiliser les fonctionnalités Docker Composedepends_on
ethealthcheck
dans docker-compose.yml pour que les projets démarrent dans la bonne séquence et qu’ils soient prêts à traiter les demandes si nécessaire. Consultez Docker Compose - Ordre de démarrage.services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend depends_on: mywebapi: condition: service_healthy build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi depends_on: redis: condition: service_started healthcheck: test: curl --fail http://mywebapi:8080/ || exit 1 interval: 20s timeout: 20s retries: 5 build: context: . dockerfile: MyWebAPI/Dockerfile redis: image: redis
Dans cet exemple, le contrôle d’intégrité utilise
curl
pour vérifier que le service est prêt à traiter les demandes. Si l’image que vous utilisez n’a pascurl
installée, ajoutez des lignes à l’étape debase
du fichier Dockerfile MyWebAPI pour l’installer. Cette étape nécessite des privilèges élevés, mais vous pouvez restaurer les privilèges utilisateur normaux après l’avoir installé comme indiqué ici (pour les images Debian utilisées dans cet exemple) :USER root RUN apt-get update && apt-get install -y curl USER $APP_UID
Remarque
Si vous utilisez une distribution Linux, comme Alpine, cela ne prend pas en charge
apt-get
, essayezRUN apk --no-cache add curl
à la place.Ces fonctionnalités Docker Compose nécessitent un paramètre de propriété dans le fichier projet Docker Compose (
.dcproj
). Définissez la propriétéDependencyAwareStart
sur true :<PropertyGroup> <!-- existing properties --> <DependencyAwareStart>true</DependencyAwareStart> </PropertyGroup>
Cette propriété active une manière différente de lancer les conteneurs pour le débogage, prenant en charge les fonctionnalités de dépendance de service.
Avec ces modifications, le service
webfrontend
ne démarre pas tant quemywebapi
démarre et gère correctement une requête web.Le premier projet auquel vous ajoutez l’orchestration de conteneur est configuré pour être lancé lorsque vous exécutez ou déboguez. Vous pouvez configurer l’action de lancement dans les propriétés du projet Docker-Compose. Sur le nœud du projet Docker Compose, cliquez avec le bouton droit pour ouvrir le menu contextuel, puis choisissez Propriétés, ou utilisez Alt+Entrée. Par exemple, vous pouvez modifier la page chargée en personnalisant la propriété d'URL du service .
Appuyez sur F5. Voici ce que vous voyez lors du lancement :
Capture d’écran
Vous pouvez surveiller les conteneurs à l’aide de la fenêtre Conteneurs. Si vous ne voyez pas la fenêtre, utilisez la zone de recherche, appuyez sur Ctrl+K, Ctrl+O, ou appuyez sur Ctrl+Q. Sous Recherche de fonctionnalités, recherchez
containers
et choisissez Afficher>Autres conteneurs>Windows dans la liste.Développez le nœud Conteneurs de solutions, puis choisissez le nœud de votre projet Docker Compose pour afficher les journaux combinés sous l’onglet Journaux de cette fenêtre.
Vous pouvez également sélectionner le nœud d’un conteneur individuel pour afficher les journaux système, les variables d’environnement, le système de fichiers et d’autres détails.
Configurer des profils de lancement
Cette solution a un cache Azure pour Redis, mais elle n’est pas efficace pour reconstruire le conteneur de cache chaque fois que vous démarrez une session de débogage. Pour éviter cette situation, vous pouvez configurer quelques profils de lancement. Créez un profil pour démarrer le Cache Azure pour Redis. Créez un deuxième profil pour démarrer les autres services. Le deuxième profil peut utiliser le conteneur de cache qui est déjà en cours d’exécution. Dans la barre de menus, vous pouvez utiliser la liste déroulante à côté du bouton Démarrer pour ouvrir un menu avec les options de débogage. Sélectionnez Gérer les paramètres de lancement de Docker Compose.
La boîte de dialogue Gérer les paramètres de lancement de Docker Compose s’affiche. Avec cette boîte de dialogue, vous pouvez contrôler quel sous-ensemble de services est lancé pendant une session de débogage, lancée avec ou sans le débogueur attaché, ainsi que le service de lancement et l’URL. Consultez Démarrer un sous-ensemble de services Compose.
Choisissez Nouveau pour créer un profil et nommez-le
Start Redis
. Ensuite, définissez le conteneur Redis sur Démarrer sans débogage, laissez l’autre défini sur Ne pas démarrer, puis choisissez Enregistrer.Créez ensuite un autre profil
Start My Services
qui ne démarre pas Redis, mais démarre les deux autres services.(Facultatif) Créez un troisième profil
Start All
pour démarrer tout. Vous pouvez choisir Démarrer sans débogage pour Redis.Choisissez Démarrer Redis dans la liste déroulante de la barre d’outils principale de Visual Studio. Le conteneur Redis est généré et démarre sans débogage. Vous pouvez utiliser la fenêtre Conteneurs pour voir qu’elle est en cours d’exécution. Ensuite, choisissez Démarrer mes services dans la liste déroulante, puis appuyez sur F5 pour les lancer. Vous pouvez maintenant conserver le conteneur de cache en cours d’exécution dans de nombreuses sessions de débogage suivantes. Chaque fois que vous utilisez Démarrer mes services, ces services utilisent le même conteneur de cache.
Félicitations, vous exécutez une application Docker Compose avec un profil Docker Compose personnalisé.
Étapes suivantes
Examinez les options de déploiement de vos conteneurs sur Azure.