Condividi tramite


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 multipiattaformastrumenti di Azure e/o carico di lavoro sviluppo multipiattaforma .NET installato
  • Docker Desktop
  • visual Studio 2022 con il carico di lavoro sviluppo multipiattaformastrumenti di Azure e/o carico 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 WebFrontEndper creare un'applicazione Web con pagine Razor.

Screenshot che mostra la creazione di un progetto ASP.NET Core Web App.

Non selezionare Abilita supporto Docker. Il supporto docker verrà aggiunto più avanti nel processo.

Screenshot della schermata Informazioni aggiuntive durante la creazione di un progetto Web. L'opzione Abilita supporto Docker non è selezionata.

Non selezionare Abilita supporto Docker. Il supporto docker verrà aggiunto più avanti nel processo.

Screenshot della schermata Informazioni aggiuntive durante la creazione di un progetto web. L'opzione per abilitare il supporto Docker non è selezionata.

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.

Screenshot della creazione del progetto Web API.

  1. 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.

    Screenshot della creazione del progetto API Web.

  2. Aggiungere il supporto per Azure Cache per Redis. Aggiungere il pacchetto NuGet Microsoft.Extensions.Caching.StackExchangeRedis (non StackExchange.Redis). In Program.csaggiungere le righe seguenti, subito prima di var 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";
       });
    
  3. Aggiungere direttive using in Program.cs per Microsoft.Extensions.Caching.Distributed e Microsoft.Extensions.Caching.StackExchangeRedis.

    using Microsoft.Extensions.Caching.Distributed;
    using Microsoft.Extensions.Caching.StackExchangeRedis;
    
  4. 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

  1. Nel progetto WebFrontEnd aprire il file Index.cshtml.cs e sostituire il metodo OnGet 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.

  2. Nel file Index.cshtml aggiungere una riga per visualizzare ViewData["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>
    
  3. (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

  1. Nel progetto WebFrontEnd, scegli Aggiungi supporto per l'orchestrazione dei contenitori >. Viene visualizzata la finestra di dialogo Opzioni di supporto Docker.

  2. Scegliere Docker Compose.

  3. Scegliere il sistema operativo di destinazione, ad esempio Linux.

    Screenshot della scelta del sistema operativo di destinazione.

    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.

    Screenshot di Esplora Soluzioni con il progetto Docker Compose aggiunto.

    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.

  4. 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
    
  5. 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 .

    Screenshot delle proprietà del progetto Docker Compose.

    Ecco cosa viene visualizzato all'avvio (versione di .NET Core 2.x):

    Screenshot dell'app Web in esecuzione.

    L'app Web per .NET 3.1 mostra i dati meteo in formato JSON.

  6. 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.

    screenshot della voce di menu Debug Gestisci impostazioni composizione.

    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.

    screenshot della finestra di dialogo Gestisci impostazioni di avvio di Docker 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.

  7. Premere F5 per verificare che funzioni come previsto.

Congratulazioni, stai eseguendo un'applicazione Docker Compose con un profilo Docker Compose personalizzato.

  1. Nel progetto WebFrontEnd aprire il file Index.cshtml.cs e sostituire il metodo OnGet 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.

  2. Nel file Index.cshtml aggiungere una riga per visualizzare ViewData["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

  1. Nel progetto di WebFrontEnd, scegliere Aggiungi supporto per l'orchestratore di contenitori >. Viene visualizzata la finestra di dialogo Opzioni di supporto Docker.

  2. Scegliere Docker Compose.

  3. Visual Studio 17.12 e versioni successive Scegliere le opzioni di scaffolding per il progetto WebFrontEnd.

    Screenshot che mostra la finestra di dialogo delle opzioni di impalcatura del contenitore per il progetto WebFrontEnd.

    Visual Studio 17.11 e versioni precedenti Scegliere il sistema operativo di destinazione, ad esempio Linux.

    Screenshot della scelta del sistema operativo di destinazione.

    Visual Studio crea un file di docker-compose.yml e il file nel nodo docker-compose nella soluzione, e il progetto compare in grassetto, indicando che è il progetto di avvio.

    Istantanea di Esplora Soluzioni con il progetto Docker Compose aggiunto.

    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.

  4. 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
    
  5. Aggiungere la cache al file docker-compose.yml:

    redis:
       image: redis
    

    Assicurarsi che il rientro sia allo stesso livello degli altri due servizi.

  6. (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 Compose depends_on e healthcheck 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 ha curl installato, aggiungere righe alla fase base 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 invece RUN 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 quando mywebapi non si avvia e gestirà correttamente una richiesta web.

  7. 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 .

    Screenshot delle proprietà del progetto Docker Compose.

  8. Premere F5. Ecco cosa viene visualizzato all'avvio:

    Screenshot dell'app Web in esecuzione.

  9. È 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 containerse scegliere Visualizza>Altri contenitori di Windows> dall'elenco.

  10. 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.

    Screenshot che mostra la visualizzazione della scheda Log nella finestra Contenitori.

    È 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

  1. 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.

    screenshot della voce di menu Debug Gestisci impostazioni composizione.

    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.

    screenshot della finestra di dialogo Gestisci impostazioni di avvio di Docker 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.

    Screenshot che mostra la creazione del profilo Redis che avvia solo il servizio Redis.

    Creare quindi un altro profilo Start My Services che non avvia Redis, ma avvia gli altri due servizi.

    Screenshot che mostra la creazione del profilo dei servizi che avvia gli altri servizi.

    (Facoltativo) Creare un terzo profilo Start All per avviare tutto. È possibile scegliere Avvia senza eseguire il debug per Redis.

  2. 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

Docker Compose

strumenti contenitore