Lernprogramm: Erstellen einer Multicontainer-App mit Docker Compose
In diesem Lernprogramm erfahren Sie, wie Sie mehr als einen Container verwalten und zwischen ihnen kommunizieren, wenn Sie Containertools in Visual Studio verwenden. Das Verwalten mehrerer Container erfordert Container-Orchestrierung und erfordert einen Orchestrator wie Docker Compose oder Service Fabric. Für diese Verfahren verwenden Sie Docker Compose. Docker Compose eignet sich hervorragend für lokales Debuggen und Testen im Verlauf des Entwicklungszyklus.
Das fertige Beispiel, das Sie in diesem Lernprogramm erstellen, finden Sie auf GitHub unter https://github.com/MicrosoftDocs/vs-tutorial-samples
im Ordner docker/ComposeSample.
Voraussetzungen
- Docker Desktop
- Visual Studio 2019 mit installierten Workloads für Webentwicklung, Azure-Tools und/oder plattformübergreifende .NET-Entwicklung
- Docker Desktop
- Visual Studio 2022 mit installierten Workloads für Webentwicklung, Azure-Tools und/oder plattformübergreifende .NET-Entwicklung. Diese Installation enthält die .NET 8-Entwicklungstools.
Erstellen eines Webanwendungsprojekts
Erstellen Sie in Visual Studio ein ASP.NET Core Web App- Projekt namens WebFrontEnd
, um eine Webanwendung mit Razor-Seiten zu erstellen.
Wählen Sie nicht Docker-Support aktivieren aus. Sie fügen die Docker-Unterstützung später im Prozess hinzu.
Wählen Sie nicht Docker-Support aktivieren aus. Sie fügen die Docker-Unterstützung später im Prozess hinzu.
Erstellen eines Web-API-Projekts
Fügen Sie der gleichen Lösung ein Projekt hinzu und nennen Sie es MyWebAPI. Wählen Sie API als Projekttyp aus und deaktivieren Sie das Kontrollkästchen für Konfigurieren für HTTPS. In diesem Design verwenden wir nur SSL für die Kommunikation mit dem Client, nicht für die Kommunikation zwischen Containern in derselben Webanwendung. Nur WebFrontEnd
benötigt HTTPS, und der Code in den Beispielen geht davon aus, dass Sie das Kontrollkästchen deaktiviert haben. Im Allgemeinen werden die von Visual Studio verwendeten .NET-Entwicklerzertifikate nur für Anforderungen für externe Container unterstützt, nicht für Container-zu-Container-Anforderungen.
Fügen Sie der gleichen Lösung ein Projekt hinzu und nennen Sie es MyWebAPI. Wählen Sie API als Projekttyp aus, und deaktivieren Sie das Kontrollkästchen Für HTTPS konfigurieren.
Anmerkung
In diesem Design verwenden wir nur HTTPS für die Kommunikation mit dem Client, nicht für die Kommunikation zwischen Containern in derselben Webanwendung. Nur
WebFrontEnd
benötigt HTTPS, und der Code in den Beispielen geht davon aus, dass Sie das Kontrollkästchen deaktiviert haben. Im Allgemeinen werden die von Visual Studio verwendeten .NET-Entwicklerzertifikate nur für Anforderungen für externe Container unterstützt, nicht für Container-zu-Container-Anforderungen.Fügen Sie Unterstützung für Azure Cache für Redis hinzu. Fügen Sie das NuGet-Paket
Microsoft.Extensions.Caching.StackExchangeRedis
hinzu (nichtStackExchange.Redis
). Fügen Sie in Program.csdie folgenden Zeilen direkt vorvar app = builder.Build()
hinzu: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"; });
Fügen Sie using-Direktiven in
Program.cs
fürMicrosoft.Extensions.Caching.Distributed
undMicrosoft.Extensions.Caching.StackExchangeRedis
hinzu.using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.StackExchangeRedis;
Löschen Sie im Web-API-Projekt die vorhandenen
WeatherForecast.cs
und Controller/WeatherForecastController.cs, und fügen Sie eine Datei unter Controllern, CounterController.cs, mit dem folgenden Inhalt hinzu: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; } } }
Der Dienst erhöht einen Indikator jedes Mal, wenn auf die Seite zugegriffen wird, und speichert den Zähler im Cache.
Hinzufügen von Code zum Aufrufen der Web-API
Öffnen Sie im
WebFrontEnd
Projekt die datei Index.cshtml.cs, und ersetzen Sie dieOnGet
-Methode durch den folgenden Code.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(); } }
Anmerkung
Für tatsächlich verwendeten Code sollte
HttpClient
nicht nach jeder Anforderung gelöscht werden. Bewährte Methoden finden Sie unter Verwenden von HttpClientFactory zum Implementieren widerstandsfähiger HTTP-Anforderungen.Fügen Sie in der datei
Index.cshtml
eine Zeile hinzu, umViewData["Message"]
anzuzeigen, damit die Datei wie der folgende Code aussieht:@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>
(nur 2.x ASP.NET) Fügen Sie nun im Web-API-Projekt Code zum Wertecontroller hinzu, um die von der API zurückgegebene Nachricht für den Aufruf anzupassen, den Sie von webfrontendhinzugefügt haben.
// GET api/values/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { return "webapi (with value " + id + ")"; }
Anmerkung
In .NET Core 3.1 und höher können Sie die bereitgestellte WeatherForecast-API anstelle dieses zusätzlichen Codes verwenden. Sie müssen jedoch den Aufruf von UseHttpsRedirection im Web-API-Projekt auskommentieren, da der Code HTTP verwendet, um den Aufruf anstelle von HTTPS auszuführen.
//app.UseHttpsRedirection();
Hinzufügen der Docker Compose-Unterstützung
Klicken Sie im
WebFrontEnd
-Projekt auf Hinzufügen > Unterstützung für Containerorchestrator. Das Dialogfeld Docker-Supportoptionen wird angezeigt.Wählen Sie Docker Compose aus.
Wählen Sie Ihr Zielbetriebssystem aus, z. B. Linux.
Visual Studio erstellt eine docker-compose.yml- und eine
.dockerignore
-Datei im Knoten docker-compose der Projektmappe. Dieses Projekt wird in fetter Schrift aufgeführt, was angibt, dass es sich um das Startprojekt handelt.Das docker-compose.yml sieht wie folgt aus:
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
Die in der ersten Zeile angegebene
version
ist die Docker Compose-Dateiversion. Normalerweise sollten Sie sie nicht ändern, da sie von den Tools verwendet wird, um zu verstehen, wie die Datei interpretiert wird.Die
.dockerignore
Datei enthält Dateitypen und Erweiterungen, die Docker nicht in den Container aufnehmen soll. Diese Dateien sind in der Regel der Entwicklungsumgebung und der Quellcodeverwaltung zugeordnet, nicht Teil der App oder des Diensts, die Sie entwickeln.Schauen Sie sich im Abschnitt Container Tools des Ausgabebereichs die Details zu den ausgeführten Befehlen an. Sie können sehen, dass das Befehlszeilentool
docker-compose
verwendet wird, um die Laufzeitcontainer zu konfigurieren und zu erstellen.Klicken Sie im Web-API-Projekt erneut mit der rechten Maustaste auf den Projektknoten, und wählen Sie dann Hinzufügen>Unterstützung für Containerorchestrator aus. Wählen Sie Docker Composeaus, und wählen Sie dann das gleiche Zielbetriebssystem aus.
Anmerkung
In diesem Schritt bietet Visual Studio das Erstellen einer Dockerfile-Datei an. Wenn Sie dies für ein Projekt tun, das bereits über Docker-Unterstützung verfügt, werden Sie aufgefordert, ob Sie die vorhandene Dockerfile-Datei überschreiben möchten. Wenn Sie Änderungen in Ihrer Dockerfile-Datei vorgenommen haben, die Sie behalten möchten, wählen Sie "Nein" aus.
Visual Studio nimmt einige Änderungen an Ihrer Docker Compose YML-Datei vor. Jetzt sind beide Dienste enthalten.
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfile
Das erste Projekt, dem Sie container-Orchestrierung hinzufügen, ist so eingerichtet, dass sie beim Ausführen oder Debuggen gestartet wird. Sie können die Startaktion in den Projekteigenschaften für das Docker-Compose-Projekt konfigurieren. Klicken Sie im Projektknoten Docker Compose mit der rechten Maustaste, um das Kontextmenü zu öffnen, und wählen Sie dann Eigenschaftenaus, oder verwenden Sie ALT+EINGABETASTE. Der folgende Screenshot zeigt die Eigenschaften, die Sie für die hier verwendete Lösung verwenden möchten. Sie können beispielsweise die Seite ändern, die geladen wird, indem Sie die Dienst-URL Eigenschaft anpassen.
Hier sehen Sie, was beim Starten angezeigt wird (die .NET Core 2.x-Version):
Die Web-App für .NET 3.1 zeigt die Wetterdaten im JSON-Format an.
Angenommen, Sie sind nur daran interessiert, den Debugger an WebFrontEnd angefügt zu haben, nicht an das Web-API-Projekt. Über die Menüleiste können Sie die Dropdownliste neben der Startschaltfläche verwenden, um ein Menü mit Debugoptionen anzuzeigen. wählen Sie Manage Docker Compose Launch Settingsaus.
Das Dialogfeld Docker Compose-Starteinstellungen verwalten wird angezeigt. Mit diesem Dialogfeld können Sie steuern, welche Teilmenge von Diensten während einer Debugsitzung gestartet wird, die mit oder ohne den angefügten Debugger gestartet werden, sowie den Startdienst und die URL. Weitere Informationen finden Sie unter Starten einer Teilmenge der Compose-Dienste.
Wählen Sie Neue aus, um ein neues Profil zu erstellen, und nennen Sie es
Debug WebFrontEnd only
. Legen Sie dann das Web-API-Projekt auf Start ohne Debuggingfest, lassen Sie das WebFrontEnd-Projekt so eingestellt, dass es mit dem Debuggen beginnt, und wählen Sie Speichernaus.Die neue Konfiguration wird als Standard für das nächste Drücken von F5 festgelegt.
Drücken Sie F5-, um zu bestätigen, dass sie wie erwartet funktioniert.
Herzlichen Glückwunsch, Sie führen eine Docker Compose-Anwendung mit einem benutzerdefinierten Docker Compose-Profil aus.
Öffnen Sie im
WebFrontEnd
Projekt die datei Index.cshtml.cs, und ersetzen Sie dieOnGet
-Methode durch den folgenden Code.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}"; } }
Anmerkung
Für tatsächlich verwendeten Code sollte
HttpClient
nicht nach jeder Anforderung gelöscht werden. Bewährte Methoden finden Sie unter Verwenden von HttpClientFactory zum Implementieren widerstandsfähiger HTTP-Anforderungen.Der angegebene URI verweist auf einen In der docker-compose.yml-Datei definierten Dienstnamen. Docker Compose richtet ein Standardnetzwerk für die Kommunikation zwischen Containern ein, die die aufgelisteten Dienstnamen als Hosts verwenden.
Der hier gezeigte Code funktioniert mit .NET 8 und höher, das ein Benutzerkonto in der Dockerfile ohne Administratorrechte einrichtet und Port 8080 verfügbar macht, da auf den HTTP-Standardport 80 nicht ohne erhöhte Rechte zugegriffen werden kann.
Fügen Sie in der datei
Index.cshtml
eine Zeile hinzu, umViewData["Message"]
anzuzeigen, damit die Datei wie der folgende Code aussieht:@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>
Dieser Code zeigt den Wert des Zählers an, der aus dem Web-API-Projekt zurückgegeben wird. Sie erhöht jedes Mal, wenn der Benutzer auf die Seite zugreift oder aktualisiert.
Hinzufügen der Docker Compose-Unterstützung
Klicken Sie im
WebFrontEnd
-Projekt auf Hinzufügen > Unterstützung für Containerorchestrator. Das Dialogfeld Docker-Supportoptionen wird angezeigt.Wählen Sie Docker Compose aus.
Visual Studio 17.12 und höher Wählen Sie die Gerüstoptionen für das WebFrontEnd-Projekt aus.
Visual Studio 17.11 und früher Wählen Sie Ihr Zielbetriebssystem, z. B. Linux.
Visual Studio erstellt eine docker-compose.yml- und eine
.dockerignore
-Datei im Knoten docker-compose der Projektmappe. Dieses Projekt wird in fetter Schrift aufgeführt, was angibt, dass es sich um das Startprojekt handelt.Die Datei docker-compose.yml wird wie folgt angezeigt:
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
Die
.dockerignore
Datei enthält Dateitypen und Erweiterungen, die Docker nicht in den Container aufnehmen soll. Diese Dateien sind in der Regel der Entwicklungsumgebung und der Quellcodeverwaltung zugeordnet, nicht Teil der App oder des Diensts, die Sie entwickeln.Sehen Sie sich den Abschnitt Container-Tools des Ausgabebereichs an, um Details zu den ausgeführten Befehlen zu erhalten. Sie können sehen, dass das Befehlszeilentool
docker-compose
verwendet wird, um die Laufzeitcontainer zu konfigurieren und zu erstellen.Klicken Sie im Web-API-Projekt erneut mit der rechten Maustaste auf den Projektknoten, und wählen Sie dann Hinzufügen>Unterstützung für Containerorchestrator aus. Wählen Sie Docker Composeaus, und wählen Sie dann das gleiche Zielbetriebssystem aus.
Anmerkung
In diesem Schritt bietet Visual Studio das Erstellen einer Dockerfile-Datei an. Wenn Sie dies für ein Projekt tun, das bereits über Docker-Unterstützung verfügt, werden Sie aufgefordert, ob Sie die vorhandene Dockerfile-Datei überschreiben möchten. Wenn Sie Änderungen in Ihrer Dockerfile-Datei vorgenommen haben, die Sie behalten möchten, wählen Sie "Nein" aus.
Visual Studio nimmt einige Änderungen an ihrer
docker-compose
YML-Datei vor. Jetzt sind beide Dienste enthalten.services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfile
Fügen Sie den Cache zur
docker-compose.yml
Datei hinzu:redis: image: redis
Stellen Sie sicher, dass sich der Einzug auf derselben Ebene befindet wie die anderen beiden Dienste.
(Visual Studio 17.13 oder höher) Die abhängigen Dienste zeigen ein häufiges Problem. Die HTTP-Anforderung auf der Hauptseite des Front-Ends kann sofort beim Starten der Anwendung ausgeführt werden, bevor der
mywebapi
-Dienst für den Empfang von Webanforderungen bereit ist. Wenn Sie Visual Studio 17.13 oder höher verwenden, können Sie die Docker Compose-Featuresdepends_on
undhealthcheck
in docker-compose.yml verwenden, um die Projekte in der richtigen Reihenfolge zu starten und dafür zu sorgen, dass sie bereit sind, bei Bedarf Anfragen zu bearbeiten. Siehe Docker Compose – Startreihenfolge.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
In diesem Beispiel verwendet die Integritätsprüfung
curl
, um zu überprüfen, ob der Dienst für die Verarbeitung von Anforderungen bereit ist. Wenn das verwendete Imagecurl
nicht installiert hat, fügen Sie Zeilen zurbase
-Stufe der MyWebAPI-Dockerfile hinzu, um es zu installieren. Dieser Schritt erfordert erhöhte Berechtigungen, aber Sie können die normalen Benutzerrechte nach der Installation wie hier gezeigt wiederherstellen (für die in diesem Beispiel verwendeten Debian-Images):USER root RUN apt-get update && apt-get install -y curl USER $APP_UID
Anmerkung
Wenn Sie eine Linux-Distro wie Alpine verwenden und
apt-get
nicht unterstützt wird, dann versuchen Sie stattdessenRUN apk --no-cache add curl
.Diese Docker Compose-Features erfordern eine Eigenschaftseinstellung in der Docker Compose-Projektdatei (
.dcproj
). Legen Sie die EigenschaftDependencyAwareStart
auf "true" fest:<PropertyGroup> <!-- existing properties --> <DependencyAwareStart>true</DependencyAwareStart> </PropertyGroup>
Diese Eigenschaft aktiviert eine andere Methode zum Starten der Container für das Debuggen, die die Dienstabhängigkeitsfeatures unterstützen.
Der
webfrontend
-Dienst wird erst gestartet, wenn dermywebapi
-Dienst gestartet wird und erfolgreich eine Webanforderung verarbeitet.Das erste Projekt, dem Sie container-Orchestrierung hinzufügen, ist so eingerichtet, dass sie beim Ausführen oder Debuggen gestartet wird. Sie können die Startaktion in der Projekteigenschaft für das Docker-Compose-Projekt konfigurieren. Klicken Sie auf dem Projektknoten Docker Compose mit der rechten Maustaste, um das Kontextmenü zu öffnen, und wählen Sie dann Eigenschaftenaus, oder verwenden Sie ALT+Eingabetaste. Sie können beispielsweise die Seite ändern, die geladen wird, indem Sie die Dienst-URL Eigenschaft anpassen.
Drücken Sie F5. Hier sehen Sie, was beim Start angezeigt wird:
Sie können die Container mithilfe des Fensters Container überwachen. Wenn das Fenster nicht angezeigt wird, drücken Sie das Suchfeld, drücken Sie STRG+K, STRG+O-, oder drücken Sie STRG+Q. Suchen Sie unter Featuresuche nach
containers
, und wählen Sie in der Liste Ansicht>Weitere Fenster>Container aus.Erweitern Sie den Knoten Lösungscontainer, und wählen Sie den Knoten für Ihr Docker Compose-Projekt aus, um kombinierte Protokolle auf der Registerkarte Protokolle dieses Fensters anzuzeigen.
Sie können auch den Knoten für einen einzelnen Container auswählen, um Protokolle, Umgebungsvariablen, das Dateisystem und andere Details anzuzeigen.
Einrichten von Startprofilen
Diese Lösung verfügt über einen Azure-Cache für Redis, aber es ist nicht effizient, den Cachecontainer jedes Mal neu zu erstellen, wenn Sie eine Debugsitzung starten. Um diese Situation zu vermeiden, können Sie ein paar Startprofile einrichten. Erstellen Sie ein Profil, um den Azure-Cache für Redis zu starten. Erstellen Sie ein zweites Profil, um die anderen Dienste zu starten. Das zweite Profil kann den Cachecontainer verwenden, der bereits ausgeführt wird. Über die Menüleiste können Sie die Dropdownliste neben der Startschaltfläche verwenden, um ein Menü mit Debugoptionen zu öffnen. Wählen Sie Verwalten der Docker Compose-Starteinstellungen aus.
Das Dialogfeld Docker Compose-Startoptionen verwalten wird angezeigt. Mit diesem Dialogfeld können Sie steuern, welche Teilmenge von Diensten während einer Debugsitzung gestartet wird, die mit oder ohne den angefügten Debugger gestartet werden, sowie den Startdienst und die URL. Weitere Informationen finden Sie unter Starten einer Teilmenge der Compose-Dienste.
Wählen Sie Neue aus, um ein neues Profil zu erstellen, und nennen Sie es
Start Redis
. Legen Sie dann den Redis-Container auf Ohne Debuggen starten und belassen Sie den anderen auf Nicht starten, und wählen Sie Speichern aus.Erstellen Sie dann ein weiteres Profil
Start My Services
, das Redis nicht startet, aber die beiden anderen Dienste startet.(Optional) Erstellen Sie ein drittes Profil
Start All
, um alles zu starten. Sie können "Start" auswählen, ohne für Redis zu debuggen.Wählen Sie Start Redis in der Dropdownliste auf der Visual Studio-Hauptsymbolleiste aus. Der Redis-Container erstellt und startet ohne Debugging. Sie können das Fenster Container verwenden, um zu sehen, dass es läuft. Wählen Sie als Nächstes "Meine Dienste starten" aus der Dropdownliste aus, und drücken Sie F5-, um sie zu starten. Jetzt können Sie den Cache-Container während vieler nachfolgender Debugsitzungen am Laufen halten. Jedes Mal, wenn Sie "Meine Dienste starten"verwenden, verwenden diese Dienste denselben Cachecontainer.
Herzlichen Glückwunsch, Sie führen eine Docker Compose-Anwendung mit einem benutzerdefinierten Docker Compose-Profil aus.
Nächste Schritte
Sehen Sie sich die Optionen für die Bereitstellung Ihrer -Container in Azurean.