Share via


Tutorial: Creación de una aplicación de varios contenedores con Docker Compose

En este tutorial aprenderá a administrar más de un contenedor y a comunicarse entre ellos mediante las herramientas de contenedor de Visual Studio. La administración de varios contenedores requiere orquestación de contenedor y un orquestador como Docker Compose o Service Fabric. Para estos procedimientos, usará Docker Compose. Docker Compose es ideal para las pruebas y la depuración locales durante el ciclo de desarrollo.

El ejemplo completado que creará en este tutorial se puede encontrar en GitHub en https://github.com/MicrosoftDocs/vs-tutorial-samples, en la carpeta docker/ComposeSample.

Requisitos previos

  • Docker Desktop
  • Visual Studio 2022 con las cargas de trabajo Desarrollo web, Azure Tools o Desarrollo multiplataforma de .NET instaladas. Esta instalación incluye las herramientas de desarrollo de .NET 8.

Creación de un proyecto de aplicación web

En Visual Studio, cree un proyecto de Aplicación web de ASP.NET Core, denominado WebFrontEnd, para crear una aplicación web con páginas de Razor.

Screenshot showing Create ASP.NET Core Web App project.

No seleccione Habilitar compatibilidad con Docker. La compatibilidad con Docker se agrega más adelante en el proceso.

Screenshot of the Additional information screen when creating a web project. The option to Enable Docker Support is not selected.

Nota:

En Visual Studio 2022 17.2 y posteriores, puede utilizar Azure Functions para este proyecto.

Screenshot showing Create ASP.NET Core Web App project.

No seleccione Habilitar compatibilidad con Docker. La compatibilidad con Docker se agrega más adelante en el proceso.

Screenshot of the Additional information screen when creating a web project. The option to Enable Docker Support is not selected.

Creación de un proyecto de API web

Agregue un proyecto a la misma solución y asígnele el nombre MyWebAPI. Seleccione API como tipo de proyecto y desactive la casilla de Configure for HTTPS (Configurar para HTTPS). En este diseño solo se usa SSL para la comunicación con el cliente, no para la comunicación entre contenedores de la misma aplicación web. Solo WebFrontEnd necesita HTTPS y en el código de los ejemplos se supone que ha desactivado esa casilla. En general, los certificados de desarrollador de .NET que usa Visual Studio solo se admiten para las solicitudes externas a contenedores, no para las solicitudes de contenedor a contenedor.

Screenshot of creating the Web API project.

  1. Agregue un proyecto a la misma solución y asígnele el nombre WebAPI. Seleccione API como tipo de proyecto y desactive la casilla de Configure for HTTPS (Configurar para HTTPS). En este diseño solo se usa SSL para la comunicación con el cliente, no para la comunicación entre contenedores de la misma aplicación web. Solo WebFrontEnd necesita HTTPS y en el código de los ejemplos se supone que ha desactivado esa casilla. En general, los certificados de desarrollador de .NET que usa Visual Studio solo se admiten para las solicitudes externas a contenedores, no para las solicitudes de contenedor a contenedor.

    Screenshot of creating the Web API project.

  2. Se ha agregado compatibilidad con Redis Cache. Agregue el paquete NuGet Microsoft.Extensions.Caching.StackExchangeRedis (no StackExchange.Redis). En Program.cs, agregue las líneas siguientes, justo antes de 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. Agregue directivas de uso en Program.cs para Microsoft.Extensions.Caching.Distributed y Microsoft.Extensions.Caching.StackExchangeRedis.

    using Microsoft.Extensions.Caching.Distributed;
    using Microsoft.Extensions.Caching.StackExchangeRedis;
    
  4. En el proyecto de Web API, elimine los archivos existentes WeatherForecast.cs y Controllers/WeatherForecastController.cs, y agregue un archivo en Controladores, CounterController.cs, con el siguiente contenido:

    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;
            }
        }
    }
    

    El servicio incrementa un contador cada vez que se accede a la página y almacena el contador en la caché de Redis.

Adición de código para llamar a la API web

  1. En el proyecto WebFrontEnd, abra el archivo Index.cshtml.cs y reemplace el método OnGet por el código siguiente.

     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

    En el código del mundo real, no se debe desechar HttpClient después de cada solicitud. Para obtener los procedimientos recomendados, vea Uso de HttpClientFactory para implementar solicitudes HTTP resistentes.

  2. En el archivo Index.cshtml, agregue una línea para mostrar ViewData["Message"] para que el archivo sea similar al código siguiente:

    @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. (ASP.NET 2.x solo) Ahora, en el proyecto de API web, agregue código al controlador de valores para personalizar el mensaje devuelto por la API para la llamada agregada desde webfrontend.

    // GET api/values/5
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
       return "webapi (with value " + id + ")";
    }
    

    Nota:

    En .NET Core 3.1 y versiones posteriores, puede usar la API WeatherForecast proporcionada en lugar de este código adicional. Sin embargo, debe marcar como comentario la llamada a UseHttpsRedirection en el proyecto de API web porque el código usa HTTP para realizar la llamada en lugar de HTTPS.

          //app.UseHttpsRedirection();
    

Agregue la compatibilidad con Docker Compose

  1. En el proyecto WebFrontEnd, seleccione Agregar > Compatibilidad con el orquestador de contenedores. Aparece el cuadro de diálogo Opciones de soporte técnico de Docker.

  2. Seleccione Docker Compose.

  3. Seleccione el sistema operativo de destino, por ejemplo, Linux.

    Screenshot of choosing the Target OS.

    Visual Studio crea un archivo docker-compose.yml y un archivo .dockerignore en el nodo docker-compose de la solución, y ese proyecto se muestra en negrita, lo que indica que es el proyecto de inicio.

    Screenshot of Solution Explorer with docker-compose project added.

    docker-compose.yml aparece de la manera siguiente:

    version: '3.4'
    
     services:
       webfrontend:
         image: ${DOCKER_REGISTRY-}webfrontend
         build:
           context: .
           dockerfile: WebFrontEnd/Dockerfile
    

    El valor version especificado en la primera línea es la versión del archivo de Docker Compose. Normalmente no debe cambiarlo, ya que las herramientas lo usan para comprender cómo interpretar el archivo.

    El archivo .dockerignore contiene los tipos de archivo y las extensiones que no quiere que Docker incluya en el contenedor. Normalmente, estos archivos están asociados al entorno de desarrollo y el control de código fuente, no forman parte de la aplicación o el servicio que se está desarrollando.

    Vea la sección Herramientas de contenedor del panel de salida para obtener detalles de los comandos que se ejecutan. Puede ver que la herramienta de línea de comandos docker-compose se usa para configurar y crear los contenedores en tiempo de ejecución.

  4. En el proyecto de API web, vuelva a hacer clic con el botón derecho en el nodo del proyecto y seleccione Agregar>Compatibilidad con el orquestador de contenedores. Seleccione Docker Compose y, después, el mismo sistema operativo de destino.

    Nota

    En este paso, Visual Studio le ofrece crear un Dockerfile. Si lo hace en un proyecto que ya tiene compatibilidad con Docker, se le pregunta si quiere sobrescribir el Dockerfile existente. Si ha realizado cambios que quiere conservar en el Dockerfile, seleccione no.

    Visual Studio realiza algunos cambios en el archivo YML de Docker Compose. Ahora ambos servicios están incluidos.

    version: '3.4'
    
    services:
      webfrontend:
        image: ${DOCKER_REGISTRY-}webfrontend
        build:
          context: .
          dockerfile: WebFrontEnd/Dockerfile
    
      mywebapi:
        image: ${DOCKER_REGISTRY-}mywebapi
        build:
          context: .
          dockerfile: MyWebAPI/Dockerfile
    
  5. El primer proyecto al que se añade la orquestación de contenedores está configurado para iniciarse al ejecutar o depurar. Puede configurar la acción de inicio en las Propiedades del proyecto del proyecto docker-compose. En el nodo del proyecto docker-compose, haga clic con el botón derecho para abrir el menú contextual y luego seleccione Propiedades o use Alt + Entrar. En la captura de pantalla siguiente se muestran las propiedades deseables para la solución que se usa aquí. Por ejemplo, puede cambiar la página que se carga mediante la personalización de la propiedad URL de servicio.

    Screenshot of docker-compose project properties.

    Esto es lo que se ve cuando se inicia (en la versión .NET Core 2.x):

    Screenshot of running web app.

    La aplicación web para .NET 3.1 muestra los datos meteorológicos en formato JSON.

  6. Ahora, supongamos que solo le interesa tener el depurador asociado a WebFrontEnd, no al proyecto de API web. En la barra de menús, puede usar la lista desplegable situada junto al botón Inicio para abrir un menú de opciones de depuración, y elija Administrar la configuración de inicio de Docker Compose.

    Screenshot of Debug Manage Compose Settings menu item.

    Aparece el cuadro de diálogo Administrar la configuración de inicio de Docker Compose. Con este cuadro de diálogo, puede controlar qué subconjunto de servicios se inicia durante una sesión de depuración, cuáles se inician con o sin el depurador asociado, así como el servicio de inicio y la dirección URL. Consulte Administración de perfiles de inicio para Docker Compose.

    Screenshot of Manage Docker Compose Launch Settings dialog box.

    Elija Nuevo para crear un nuevo perfil y asígnele el nombre Debug WebFrontEnd only. A continuación, establezca el proyecto de API web en Iniciar sin depurar, deje el proyecto WebFrontEnd establecido para comenzar con la depuración y elija Guardar.

    La nueva configuración se elige como valor predeterminado para el siguiente F5.

  7. Presione F5 para confirmar que funciona según lo previsto.

Enhorabuena, está ejecutando una aplicación Docker Compose con un perfil Docker Compose personalizado.

  1. En el proyecto WebFrontEnd, abra el archivo Index.cshtml.cs y reemplace el método OnGet por el código siguiente.

    public async Task OnGet()
    {
       using (var client = new System.Net.Http.HttpClient())
       {
          // Call *mywebapi*, and display its response in the page
          var request = new System.Net.Http.HttpRequestMessage();
          // webapi is the container name
          request.RequestUri = new Uri("http://webapi/Counter");
          var response = await client.SendAsync(request);
          string counter = await response.Content.ReadAsStringAsync();
          ViewData["Message"] = $"Counter value from cache :{counter}";
       }
    }
    

    Nota

    En el código del mundo real, no se debe desechar HttpClient después de cada solicitud. Para obtener los procedimientos recomendados, vea Uso de HttpClientFactory para implementar solicitudes HTTP resistentes.

  2. En el archivo Index.cshtml, agregue una línea para mostrar ViewData["Message"] para que el archivo sea similar al código siguiente:

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

    Este código muestra el valor del contador devuelto desde el proyecto de Web API.

Agregue la compatibilidad con Docker Compose

  1. En el proyecto WebFrontEnd, seleccione Agregar > Compatibilidad con el orquestador de contenedores. Aparece el cuadro de diálogo Opciones de soporte técnico de Docker.

  2. Seleccione Docker Compose.

  3. Seleccione el sistema operativo de destino, por ejemplo, Linux.

    Screenshot of choosing the Target OS.

    Visual Studio crea un archivo docker-compose.yml y un archivo .dockerignore en el nodo docker-compose de la solución, y ese proyecto se muestra en negrita, lo que indica que es el proyecto de inicio.

    Screenshot of Solution Explorer with docker-compose project added.

    docker-compose.yml aparece de la manera siguiente:

    version: '3.4'
    
     services:
       webfrontend:
         image: ${DOCKER_REGISTRY-}webfrontend
         build:
           context: .
           dockerfile: WebFrontEnd/Dockerfile
    

    El valor version especificado en la primera línea es la versión del archivo de Docker Compose. Normalmente no debe cambiarlo, ya que las herramientas lo usan para comprender cómo interpretar el archivo.

    El archivo .dockerignore contiene los tipos de archivo y las extensiones que no quiere que Docker incluya en el contenedor. Normalmente, estos archivos están asociados al entorno de desarrollo y el control de código fuente, no forman parte de la aplicación o el servicio que se está desarrollando.

    Vea la sección Herramientas de contenedor del panel de salida para obtener detalles de los comandos que se ejecutan. Puede ver que la herramienta de línea de comandos docker-compose se usa para configurar y crear los contenedores en tiempo de ejecución.

  4. En el proyecto de API web, vuelva a hacer clic con el botón derecho en el nodo del proyecto y seleccione Agregar>Compatibilidad con el orquestador de contenedores. Seleccione Docker Compose y, después, el mismo sistema operativo de destino.

    Nota

    En este paso, Visual Studio le ofrece crear un Dockerfile. Si lo hace en un proyecto que ya tiene compatibilidad con Docker, se le pregunta si quiere sobrescribir el Dockerfile existente. Si ha realizado cambios que quiere conservar en el Dockerfile, seleccione no.

    Visual Studio realiza algunos cambios en el archivo YML de Docker Compose. Ahora ambos servicios están incluidos.

    version: '3.4'
    
    services:
      webfrontend:
        image: ${DOCKER_REGISTRY-}webfrontend
        build:
          context: .
          dockerfile: WebFrontEnd/Dockerfile
    
      mywebapi:
        image: ${DOCKER_REGISTRY-}mywebapi
        build:
          context: .
          dockerfile: MyWebAPI/Dockerfile
    
  5. Agregue la caché de Redis al archivo docker.compose.yml:

    redis:
       image: redis
    

    Asegúrese de que la sangría está en el mismo nivel que los otros dos servicios.

  6. El primer proyecto al que se añade la orquestación de contenedores está configurado para iniciarse al ejecutar o depurar. Puede configurar la acción de inicio en las Propiedades del proyecto del proyecto docker-compose. En el nodo del proyecto docker-compose, haga clic con el botón derecho para abrir el menú contextual y luego seleccione Propiedades o use Alt+Entrar. Por ejemplo, puede cambiar la página que se carga mediante la personalización de la propiedad URL de servicio.

    Screenshot of docker-compose project properties.

  7. Presione F5. Esto es lo que se ve cuando se inicia:

    Screenshot of running web app.

  8. Los contenedores se pueden supervisar desde la ventana Contenedores. Si no ve la ventana, use el cuadro de búsqueda, presione Ctrl+K, Ctrl+O, o bien presione Ctrl+Q. En Búsqueda de características, busque containers y elija Ver>Otras ventanas>Contenedores en la lista.

  9. Expanda el nodo Contenedores de soluciones y elija el nodo del proyecto de Docker Compose para ver los registros combinados en la pestaña Registros de esta ventana.

    Screenshot showing viewing the Logs tab in the Containers window.

    También puede seleccionar el nodo de un contenedor individual para ver los registros, las variables de entorno, el sistema de archivos y otros detalles.

Configurar los perfiles de inicio

  1. Esta solución tiene una instancia de Redis Cache, pero no es eficaz volver a generar el contenedor de caché de Redis cada vez que inicie una sesión de depuración. Para evitar esa situación, puede configurar un par de perfiles de inicio. Cree un perfil para iniciar la caché de Redis. Cree un segundo perfil para iniciar los demás servicios. El segundo perfil puede usar el contenedor de caché de Redis que ya se está ejecutando. En la barra de menús, puede usar la lista desplegable situada junto al botón Iniciar para abrir un menú con opciones de depuración. Seleccione Administrar la configuración de inicio de Docker Compose.

    Screenshot of Debug Manage Compose Settings menu item.

    Aparece el cuadro de diálogo Administrar la configuración de inicio de Docker Compose. Con este cuadro de diálogo, puede controlar qué subconjunto de servicios se inicia durante una sesión de depuración, cuáles se inician con o sin el depurador asociado, así como el servicio de inicio y la dirección URL. Consulte Administración de perfiles de inicio para Docker Compose.

    Screenshot of Manage Docker Compose Launch Settings dialog box.

    Elija Nuevo para crear un nuevo perfil y asígnele el nombre Start Redis. A continuación, establezca el contenedor de Redis en Iniciar sin depurar, deje el otro conjunto en No iniciar y elija Guardar.

    Screenshot showing creating the Redis profile that starts the Redis service only.

    A continuación, cree otro perfil Start My Services que no inicie Redis, pero inicie los otros dos servicios.

    Screenshot showing creating the Services profile that starts the other services.

    (Opcional) Cree un tercer perfil Start All para iniciarlo todo. Puede elegir Iniciar sin depurar para Redis.

  2. Elija Iniciar Redis en la lista desplegable de la barra de herramientas principal Visual Studio, presione F5. El contenedor de Redis se compila e inicia. Puede usar la ventana Contenedores para ver que se está ejecutando. A continuación, elija Iniciar Mis servicios en la lista desplegable y presione F5 para iniciarlos. Ahora puede mantener el contenedor de caché de Redis en ejecución en muchas sesiones de depuración posteriores. Cada vez que use Iniciar Mis servicios, esos servicios usarán el mismo contenedor de caché de Redis.

Enhorabuena, está ejecutando una aplicación Docker Compose con un perfil Docker Compose personalizado.

Pasos siguientes

Vea las opciones para implementar contenedores en Azure.

Consulte también

Docker Compose
Herramientas de contenedor