Partilhar via


Fluxo de trabalho de desenvolvimento para aplicativos Docker

Gorjeta

Este conteúdo é um trecho do eBook, .NET Microservices Architecture for Containerized .NET Applications, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

Miniatura da capa do eBook .NET Microservices Architecture for Containerized .NET Applications.

O ciclo de vida de desenvolvimento do aplicativo começa no seu computador, como desenvolvedor, onde você codifica o aplicativo usando seu idioma preferido e o testa localmente. Com esse fluxo de trabalho, não importa qual idioma, estrutura e plataforma você escolha, você está sempre desenvolvendo e testando contêineres do Docker, mas fazendo isso localmente.

Cada contêiner (uma instância de uma imagem do Docker) inclui os seguintes componentes:

  • Uma seleção de sistema operacional, por exemplo, uma distribuição Linux, Windows Nano Server ou Windows Server Core.
  • Arquivos adicionados durante o desenvolvimento, por exemplo, código-fonte e binários de aplicativos.
  • Informações de configuração, como configurações de ambiente e dependências.

Fluxo de trabalho para desenvolver aplicativos baseados em contêiner do Docker

Esta seção descreve o fluxo de trabalho de desenvolvimento de loop interno para aplicativos baseados em contêiner do Docker. O fluxo de trabalho de loop interno significa que ele não está considerando o fluxo de trabalho de DevOps mais amplo, que pode incluir até a implantação de produção, e se concentra apenas no trabalho de desenvolvimento feito no computador do desenvolvedor. As etapas iniciais para configurar o ambiente não estão incluídas, uma vez que essas etapas são feitas apenas uma vez.

Um aplicativo é composto por seus próprios serviços mais bibliotecas adicionais (dependências). A seguir estão as etapas básicas que você geralmente executa ao criar um aplicativo Docker, conforme ilustrado na Figura 5-1.

Diagrama mostrando as sete etapas necessárias para criar um aplicativo em contêiner.

O processo de desenvolvimento para aplicativos Docker: 1 - Codifique seu aplicativo, 2 - Escreva Dockerfile/s, 3 - Crie imagens definidas em Dockerfile/s, 4 - (opcional) Componha serviços no arquivo docker-compose.yml, 5 - Execute contêiner ou aplicativo docker-compose, 6 - Teste seu aplicativo ou microsserviços, 7 - Empurre para repo e repita.

Figura 5-1. Fluxo de trabalho passo a passo para desenvolver aplicativos em contêineres do Docker

Nesta seção, todo esse processo é detalhado e cada etapa principal é explicada concentrando-se em um ambiente do Visual Studio.

Quando você estiver usando uma abordagem de desenvolvimento de editor/CLI (por exemplo, Visual Studio Code mais Docker CLI no macOS ou Windows), você precisa saber cada etapa, geralmente com mais detalhes do que se estiver usando o Visual Studio. Para obter mais informações sobre como trabalhar em um ambiente CLI, consulte o e-book Containerized Docker Application lifecycle with Microsoft Platforms and Tools.

Quando você está usando o Visual Studio 2022, muitas dessas etapas são tratadas para você, o que melhora drasticamente sua produtividade. Isso é especialmente verdadeiro quando você está usando o Visual Studio 2022 e visando aplicativos de vários contêineres. Por exemplo, com apenas um clique do mouse, o Visual Studio adiciona o Dockerfile arquivo e docker-compose.yml aos seus projetos com a configuração para seu aplicativo. Quando você executa o aplicativo no Visual Studio, ele cria a imagem do Docker e executa o aplicativo de vários contêineres diretamente no Docker; ele ainda permite que você depure vários contêineres ao mesmo tempo. Esses recursos aumentarão sua velocidade de desenvolvimento.

No entanto, só porque o Visual Studio torna essas etapas automáticas não significa que você não precisa saber o que está acontecendo por baixo com o Docker. Portanto, as orientações a seguir detalham cada etapa.

Imagem para o Passo 1.

Passo 1. Comece a codificar e crie sua linha de base inicial de aplicativo ou serviço

O desenvolvimento de um aplicativo Docker é semelhante à maneira como você desenvolve um aplicativo sem o Docker. A diferença é que, ao desenvolver para o Docker, você está implantando e testando seu aplicativo ou serviços em execução em contêineres do Docker em seu ambiente local (uma configuração de VM Linux pelo Docker ou diretamente o Windows se estiver usando contêineres do Windows).

Configurar seu ambiente local com o Visual Studio

Para começar, verifique se o Docker Desktop para Windows para Windows está instalado, conforme explicado nas instruções a seguir:

Introdução ao Docker Desktop para Windows

Além disso, você precisa do Visual Studio 2022 versão 17.0, com a carga de trabalho de desenvolvimento .ASP.NET e Web instalada, como mostra a Figura 5-2.

Captura de tela da seleção de desenvolvimento de plataforma cruzada do .NET Core.

Figura 5-2. Selecionando a carga de trabalho de desenvolvimento ASP.NET e Web durante a instalação do Visual Studio 2022

Você pode começar a codificar seu aplicativo em .NET simples (geralmente no .NET Core ou posterior se estiver planejando usar contêineres) antes mesmo de habilitar o Docker em seu aplicativo e implantar e testar no Docker. No entanto, é recomendável que você comece a trabalhar no Docker o mais rápido possível, porque esse será o ambiente real e quaisquer problemas podem ser descobertos o mais rápido possível. Isso é incentivado porque o Visual Studio facilita tanto o trabalho com o Docker que quase parece transparente — o melhor exemplo ao depurar aplicativos de vários contêineres do Visual Studio.

Recursos adicionais

Imagem para o Passo 2.

Você precisa de um Dockerfile para cada imagem personalizada que deseja criar; você também precisa de um Dockerfile para cada contêiner a ser implantado, quer implante automaticamente a partir do Visual Studio ou manualmente usando a CLI do Docker (comandos docker run e docker-compose). Se seu aplicativo contiver um único serviço personalizado, você precisará de um único Dockerfile. Se seu aplicativo contiver vários serviços (como em uma arquitetura de microsserviços), você precisará de um Dockerfile para cada serviço.

O Dockerfile é colocado na pasta raiz do seu aplicativo ou serviço. Ele contém os comandos que informam ao Docker como configurar e executar seu aplicativo ou serviço em um contêiner. Você pode criar manualmente um Dockerfile no código e adicioná-lo ao seu projeto junto com suas dependências .NET.

Com o Visual Studio e suas ferramentas para Docker, essa tarefa requer apenas alguns cliques do mouse. Quando você cria um novo projeto no Visual Studio 2022, há uma opção chamada Enable Docker Support, como mostra a Figura 5-3.

Captura de tela mostrando a caixa de seleção Ativar suporte ao Docker.

Figura 5-3. Habilitando o suporte ao Docker ao criar um novo projeto ASP.NET Core no Visual Studio 2022

Você também pode habilitar o suporte ao Docker em um projeto de aplicativo Web ASP.NET Core existente clicando com o botão direito do mouse no projeto no Gerenciador de Soluções e selecionando Adicionar>Suporte ao Docker..., como mostra a Figura 5-4.

Captura de tela mostrando a opção Suporte do Docker no menu Adicionar.

Figura 5-4. Habilitando o suporte ao Docker em um projeto existente do Visual Studio 2022

Essa ação adiciona um Dockerfile ao projeto com a configuração necessária e só está disponível em ASP.NET projetos principais.

De forma semelhante, o Visual Studio também pode adicionar um docker-compose.yml arquivo para toda a solução com a opção Add > Container Orchestrator Support.... Na etapa 4, exploraremos essa opção com mais detalhes.

Usando uma imagem oficial existente do .NET Docker

Normalmente, você cria uma imagem personalizada para seu contêiner sobre uma imagem base obtida de um repositório oficial, como o registro do Docker Hub . Isso é precisamente o que acontece quando você habilita o suporte ao Docker no Visual Studio. Seu Dockerfile usará uma imagem existente dotnet/core/aspnet .

Anteriormente, explicamos quais imagens e repositórios do Docker você pode usar, dependendo da estrutura e do sistema operacional escolhido. Por exemplo, se você quiser usar o ASP.NET Core (Linux ou Windows), a imagem a ser usada é mcr.microsoft.com/dotnet/aspnet:8.0. Portanto, você só precisa especificar qual imagem base do Docker você usará para seu contêiner. Você faz isso adicionando FROM mcr.microsoft.com/dotnet/aspnet:8.0 ao seu Dockerfile. Isso é executado automaticamente pelo Visual Studio, mas se você fosse atualizar a versão, você atualiza esse valor.

O uso de um repositório de imagens .NET oficial do Docker Hub com um número de versão garante que os mesmos recursos de linguagem estejam disponíveis em todas as máquinas (incluindo desenvolvimento, teste e produção).

O exemplo a seguir mostra um Dockerfile de exemplo para um contêiner ASP.NET Core.

FROM mcr.microsoft.com/dotnet/aspnet:8.0
ARG source
WORKDIR /app
EXPOSE 80
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", " MySingleContainerWebApp.dll "]

Neste caso, a imagem é baseada na versão 8.0 da imagem oficial do ASP.NET Core Docker (multi-arch para Linux e Windows). Este é o cenário FROM mcr.microsoft.com/dotnet/aspnet:8.0. (Para obter mais informações sobre essa imagem base, consulte a página ASP.NET Core Docker Image .) No Dockerfile, você também precisa instruir o Docker a escutar na porta TCP que você usará em tempo de execução (neste caso, a porta 80, conforme configurado com a configuração EXPOS).

Você pode especificar definições de configuração adicionais no Dockerfile, dependendo do idioma e da estrutura que estiver usando. Por exemplo, a linha ENTRYPOINT com ["dotnet", "MySingleContainerWebApp.dll"] diz ao Docker para executar um aplicativo .NET. Se você estiver usando o SDK e a CLI do .NET (CLI dotnet) para criar e executar o aplicativo .NET, essa configuração será diferente. A conclusão é que a linha ENTRYPOINT e outras configurações serão diferentes dependendo do idioma e da plataforma que você escolher para seu aplicativo.

Recursos adicionais

Usando repositórios de imagens multi-arch

Um único repositório pode conter variantes de plataforma, como uma imagem do Linux e uma imagem do Windows. Esse recurso permite que fornecedores como a Microsoft (criadores de imagens base) criem um único repositório para cobrir várias plataformas (ou seja, Linux e Windows). Por exemplo, o repositório .NET disponível no registro do Docker Hub fornece suporte para Linux e Windows Nano Server usando o mesmo nome de repositório.

Se você especificar uma tag, segmente uma plataforma explícita como nos seguintes casos:

  • mcr.microsoft.com/dotnet/aspnet:8.0-bullseye-slim
    Destinos: somente tempo de execução do .NET 8 no Linux

  • mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-ltsc2022
    Destinos: somente tempo de execução do .NET 8 no Windows Nano Server

Mas, se você especificar o mesmo nome de imagem, mesmo com a mesma tag, as imagens de vários arcos (como a aspnet imagem) usarão a versão Linux ou Windows, dependendo do sistema operacional host do Docker que você está implantando, conforme mostrado no exemplo a seguir:

  • mcr.microsoft.com/dotnet/aspnet:8.0
    Multi-arch: .NET 8 somente tempo de execução no Linux ou Windows Nano Server, dependendo do sistema operacional host do Docker

Dessa forma, quando você puxa uma imagem de um host Windows, ele puxa a variante do Windows, e puxar o mesmo nome de imagem de um host Linux puxa a variante Linux.

Compilações de vários estágios no Dockerfile

O Dockerfile é semelhante a um script em lote. Semelhante ao que você faria se tivesse que configurar a máquina a partir da linha de comando.

Ele começa com uma imagem base que configura o contexto inicial, é como o sistema de arquivos de inicialização, que fica no topo do sistema operacional host. Não é um sistema operacional, mas você pode pensar nele como "o" sistema operacional dentro do contêiner.

A execução de cada linha de comando cria uma nova camada no sistema de arquivos com as alterações da anterior, de modo que, quando combinada, produz o sistema de arquivos resultante.

Como cada nova camada "descansa" sobre a anterior e o tamanho da imagem resultante aumenta a cada comando, as imagens podem ficar muito grandes se tiverem que incluir, por exemplo, o SDK necessário para criar e publicar um aplicativo.

É aqui que as construções de vários estágios entram na trama (a partir do Docker 17.05 e superior) para fazer sua mágica.

A ideia central é que você pode separar o processo de execução do Dockerfile em estágios, onde um estágio é uma imagem inicial seguida por um ou mais comandos, e o último estágio determina o tamanho final da imagem.

Em suma, as compilações de vários estágios permitem dividir a criação em diferentes "fases" e, em seguida, montar a imagem final, tirando apenas os diretórios relevantes dos estágios intermediários. A estratégia geral para usar esse recurso é:

  1. Use uma imagem SDK base (não importa o tamanho), com tudo o que é necessário para criar e publicar o aplicativo em uma pasta e, em seguida,

  2. Use uma imagem base, pequena e somente em tempo de execução e copie a pasta de publicação do estágio anterior para produzir uma pequena imagem final.

Provavelmente, a melhor maneira de entender vários estágios é passar por um Dockerfile em detalhes, linha por linha, então vamos começar com o Dockerfile inicial criado pelo Visual Studio ao adicionar suporte ao Docker a um projeto e entraremos em algumas otimizações mais tarde.

O Dockerfile inicial pode ter esta aparência:

 1  FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
 2  WORKDIR /app
 3  EXPOSE 80
 4
 5  FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
 6  WORKDIR /src
 7  COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj …
 8  COPY src/BuildingBlocks/HealthChecks/src/Microsoft.AspNetCore.HealthChecks …
 9  COPY src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions.HealthChecks …
10  COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/ …
11  COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj …
12  COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj …
13  COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj …
14  COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization …
15  COPY src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions …
16  COPY src/BuildingBlocks/HealthChecks/src/Microsoft.Extensions …
17  RUN dotnet restore src/Services/Catalog/Catalog.API/Catalog.API.csproj
18  COPY . .
19  WORKDIR /src/src/Services/Catalog/Catalog.API
20  RUN dotnet build Catalog.API.csproj -c Release -o /app
21
22  FROM build AS publish
23  RUN dotnet publish Catalog.API.csproj -c Release -o /app
24
25  FROM base AS final
26  WORKDIR /app
27  COPY --from=publish /app .
28  ENTRYPOINT ["dotnet", "Catalog.API.dll"]

E estes são os detalhes, linha por linha:

  • Linha #1: Comece um estágio com uma "pequena" imagem base somente em tempo de execução, chame-a de base para referência.

  • Linha #2: Crie o diretório /app na imagem.

  • Linha #3: Exponha a porta 80.

  • Linha #5: Comece uma nova etapa com a imagem "grande" para construção/publicação. Chame-o de build para referência.

  • Linha #6: Crie o diretório /src na imagem.

  • Linha #7: Até a linha 16, copie os arquivos de projeto .csproj referenciados para poder restaurar pacotes mais tarde.

  • Linha #17: Restaure pacotes para o projeto Catalog.API e os projetos referenciados.

  • Linha #18: Copie toda a árvore de diretórios da solução (exceto os arquivos/diretórios incluídos no arquivo .dockerignore ) para o diretório /src na imagem.

  • Linha #19: Altere a pasta atual para o projeto Catalog.API .

  • Linha #20: Crie o projeto (e outras dependências do projeto) e a saída para o diretório /app na imagem.

  • Linha #22: Comece uma nova etapa continuando a partir da compilação. Chame-o de publicar para referência.

  • Linha #23: Publique o projeto (e as dependências) e a saída para o diretório /app na imagem.

  • Linha #25: Comece uma nova etapa continuando da base e chame-a de final.

  • Linha #26: Altere o diretório atual para /app.

  • Linha #27: Copie o diretório /app da publicação do estágio para o diretório atual.

  • Linha #28: Defina o comando a ser executado quando o contêiner for iniciado.

Agora vamos explorar algumas otimizações para melhorar todo o desempenho do processo que, no caso do eShopOnContainers, significa cerca de 22 minutos ou mais para construir a solução completa em contêineres Linux.

Você aproveitará o recurso de cache de camada do Docker, que é bastante simples: se a imagem base e os comandos forem os mesmos de alguns executados anteriormente, ele pode apenas usar a camada resultante sem a necessidade de executar os comandos, economizando tempo.

Então, vamos nos concentrar no estágio de construção, as linhas 5-6 são basicamente as mesmas, mas as linhas 7-17 são diferentes para cada serviço do eShopOnContainers, então elas têm que ser executadas todas as vezes, no entanto, se você mudou as linhas 7-16 para:

COPY . .

Então seria exatamente o mesmo para todos os serviços, copiaria toda a solução e criaria uma camada maior, mas:

  1. O processo de cópia só seria executado na primeira vez (e ao reconstruir se um arquivo for alterado) e usaria o cache para todos os outros serviços e

  2. Como a imagem maior ocorre em um estágio intermediário, isso não afeta o tamanho final da imagem.

A próxima otimização significativa envolve o restore comando executado na linha 17, que também é diferente para cada serviço de eShopOnContainers. Se você alterar essa linha para apenas:

RUN dotnet restore

Restauraria os pacotes para toda a solução, mas, mais uma vez, fá-lo-ia apenas uma vez, em vez das 15 vezes com a estratégia atual.

No entanto, dotnet restore só é executado se houver um único projeto ou arquivo de solução na pasta, então conseguir isso é um pouco mais complicado e a maneira de resolvê-lo, sem entrar em muitos detalhes, é esta:

  1. Adicione as seguintes linhas a .dockerignore:

    • *.sln, para ignorar todos os arquivos de solução na árvore de pastas principais

    • !eShopOnContainers-ServicesAndWebApps.sln, para incluir apenas este ficheiro de solução.

  2. Inclua o /ignoreprojectextensions:.dcproj argumento para dotnet restore, para que ele também ignore o projeto docker-compose e restaure apenas os pacotes para a solução eShopOnContainers-ServicesAndWebApps.

Para a otimização final, acontece apenas que a linha 20 é redundante, pois a linha 23 também constrói o aplicativo e vem, em essência, logo após a linha 20, então vai outro comando demorado.

O arquivo resultante é:

 1  FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
 2  WORKDIR /app
 3  EXPOSE 80
 4
 5  FROM mcr.microsoft.com/dotnet/sdk:8.0 AS publish
 6  WORKDIR /src
 7  COPY . .
 8  RUN dotnet restore /ignoreprojectextensions:.dcproj
 9  WORKDIR /src/src/Services/Catalog/Catalog.API
10  RUN dotnet publish Catalog.API.csproj -c Release -o /app
11
12  FROM base AS final
13  WORKDIR /app
14  COPY --from=publish /app .
15  ENTRYPOINT ["dotnet", "Catalog.API.dll"]

Criando sua imagem base do zero

Você pode criar sua própria imagem base do Docker do zero. Esse cenário não é recomendado para alguém que está começando com o Docker, mas se você quiser definir os bits específicos de sua própria imagem base, poderá fazê-lo.

Recursos adicionais

Imagem para o Passo 3.

Passo 3. Crie suas imagens personalizadas do Docker e incorpore seu aplicativo ou serviço nelas

Para cada serviço em seu aplicativo, você precisa criar uma imagem relacionada. Se o seu aplicativo é composto por um único serviço ou aplicativo Web, você só precisa de uma única imagem.

Observe que as imagens do Docker são criadas automaticamente para você no Visual Studio. As etapas a seguir são necessárias apenas para o fluxo de trabalho do editor/CLI e explicadas para clareza sobre o que acontece por baixo.

Você, como desenvolvedor, precisa desenvolver e testar localmente até enviar um recurso concluído ou alterar para seu sistema de controle de origem (por exemplo, para o GitHub). Isso significa que você precisa criar as imagens do Docker e implantar contêineres em um host Docker local (VM Windows ou Linux) e executar, testar e depurar nesses contêineres locais.

Para criar uma imagem personalizada em seu ambiente local usando a CLI do Docker e seu Dockerfile, você pode usar o comando docker build, como na Figura 5-5.

Captura de tela mostrando a saída do console do comando docker build.

Figura 5-5. Criando uma imagem personalizada do Docker

Opcionalmente, em vez de executar diretamente a compilação do docker a partir da pasta do projeto, você pode primeiro gerar uma pasta implantável com as bibliotecas e binários .NET necessários executando dotnet publishe, em seguida, usar o docker build comando.

Isso criará uma imagem do Docker com o nome cesardl/netcore-webapi-microservice-docker:first. Nesse caso, :first é uma tag que representa uma versão específica. Você pode repetir esta etapa para cada imagem personalizada que precisa criar para seu aplicativo Docker composto.

Quando um aplicativo é feito de vários contêineres (ou seja, é um aplicativo de vários contêineres), você também pode usar o docker-compose up --build comando para criar todas as imagens relacionadas com um único comando usando os metadados expostos nos arquivos de docker-compose.yml relacionados.

Você pode encontrar as imagens existentes em seu repositório local usando o comando docker images, como mostra a Figura 5-6.

Saída do console a partir de imagens docker de comando, mostrando imagens existentes.

Figura 5-6. Visualizando imagens existentes usando o comando docker images

Criando imagens do Docker com o Visual Studio

Quando você usa o Visual Studio para criar um projeto com suporte ao Docker, você não cria explicitamente uma imagem. Em vez disso, a imagem é criada para você quando você pressiona F5 (ou Ctrl+F5) para executar o aplicativo ou serviço dockerizado. Esta etapa é automática no Visual Studio e você não verá isso acontecer, mas é importante que você saiba o que está acontecendo por baixo.

Imagem para o Passo 4 opcional.

Passo 4. Defina seus serviços em docker-compose.yml ao criar um aplicativo Docker de vários contêineres

O arquivo docker-compose.yml permite definir um conjunto de serviços relacionados a serem implantados como um aplicativo composto com comandos de implantação. Ele também configura suas relações de dependência e configuração de tempo de execução.

Para usar um arquivo docker-compose.yml, você precisa criar o arquivo em sua pasta de solução principal ou raiz, com conteúdo semelhante ao do exemplo a seguir:

version: '3.4'

services:

  webmvc:
    image: eshop/web
    environment:
      - CatalogUrl=http://catalog-api
      - OrderingUrl=http://ordering-api
    ports:
      - "80:80"
    depends_on:
      - catalog-api
      - ordering-api

  catalog-api:
    image: eshop/catalog-api
    environment:
      - ConnectionString=Server=sqldata;Port=1433;Database=CatalogDB;…
    ports:
      - "81:80"
    depends_on:
      - sqldata

  ordering-api:
    image: eshop/ordering-api
    environment:
      - ConnectionString=Server=sqldata;Database=OrderingDb;…
    ports:
      - "82:80"
    extra_hosts:
      - "CESARDLBOOKVHD:10.0.75.1"
    depends_on:
      - sqldata

  sqldata:
    image: mcr.microsoft.com/mssql/server:latest
    environment:
      - SA_PASSWORD=[PLACEHOLDER]
      - ACCEPT_EULA=Y
    ports:
      - "5433:1433"

Importante

A Microsoft recomenda que você use o fluxo de autenticação mais seguro disponível. Se você estiver se conectando ao SQL do Azure, as Identidades Gerenciadas para recursos do Azure serão o método de autenticação recomendado.

Este arquivo docker-compose.yml é uma versão simplificada e mesclada. Ele contém dados de configuração estáticos para cada contêiner (como o nome da imagem personalizada), que são sempre necessários, e informações de configuração que podem depender do ambiente de implantação, como a cadeia de conexão. Em seções posteriores, você aprenderá como dividir a configuração do docker-compose.yml em vários arquivos de composição do docker e substituir valores dependendo do ambiente e do tipo de execução (depuração ou versão).

O exemplo de arquivo docker-compose.yml define quatro serviços: o webmvc serviço (um aplicativo Web), dois microsserviços (ordering-api e basket-api) e um contêiner de fonte de dados, sqldata, com base no SQL Server para Linux em execução como um contêiner. Cada serviço será implantado como um contêiner, portanto, uma imagem do Docker é necessária para cada um.

O arquivo docker-compose.yml especifica não apenas quais contêineres estão sendo usados, mas como eles são configurados individualmente. Por exemplo, a definição de webmvc contêiner no arquivo .yml:

  • Usa uma imagem pré-criada eshop/web:latest . No entanto, você também pode configurar a imagem a ser criada como parte da execução docker-compose com uma configuração adicional baseada em uma seção build: no arquivo docker-compose.

  • Inicializa duas variáveis de ambiente (CatalogUrl e OrderingUrl).

  • Encaminha a porta 80 exposta no contêiner para a porta externa 80 na máquina host.

  • Vincula o aplicativo Web ao catálogo e ao serviço de pedidos com a configuração depends_on. Isso faz com que o serviço aguarde até que esses serviços sejam iniciados.

Revisitaremos o arquivo docker-compose.yml em uma seção posterior, quando abordarmos como implementar microsserviços e aplicativos de vários contêineres.

Trabalhando com docker-compose.yml no Visual Studio 2022

Além de adicionar um Dockerfile a um projeto, como mencionamos anteriormente, o Visual Studio 2017 (a partir da versão 15.8) pode adicionar suporte a orquestrador para Docker Compose a uma solução.

Quando você adiciona suporte ao orquestrador de contêiner, como mostra a Figura 5-7, pela primeira vez, o Visual Studio cria o Dockerfile para o projeto e cria um novo projeto (seção de serviço) em sua solução com vários arquivos globais docker-compose*.yml e, em seguida, adiciona o projeto a esses arquivos. Em seguida, você pode abrir os arquivos docker-compose.yml e atualizá-los com recursos adicionais.

Repita essa operação para cada projeto que você deseja incluir no arquivo docker-compose.yml.

No momento em que este artigo foi escrito, o Visual Studio oferece suporte a orquestradores do Docker Compose .

Captura de tela mostrando a opção Suporte ao Container Orchestrator no menu de contexto do projeto.

Figura 5-7. Adicionando suporte ao Docker no Visual Studio 2022 clicando com o botão direito do mouse em um projeto ASP.NET Core

Depois de adicionar o suporte ao orchestrator à sua solução no Visual Studio, você também verá um novo nó (no docker-compose.dcproj arquivo de projeto) no Gerenciador de Soluções que contém os arquivos de docker-compose.yml adicionados, como mostra a Figura 5-8.

Captura de tela do nó docker-compose no Gerenciador de Soluções.

Figura 5-8. O nó da árvore docker-compose adicionado no Gerenciador de Soluções do Visual Studio 2022

Você pode implantar um aplicativo de vários contêineres com um único arquivo docker-compose.yml usando o docker-compose up comando. No entanto, o Visual Studio adiciona um grupo deles para que você possa substituir valores dependendo do ambiente (desenvolvimento ou produção) e do tipo de execução (versão ou depuração). Essa capacidade será explicada em seções posteriores.

Imagem para o Passo 5.

Passo 5. Crie e execute seu aplicativo Docker

Se seu aplicativo tiver apenas um único contêiner, você poderá executá-lo implantando-o em seu host do Docker (VM ou servidor físico). No entanto, se seu aplicativo contiver vários serviços, você poderá implantá-lo como um aplicativo composto, usando um único comando da CLI (docker-compose up), ou com o Visual Studio, que usará esse comando sob as capas. Vejamos as diferentes opções.

Opção A: Executando um aplicativo de contêiner único

Usando a CLI do Docker

Você pode executar um contêiner do Docker usando o comando, como mostra a docker run Figura 5-9:

docker run -t -d -p 80:5000 cesardl/netcore-webapi-microservice-docker:first

O comando acima criará uma nova instância de contêiner a partir da imagem especificada, sempre que ela for executada. Você pode usar o --name parâmetro para dar um nome ao contêiner e, em seguida, usar docker start {name} (ou usar o ID do contêiner ou o nome automático) para executar uma instância de contêiner existente.

Captura de tela executando um contêiner do Docker usando o comando docker run.

Figura 5-9. Executando um contêiner do Docker usando o comando docker run

Nesse caso, o comando vincula a porta interna 5000 do contêiner à porta 80 da máquina host. Isso significa que o host está escutando na porta 80 e encaminhando para a porta 5000 no contêiner.

O hash mostrado é o ID do contêiner e também é atribuído um nome legível aleatoriamente se a --name opção não for usada.

Com o Visual Studio

Se você não adicionou suporte ao orquestrador de contêineres, também pode executar um único aplicativo de contêiner no Visual Studio pressionando Ctrl+F5 e também pode usar F5 para depurar o aplicativo dentro do contêiner. O contêiner é executado localmente usando a execução do docker.

Opção B: Executando um aplicativo de vários contêineres

Na maioria dos cenários corporativos, um aplicativo Docker será composto por vários serviços, o que significa que você precisa executar um aplicativo de vários contêineres, como mostra a Figura 5-10.

VM com vários contêineres do Docker

Figura 5-10. VM com contêineres do Docker implantados

Usando a CLI do Docker

Para executar um aplicativo de vários contêineres com a CLI do Docker, use o docker-compose up comando. Este comando usa o arquivo docker-compose.yml que você tem no nível da solução para implantar um aplicativo de vários contêineres. A Figura 5-11 mostra os resultados ao executar o comando do diretório principal da solução, que contém o arquivo docker-compose.yml.

Visualização de tela ao executar o comando docker-compose up

Figura 5-11. Exemplos de resultados ao executar o comando docker-compose up

Depois que o comando docker-compose up é executado, o aplicativo e seus contêineres relacionados são implantados no host do Docker, conforme mostrado na Figura 5-10.

Com o Visual Studio

Executar um aplicativo de vários contêineres usando o Visual Studio 2019 não pode ser mais simples. Basta pressionar Ctrl+F5 para executar ou F5 para depurar, como de costume, configurando o projeto docker-compose como o projeto de inicialização. O Visual Studio lida com toda a configuração necessária, para que você possa criar pontos de interrupção como de costume e depurar o que finalmente se tornam processos independentes em execução em "servidores remotos", com o depurador já anexado, exatamente assim.

Como mencionado anteriormente, cada vez que você adiciona suporte à solução Docker a um projeto dentro de uma solução, esse projeto é configurado no arquivo de docker-compose.yml global (nível da solução), que permite executar ou depurar toda a solução de uma só vez. O Visual Studio iniciará um contêiner para cada projeto que tenha o suporte à solução Docker habilitado e executará todas as etapas internas para você (dotnet publish, docker build, etc.).

Se você quiser dar uma olhada em todo o trabalho, dê uma olhada no arquivo:

{root solution folder}\obj\Docker\docker-compose.vs.debug.g.yml

O ponto importante aqui é que, como mostrado na Figura 5-12, no Visual Studio 2019 há um comando Docker adicional para a ação chave F5. Essa opção permite executar ou depurar um aplicativo de vários contêineres executando todos os contêineres definidos nos arquivos docker-compose.yml no nível da solução. A capacidade de depurar soluções de vários contêineres significa que você pode definir vários pontos de interrupção, cada ponto de interrupção em um projeto diferente (contêiner) e, ao depurar do Visual Studio, você vai parar em pontos de interrupção definidos em projetos diferentes e em execução em contêineres diferentes.

Captura de tela da barra de ferramentas de depuração executando um projeto docker-compose.

Figura 5-12. Executando aplicativos de vários contêineres no Visual Studio 2022

Recursos adicionais

Uma nota sobre testes e implantação com orquestradores

Os comandos docker-compose up e docker run (ou executar e depurar os contêineres no Visual Studio) são adequados para testar contêineres em seu ambiente de desenvolvimento. Mas você não deve usar essa abordagem para implantações de produção, onde você deve direcionar orquestradores como Kubernetes ou Service Fabric. Se você estiver usando o Kubernetes, terá que usar pods para organizar contêineres e serviços para conectá-los. Você também usa implantações para organizar a criação e modificação de pods.

Imagem para o Passo 6.

Passo 6. Teste seu aplicativo Docker usando seu host Docker local

Esta etapa irá variar dependendo do que seu aplicativo está fazendo. Em um aplicativo Web .NET simples que é implantado como um único contêiner ou serviço, você pode acessar o serviço abrindo um navegador no host do Docker e navegando até esse site, como mostra a Figura 5-13. (Se a configuração no Dockerfile mapear o contêiner para uma porta no host que seja diferente de 80, inclua a porta do host na URL.)

Captura de tela da resposta de localhost/API/values.

Figura 5-13. Exemplo de teste do aplicativo Docker localmente usando localhost

Se localhost não estiver apontando para o IP do host do Docker (por padrão, ao usar o Docker CE, deveria), para navegar até o serviço, use o endereço IP da placa de rede da sua máquina.

Esse URL no navegador usa a porta 80 para o exemplo de contêiner específico que está sendo discutido. No entanto, internamente as solicitações estão sendo redirecionadas para a porta 5000, porque foi assim que ela foi implantada com o comando docker run, conforme explicado em uma etapa anterior.

Você também pode testar o aplicativo usando curl do terminal, como mostra a Figura 5-14. Em uma instalação do Docker no Windows, o IP padrão do Docker Host é sempre 10.0.75.1, além do endereço IP real da sua máquina.

Saída do console de obter o http://10.0.75.1/API/values com ondulação.

Figura 5-14. Exemplo de teste do aplicativo Docker localmente usando curl

Testando e depurando contêineres com o Visual Studio 2022

Ao executar e depurar os contêineres com o Visual Studio 2022, você pode depurar o aplicativo .NET da mesma forma que faria ao executar sem contêineres.

Testando e depurando sem o Visual Studio

Se você estiver desenvolvendo usando a abordagem editor/CLI, a depuração de contêineres é mais difícil e você provavelmente desejará depurar gerando rastreamentos.

Recursos adicionais

Fluxo de trabalho simplificado ao desenvolver contêineres com o Visual Studio

Efetivamente, o fluxo de trabalho ao usar o Visual Studio é muito mais simples do que se você usar a abordagem editor/CLI. A maioria das etapas exigidas pelo Docker relacionadas ao Dockerfile e aos arquivos docker-compose.yml são ocultadas ou simplificadas pelo Visual Studio, como mostra a Figura 5-15.

Diagrama mostrando as cinco etapas simplificadas necessárias para criar um aplicativo.

O processo de desenvolvimento para aplicativos Docker: 1 - Codifique seu aplicativo, 2 - Escreva Dockerfile/s, 3 - Crie imagens definidas em Dockerfile/s, 4 - (opcional) Componha serviços no arquivo docker-compose.yml, 5 - Execute contêiner ou aplicativo docker-compose, 6 - Teste seu aplicativo ou microsserviços, 7 - Empurre para repo e repita.

Figura 5-15. Fluxo de trabalho simplificado ao desenvolver com o Visual Studio

Além disso, você precisa executar a etapa 2 (adicionar suporte ao Docker aos seus projetos) apenas uma vez. Portanto, o fluxo de trabalho é semelhante às suas tarefas de desenvolvimento habituais ao usar o .NET para qualquer outro desenvolvimento. Você precisa saber o que está acontecendo sob as capas (o processo de construção de imagem, quais imagens base você está usando, implantação de contêineres, etc.) e, às vezes, você também precisará editar o Dockerfile ou docker-compose.yml arquivo para personalizar comportamentos. Mas a maior parte do trabalho é muito simplificada usando o Visual Studio, tornando-o muito mais produtivo.

Usando comandos do PowerShell em um Dockerfile para configurar contêineres do Windows

Os Contêineres do Windows permitem converter seus aplicativos existentes do Windows em imagens do Docker e implantá-los com as mesmas ferramentas que o restante do ecossistema do Docker. Para usar contêineres do Windows, execute comandos do PowerShell no Dockerfile, conforme mostrado no exemplo a seguir:

FROM mcr.microsoft.com/windows/servercore
LABEL Description="IIS" Vendor="Microsoft" Version="10"
RUN powershell -Command Add-WindowsFeature Web-Server
CMD [ "ping", "localhost", "-t" ]

Nesse caso, estamos usando uma imagem base do Windows Server Core (a configuração FROM) e instalando o IIS com um comando do PowerShell (a configuração RUN). Da mesma forma, você também pode usar comandos do PowerShell para configurar componentes adicionais, como ASP.NET 4.x, .NET Framework 4.6 ou qualquer outro software Windows. Por exemplo, o seguinte comando em um Dockerfile configura o ASP.NET 4.5:

RUN powershell add-windowsfeature web-asp-net45

Recursos adicionais