Tutorial: Creare un'app multi-contenitore con Docker Compose
In questa esercitazione si apprenderà come gestire più contenitori e comunicare tra di essi quando si usa Strumenti contenitore in Visual Studio. La gestione di più contenitori richiede orchestrazione dei contenitori e richiede un agente di orchestrazione, ad esempio Docker Compose o Service Fabric. Per queste procedure, si usa Docker Compose. Docker Compose è ideale per il debug e il test locali nel corso del ciclo di sviluppo.
L'esempio completato creato in questa esercitazione è disponibile in GitHub all'indirizzo https://github.com/MicrosoftDocs/vs-tutorial-samples
nella cartella docker/ComposeSample.
Prerequisiti
- Docker Desktop
di Visual Studio 2019 con il carico di lavoro sviluppo multipiattaforma strumenti di Azure e/ocarico di lavoro sviluppo multipiattaforma .NET installato
- Docker Desktop
visual Studio 2022 con il carico di lavoro sviluppo multipiattaformastrumenti di Azure e/ocarico di lavoro sviluppo multipiattaforma .NET installato. Questa installazione include gli strumenti di sviluppo .NET 8.
Creare un progetto di applicazione Web
In Visual Studio creare un progetto ASP.NET Core Web App denominato WebFrontEnd
per creare un'applicazione Web con pagine Razor.
Non selezionare Abilita supporto Docker. Il supporto docker verrà aggiunto più avanti nel processo.
Non selezionare Abilita supporto Docker. Il supporto docker verrà aggiunto più avanti nel processo.
Creare un progetto API Web
Aggiungere un progetto alla stessa soluzione e chiamarlo MyWebAPI. Seleziona API come tipo di progetto e deseleziona la casella di controllo Configura per HTTPS. In questa progettazione si usa SSL solo per la comunicazione con il client, non per la comunicazione tra contenitori nella stessa applicazione Web. Solo WebFrontEnd
richiede HTTPS e il codice negli esempi presuppone che sia stata deselezionata tale casella di controllo. In generale, i certificati per sviluppatori .NET usati da Visual Studio sono supportati solo per le richieste da esterno a contenitore, non per le richieste da contenitore a contenitore.
Aggiungere un progetto alla stessa soluzione e chiamarlo MyWebAPI. Selezionare API come tipo di progetto e deselezionare la casella per Configura per HTTPS.
Nota
In questa progettazione si usa SOLO HTTPS per la comunicazione con il client, non per la comunicazione tra contenitori nella stessa applicazione Web. Solo
WebFrontEnd
richiede HTTPS e il codice negli esempi presuppone che sia stata deselezionata tale casella di controllo. In generale, i certificati per sviluppatori .NET usati da Visual Studio sono supportati solo per le richieste da esterno a contenitore, non per le richieste da contenitore a contenitore.Aggiungere il supporto per Azure Cache per Redis. Aggiungere il pacchetto NuGet
Microsoft.Extensions.Caching.StackExchangeRedis
(nonStackExchange.Redis
). In Program.csaggiungere le righe seguenti, subito prima divar 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"; });
Aggiungere direttive using in
Program.cs
perMicrosoft.Extensions.Caching.Distributed
eMicrosoft.Extensions.Caching.StackExchangeRedis
.using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.StackExchangeRedis;
Nel progetto API Web, eliminare i Controller esistenti
WeatherForecast.cs
e Controllers/WeatherForecastController.cs, e aggiungere un file nella cartella Controllers, CounterController.cs, con il contenuto seguente: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; } } }
Il servizio incrementa un contatore ogni volta che si accede alla pagina e archivia il contatore nella cache.
Aggiungere codice per chiamare l'API Web
Nel progetto
WebFrontEnd
aprire il file Index.cshtml.cs e sostituire il metodoOnGet
con il codice seguente.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(); } }
Nota
Nel codice reale non è consigliabile eliminare
HttpClient
dopo ogni richiesta. Per le procedure consigliate, vedere Usare HttpClientFactory per implementare richieste HTTP resilienti.Nel file
Index.cshtml
aggiungere una riga per visualizzareViewData["Message"]
in modo che il file sia simile al codice seguente:@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>
(solo ASP.NET 2.x) Ora nel progetto Web API, aggiungere il codice al controller Values per personalizzare il messaggio restituito dall'API per la chiamata che hai aggiunto da webfrontend.
// GET api/values/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { return "webapi (with value " + id + ")"; }
Nota
In .NET Core 3.1 e versioni successive è possibile usare l'API WeatherForecast fornita anziché questo codice aggiuntivo. Tuttavia, è necessario commentare la chiamata a UseHttpsRedirection nel progetto API Web perché il codice usa HTTP per effettuare la chiamata anziché HTTPS.
//app.UseHttpsRedirection();
Aggiungere il supporto di Docker Compose
Nel progetto
WebFrontEnd
, scegli Aggiungi supporto per l'orchestrazione dei contenitori >. Viene visualizzata la finestra di dialogo Opzioni di supporto Docker.Scegliere Docker Compose.
Scegliere il sistema operativo di destinazione, ad esempio Linux.
Visual Studio crea un file docker-compose.yml e un file
.dockerignore
all'interno del nodo docker-compose nella soluzione, e il progetto viene visualizzato in grassetto, indicando che è il progetto di avvio.Il docker-compose.yml viene visualizzato come segue:
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
Il
specificato nella prima riga è la versionedel file Docker Compose . In genere non è consigliabile modificarlo, perché viene usato dagli strumenti per comprendere come interpretare il file. Il file
.dockerignore
contiene i tipi di file e le estensioni che non si desidera che Docker includa nel contenitore. Questi file sono in genere associati all'ambiente di sviluppo e al controllo del codice sorgente, non a parte dell'app o del servizio in fase di sviluppo.Per informazioni dettagliate sui comandi in esecuzione, esaminare la sezione Strumenti Contenitore del riquadro di output. È possibile vedere che lo strumento da riga di comando
docker-compose
viene usato per configurare e creare i contenitori di runtime.Nel progetto API Web fare di nuovo clic con il pulsante destro del mouse sul nodo del progetto e scegliere Aggiungi>Supporto per l'orchestrazione dei container. Scegliere Docker Composee quindi selezionare lo stesso sistema operativo di destinazione.
Nota
In questo passaggio, Visual Studio offrirà di creare un Dockerfile. Se si esegue questa operazione in un progetto che dispone già del supporto docker, viene richiesto se si vuole sovrascrivere il Dockerfile esistente. Se hai apportato modifiche al Dockerfile che desideri mantenere, scegli no.
Visual Studio apporta alcune modifiche al file Docker Compose YML. Ora sono inclusi entrambi i servizi.
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfile
Il primo progetto a cui si aggiunge l'orchestrazione dei contenitori è configurato per l'avvio quando si lancia o si esegue il debug. È possibile configurare l'azione di avvio nelle Proprietà del progetto per il progetto Docker Compose. Nel nodo del progetto Docker Compose fare clic con il pulsante destro del mouse per aprire il menu di scelta rapida e quindi scegliere Proprietào usare ALT+INVIO. Lo screenshot seguente mostra le proprietà desiderate per la soluzione usata qui. Ad esempio, è possibile modificare la pagina caricata personalizzando la proprietà URL del servizio
. Ecco cosa viene visualizzato all'avvio (versione di .NET Core 2.x):
L'app Web per .NET 3.1 mostra i dati meteo in formato JSON.
Si supponga ora di essere interessati solo a avere il debugger collegato a WebFrontEnd, non al progetto API Web. Dalla barra dei menu è possibile usare l'elenco a discesa accanto al pulsante Start per visualizzare un menu di opzioni di debug; scegliere Gestisci impostazioni di avvio di Docker Compose.
Viene visualizzata la finestra di dialogo Gestisci impostazioni di avvio di Docker Compose. Con questa finestra di dialogo, puoi controllare quale insieme specifico di servizi viene avviato durante una sessione di debug, quali vengono avviati con o senza il debugger collegato e il servizio di avvio e l'URL di lancio. Vedi Avvia un subset di servizi Compose.
Scegliere Nuovo per creare un nuovo profilo e denominarlo
Debug WebFrontEnd only
. Impostare quindi il progetto API Web su Avvia senza eseguire il debug, lasciare il progetto WebFrontEnd impostato per iniziare con il debug e scegliere Salva.La nuova configurazione viene scelta come predefinita per il successivo F5.
Premere F5 per verificare che funzioni come previsto.
Congratulazioni, stai eseguendo un'applicazione Docker Compose con un profilo Docker Compose personalizzato.
Nel progetto
WebFrontEnd
aprire il file Index.cshtml.cs e sostituire il metodoOnGet
con il codice seguente.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}"; } }
Nota
Nel codice reale non è consigliabile eliminare
HttpClient
dopo ogni richiesta. Per le procedure consigliate, vedere Usare HttpClientFactory per implementare richieste HTTP resilienti.L'URI specificato fa riferimento a un nome di servizio definito nel file docker-compose.yml. Docker Compose configura una rete predefinita per la comunicazione tra contenitori usando i nomi dei servizi elencati come host.
Il codice illustrato di seguito funziona con .NET 8 e versioni successive, che configura un account utente nel Dockerfile senza privilegi di amministratore ed espone la porta 8080 perché la porta predefinita HTTP 80 non è accessibile senza privilegi elevati.
Nel file
Index.cshtml
aggiungere una riga per visualizzareViewData["Message"]
in modo che il file sia simile al codice seguente:@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>
Questo codice visualizza il valore del contatore restituito dal progetto API Web. Incrementa ogni volta che l'utente accede o aggiorna la pagina.
Aggiungere il supporto di Docker Compose
Nel progetto di
WebFrontEnd
, scegliere Aggiungi supporto per l'orchestratore di contenitori >. Viene visualizzata la finestra di dialogo Opzioni di supporto Docker.Scegliere Docker Compose.
Visual Studio 17.12 e versioni successive Scegliere le opzioni di scaffolding per il progetto WebFrontEnd.
Visual Studio 17.11 e versioni precedenti Scegliere il sistema operativo di destinazione, ad esempio Linux.
Visual Studio crea un file di
docker-compose.yml e il filenel nodo docker-compose nella soluzione, e il progetto compare in grassetto, indicando che è il progetto di avvio. Il docker-compose.yml viene visualizzato come segue:
services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile
Il file
.dockerignore
contiene i tipi di file e le estensioni che non si vuole includere nel contenitore Docker. Questi file sono in genere associati all'ambiente di sviluppo e al controllo del codice sorgente, non a parte dell'app o del servizio in fase di sviluppo.Per informazioni dettagliate sui comandi in esecuzione, esaminare la sezione strumenti del contenitore del riquadro di output. È possibile vedere che lo strumento da riga di comando
docker-compose
viene usato per configurare e creare i contenitori di runtime.Nel progetto API Web fare di nuovo clic con il pulsante destro del mouse sul nodo del progetto e scegliere Aggiungi>Supporto per l'orchestrazione dei contenitori. Scegliere Docker Composee quindi selezionare lo stesso sistema operativo di destinazione.
Nota
In questo passaggio, Visual Studio offrirà di creare un Dockerfile. Se si esegue questa operazione in un progetto che dispone già del supporto docker, viene richiesto se si vuole sovrascrivere il Dockerfile esistente. Se vuoi mantenere le modifiche apportate al Dockerfile, scegli no.
Visual Studio apporta alcune modifiche al file YML
docker-compose
. Ora sono inclusi entrambi i servizi.services: webfrontend: image: ${DOCKER_REGISTRY-}webfrontend build: context: . dockerfile: WebFrontEnd/Dockerfile mywebapi: image: ${DOCKER_REGISTRY-}mywebapi build: context: . dockerfile: MyWebAPI/Dockerfile
Aggiungere la cache al file
docker-compose.yml
:redis: image: redis
Assicurarsi che il rientro sia allo stesso livello degli altri due servizi.
(Visual Studio 17.13 o versione successiva) I servizi dipendenti manifestano un problema comune. La richiesta HTTP nella pagina principale del front-end potrebbe essere eseguita immediatamente all'avvio dell'applicazione, prima che il servizio
mywebapi
sia pronto per ricevere richieste Web. Se si usa Visual Studio 17.13 o versione successiva, è possibile usare le funzionalità di Docker Composedepends_on
ehealthcheck
in docker-compose.yml per avviare i progetti nella sequenza corretta e prepararli a soddisfare le richieste quando necessario. Vedere Docker Compose - Ordine di avvio.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 questo esempio, il controllo dello stato di integrità usa
curl
per verificare che il servizio sia pronto per elaborare le richieste. Se l'immagine in uso non hacurl
installato, aggiungere righe alla fasebase
del Dockerfile di MyWebAPI per installarlo. Questo passaggio richiede privilegi elevati, ma è possibile ripristinare i normali privilegi utente dopo l'installazione, come illustrato di seguito (per le immagini Debian usate in questo esempio):USER root RUN apt-get update && apt-get install -y curl USER $APP_UID
Nota
Se si usa una distribuzione Linux, ad esempio Alpine, che non supporta
apt-get
, provare inveceRUN apk --no-cache add curl
.Queste funzionalità di Docker Compose richiedono un'impostazione di proprietà nel file di progetto Docker Compose (
.dcproj
). Impostare la proprietàDependencyAwareStart
su true:<PropertyGroup> <!-- existing properties --> <DependencyAwareStart>true</DependencyAwareStart> </PropertyGroup>
Questa proprietà attiva un modo diverso per avviare i contenitori per il debug che supporta le funzionalità di dipendenza del servizio.
Con queste modifiche, il servizio
webfrontend
non verrà avviato fino a quandomywebapi
non si avvia e gestirà correttamente una richiesta web.Il primo progetto a cui si aggiunge l'orchestrazione dei contenitori è configurato per essere avviato quando si avvia o si esegue il debug. È possibile configurare l'azione di avvio nelle Proprietà del progetto per il progetto Docker Compose. Nel nodo del progetto Docker Compose fare clic con il pulsante destro del mouse per aprire il menu di scelta rapida e scegliere Proprietàoppure usare ALT+INVIO. Ad esempio, è possibile modificare la pagina caricata personalizzando la proprietà URL del servizio
. Premere F5. Ecco cosa viene visualizzato all'avvio:
È possibile monitorare i contenitori usando la finestra Contenitori. Se la finestra non viene visualizzata, usare la casella di ricerca, premere CTRL+K, CTRL+Ooppure premere CTRL+Q. In Ricerca funzionalitàcercare
containers
e scegliere Visualizza>Altri contenitori di Windows> dall'elenco.Espandi il nodo contenitori di soluzioni e scegli il nodo per il tuo progetto Docker Compose per visualizzare i log combinati nella scheda Log di questa finestra.
È anche possibile selezionare il nodo per un singolo contenitore per visualizzare log, variabili di ambiente, file system e altri dettagli.
Configurare i profili di avvio
Questa soluzione ha una Cache Redis di Azure, ma non è efficiente ricompilare il contenitore della cache ogni volta che si avvia una sessione di debug. Per evitare questa situazione, è possibile configurare un paio di profili di avvio. Crea un profilo per avviare la Cache Redis di Azure. Creare un secondo profilo per avviare gli altri servizi. Il secondo profilo può usare il contenitore della cache già in esecuzione. Dalla barra dei menu è possibile usare l'elenco a discesa accanto al pulsante Start per aprire un menu con le opzioni di debug. Selezionare Gestisci le impostazioni di avvio di Docker Compose.
La finestra di dialogo Gestisci impostazioni di avvio di Docker Compose viene visualizzata. Con questa finestra di dialogo, puoi controllare quale insieme di servizi viene avviato durante una sessione di debug, quali vengono avviati con o senza il debugger collegato e specificare il servizio di avvio e l'URL. Vedere Avviare un subset di servizi Compose.
Scegliere Nuovo per creare un nuovo profilo e denominarlo
Start Redis
. Impostare quindi il contenitore Redis su Avvia senza eseguire il debug, lasciare l'altro impostato su Non avviaree scegliere Salva.Creare quindi un altro profilo
Start My Services
che non avvia Redis, ma avvia gli altri due servizi.(Facoltativo) Creare un terzo profilo
Start All
per avviare tutto. È possibile scegliere Avvia senza eseguire il debug per Redis.Scegliere Avvia Redis dall'elenco a discesa sulla principale barra degli strumenti di Visual Studio. Il contenitore Redis compila e inizia senza eseguire il debug. È possibile usare la finestra Contenitori per verificare che sia in esecuzione. Scegliere quindi Start My Services dall'elenco a discesa e premere F5 per avviarli. È ora possibile mantenere il contenitore della cache in esecuzione in molte sessioni di debug successive. Ogni volta che si usa Avviare i servizi personali, questi servizi usano lo stesso contenitore di cache.
Congratulazioni, stai eseguendo un'applicazione Docker Compose con un profilo Docker Compose personalizzato.
Passaggi successivi
Esamina le opzioni per distribuire i contenitori in Azure.
Vedere anche
strumenti contenitore