Skip to main content

Práticas recomendadas para conteinerizar aplicações .NET

Escrito por

Marcelo Oliveira

hero container aps

31 de agosto de 2022

0 minutos de leitura

A conteinerização com Docker se tornou uma grande tendência no desenvolvimento de aplicações web, adotada por muitos desenvolvedores .NET. Há muitas vantagens para desenvolvedores e engenheiros de DevOps conteinerizarem aplicações .NET, mesmo ao trabalhar com versões mais antigas do .NET Framework 4.x. No entanto, se não soubermos usar os contêineres corretamente, teremos poucos benefícios.

Neste artigo, vamos abordar algumas práticas recomendadas para conteinerizar aplicações .NET, incluindo as que usam o framework da versão 4.x. Também vamos falar sobre o uso de imagens menores e a análise de imagens para reduzir riscos de segurança e remover componentes desnecessários dos nossos contêineres.

Requisitos

Antes de começar, você precisará:

Considere conteinerizar suas aplicações .NET (inclusive o .NET Framework 4.x)

Com o lançamento do .NET Core 1.0, as aplicações web se tornaram multiplataforma, portáteis e de código aberto, permitindo que os desenvolvedores as migrassem para o Docker e aproveitassem ao máximo a conteinerização.

Mas, embora as versões mais recentes do .NET executadas no Linux recebam mais atenção, os contêineres Windows são compatíveis com versões antigas do .NET exclusivas do Windows, das quais inúmeros aplicativos empresariais dependem. Além disso, nem toda organização que mantém aplicações web do .NET Framework está pronta para migrá-las para versões mais recentes. Por isso, faz sentido conteinerizar nossas aplicações do .NET Framework 4.x.

As etapas a seguir mostram como criar e executar uma aplicação ASP.NET Web Forms conteinerizada no Visual Studio 2022.

Primeiro, execute o Docker Desktop na sua máquina de desenvolvimento:

Resultados de busca do Windows por “docker desktop”, mostrando o Docker Desktop como o aplicativo mais relevante.

Na janela Introdução do Visual Studio, selecione Criar um novo projeto.

Tela inicial do Visual Studio com a opção “Criar um novo projeto” destacada em vermelho.

Digite “Web Forms” na caixa de texto Pesquisar modelos e selecione Aplicativo Web ASP.NET (.NET Framework).

Resultados da pesquisa por “Web Forms” no Visual Studio, mostrando o modelo de projeto Aplicativo Web ASP.NET com as tags C#, Windows, Cloud e Web

Insira um nome para a nova aplicação (por exemplo, WebFormsApp), especifique o local no disco, selecione .NET Framework 4.8 e clique em Criar.

Janela do Visual Studio para configurar um novo projeto de aplicativo Web ASP.NET chamado WebFormsApp com o .NET Framework 4.8

Em seguida, selecione o tipo Web Forms.

Tela de criação de um novo aplicativo Web ASP.NET, mostrando as opções de modelos de projeto Empty e Web Forms com descrições

Verifique se as opções Web Forms e Suporte ao Docker estão marcadas e clique em Criar.

Janela de criação de projeto com opções de pasta e referência principal, configurações avançadas, campo de projeto de teste desativado e botões Voltar e Criar.

Aguarde enquanto o Visual Studio cria o projeto. Esta é a estrutura do projeto exibida no Visual Studio:

Gerenciador de Soluções do Visual Studio exibindo a estrutura do projeto WebFormsApp com arquivos, pastas e arquivos de configuração do ASP.NET.

Agora, abra o Docker Desktop. Você verá que o contêiner WebFormsApp está em execução na porta 61469:

Visualização de contêineres do Docker Desktop mostrando o contêiner WebFormsApp em execução na porta 61469

Abra a guia Imagens para ver a imagem WebFormsApp, usada pelo contêiner WebFormsApp.

Tela Images on disk do Docker Desktop mostrando duas imagens locais que totalizam 8,64 GB, incluindo webformsapp com a tag dev.

Por fim, pressione Ctrl+F5 para criar sua imagem Docker e executá-la localmente. Depois que a imagem do contêiner for criada e estiver em execução em um contêiner Docker, o Visual Studio abrirá a aplicação web no navegador padrão.

Janela do navegador exibindo a página inicial de um aplicativo ASP.NET, com navegação, texto introdutório e seções sobre como começar, bibliotecas e hospedagem na web.

Agora, volte ao Visual Studio e clique no arquivo Dockerfile:

Gerenciador de Soluções do Visual Studio exibindo um projeto WebFormsApp com o Dockerfile destacado.

Isso abrirá o Dockerfile, que configura o projeto para ser executado em um contêiner.

Editor do Visual Studio exibindo um Dockerfile para um aplicativo ASP.NET, incluindo uma imagem base do .NET Framework, um argumento de origem, um diretório de trabalho e o comando publish-

A instrução FROM inicia uma nova etapa de compilação e define a imagem base para as instruções seguintes. Neste caso, a imagem é aspnet:4.8-windowsservercore-ltsc2019, que o Docker baixa do repositório de imagens da Microsoft.

É claro que é mais provável que seu projeto Web Forms não tenha sido criado inicialmente com suporte ao Docker. Para simular essa situação, crie um novo projeto ASP.NET Web Forms, mas desta vez sem suporte ao Docker:

Gerenciador de Soluções do Visual Studio exibindo uma solução WebFormsApp com os arquivos do projeto WebFormsAppNoDocker, incluindo páginas ASPX e arquivos de configuração.

Agora, vamos adicionar um Dockerfile ao novo projeto. Clique com o botão direito no nome do projeto, escolha o menu Adicionar e, em seguida, o submenu Suporte ao Docker:

Solution Explorer do Visual Studio exibindo o menu Adicionar, com Suporte ao Docker selecionado para um projeto web

O Visual Studio criará automaticamente o Dockerfile do projeto.

O Solution Explorer do Visual Studio mostra o projeto WebFormsAppNoDocker, com o Dockerfile selecionado

Observe que o Visual Studio já selecionou a imagem e o caminho do código-fonte a partir dos quais o contêiner será gerado.

Editor do Visual Studio exibindo um Dockerfile com uma imagem base do ASP.NET Framework, WORKDIR /inetpub/wwwroot e o comando COPY para copiar os arquivos gerados na compilação

A partir daqui, seu projeto já conta com o suporte e os benefícios inerentes à conteinerização com Docker, incluindo portabilidade, agilidade, entrega mais rápida, segurança aprimorada e gerenciamento simplificado.

Mantenha as imagens de contêiner tão pequenas quanto possível

Os contêineres Linux e Windows oferecem imagens base enxutas, que contêm apenas as aplicações e os serviços necessários para o funcionamento da sua aplicação. Uma imagem pequena, com o mínimo de dependências, reduz o número de vulnerabilidades introduzidas por essas dependências e diminui a superfície de ataque.

Vamos falar sobre algumas imagens base que os desenvolvedores .NET podem considerar para criar contêineres pequenos. Primeiro, se você ainda usa o ASP.NET Framework 4.x, que não é compatível com Linux, sua única opção são os contêineres Windows. As imagens base enxutas recomendadas pela Microsoft são Windows Server Core e Nano Server.

O Windows Server Core é um sistema operacional mínimo, gerenciado por linha de comando, para executar funções do Windows Server e aplicações que não exigem a interface gráfica padrão do Windows. O Nano Server é um sistema operacional otimizado para nuvens privadas e data centers. Ele não permite logon local, é menor e reinicia muito mais rápido que o Server Core.

Para .NET Core e .NET 5+, as imagens do SDK devem ser usadas apenas na compilação, enquanto as imagens de runtime devem ser usadas em implantações de produção como parte de uma compilação em vários estágios. Algumas imagens base enxutas adequadas são as imagens Debian bullseye-slim-amd64 e Alpine Linux.

Podemos deixar as imagens base ainda menores usando imagens com as dependências de runtime do .NET e compilando nossa aplicação .NET no modo autocontido — assim, baixamos apenas as dependências necessárias para a aplicação, sem nada além disso.

Agora, vamos praticar a criação de uma aplicação web .NET 6 com imagens enxutas. Abra o Visual Studio 2022, clique em Criar novo projeto e selecione o tipo Aplicativo Web ASP.NET Core.

Solution Explorer do Visual Studio exibindo um projeto WebApp com Connected Services, Dependencies, Properties, wwwroot, Pages, appsettings.json, Dockerfile e C#

Dê um nome ao projeto, como WebApp.

Tela “Configure seu novo projeto” do Visual Studio, exibindo o nome do projeto ASP.NET Core Web App, o local, o nome da solução e a opção de diretório.

Clique em Avançar e selecione estas opções:

  • Framework .NET 6.0

  • Tipo de autenticação: Nenhum

  • Configurar para HTTPS: marcado

  • Habilitar Docker: marcado

  • Sistema operacional do Docker: Linux

Configurações adicionais de informações para um aplicativo Web ASP.NET Core, mostrando .NET 6.0, sem autenticação, HTTPS e Docker ativados e Linux selecionado.

Clique no botão Criar e veja o novo projeto no Visual Studio.

Janela de pesquisa de modelos mostrando um modelo de aplicativo Web ASP.NET Core com filtros para C#, todas as plataformas e Web.

Agora, pressione F5 para executar a aplicação web hospedada no seu contêiner Docker local.

Página inicial do WebApp exibindo o título “Boas-vindas”, um link sobre como criar aplicativos web com ASP.NET Core e links de navegação para Início e Privacidade.

Agora, execute o comando docker images para ver uma lista das imagens Docker no seu sistema:

> docker images

O resultado deste comando será semelhante ao seguinte:

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
webapp       dev       e3b51b1eef08   4 hours ago   208MB

Observe que a aplicação está sendo executada em um contêiner Linux e que o tamanho da imagem webapp acima é de 208 MB.

Em seguida, vamos reduzir o tamanho da imagem do contêiner da nossa aplicação web.

Pare a aplicação no Visual Studio e abra o arquivo Dockerfile. Você verá o bloco a seguir, que instrui o Docker a baixar as imagens dotnet/aspnet:6.0 e dotnet/sdk:6.0 do Microsoft Container Registry (mcr) e usá-las como imagens base do contêiner da aplicação:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["WebApp/WebApp.csproj", "WebApp/"]
RUN dotnet restore "WebApp/WebApp.csproj"
COPY . .
WORKDIR "/src/WebApp"
RUN dotnet build "WebApp.csproj" -c Release -o /app/build

Em seguida, pressione F5 para executar a aplicação novamente. Quando a aplicação web estiver funcionando, execute o comando docker images para ver uma lista das imagens Docker no seu sistema:

> docker images

Sua lista de imagens será semelhante à seguinte:

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
webapp       dev       778bcd52f366   4 hours ago   100MB
<none>       <none>    e3b51b1eef08   4 hours ago   208MB

Observe que a imagem webapp foi recriada e agora tem 100 MB (108 MB a menos que a imagem original).

Analise as imagens em busca de vulnerabilidades

Manter a base de código atualizada com frequência já é, por si só, uma prática recomendada. Entre as vantagens mais evidentes estão o acesso a novos recursos, correções de bugs, uma interface melhor e desempenho aprimorado. Mas as atualizações de segurança são igualmente importantes.

O sistema operacional ou as bibliotecas da imagem base podem conter vulnerabilidades sem correção. Além disso, scripts, código e aplicações adicionados à imagem base também podem ter vulnerabilidades que não queremos incluir acidentalmente na produção.

Analisar contêineres em busca de vulnerabilidades é essencial para avaliar possíveis riscos de segurança e tomar as medidas adequadas. Neste caso, vamos escolher uma imagem antiga do .NET: mcr.microsoft.com/dotnet/core/aspnet:2.2.

dotnet new webapp -n "AspNet2.2" -f "netcoreapp2.2"

Vamos abrir o projeto no Visual Studio e adicionar um Dockerfile ao novo projeto. Clique com o botão direito no nome do projeto, escolha o menu Adicionar e, em seguida, clique no submenu Suporte ao Docker.

Agora, abra o arquivo Dockerfile e substitua o conteúdo pelo código a seguir:

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:2.2.105 AS build
WORKDIR /src
COPY ["AspNet2.2.csproj", "."]
RUN dotnet restore "./AspNet2.2.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "AspNet2.2.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "AspNet2.2.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "AspNet2.2.dll"]

Em seguida, vamos ver como analisar imagens para descobrir o nível de vulnerabilidade do nosso contêiner. Primeiro, execute o comando de CLI docker images para listar as imagens locais atuais:

docker images

REPOSITORY       TAG       IMAGE ID       CREATED              SIZE
aspnet22         latest    223b485f4516   About a minute ago   265MB

Em seguida, execute o comando snyk auth para autenticar a CLI do Snyk:

> snyk auth

Depois de autenticar a conta, podemos usar a CLI do Snyk. Vamos executar o comando snyk container test <repository>:<tag> para testar a imagem que criamos localmente e disponibilizamos no daemon Docker local:

> snyk container test aspnet22:latest
Terminal do PowerShell listando vulnerabilidades de alta severidade nos pacotes zlib, systemd e shadow/passwd

O comando snyk container test gera uma lista dos componentes instalados na imagem, envia essa lista ao serviço do Snyk e retorna uma lista das vulnerabilidades encontradas na imagem.

Ao final, a análise da imagem encontrou 193 vulnerabilidades:

Relatório do terminal para docker-image|aspnet22 mostrando 193 vulnerabilidades, incluindo 10 críticas, na imagem base do Microsoft .NET.

Para monitorar a imagem, execute o comando snyk container monitor <repository>:<tag>:

> snyk container monitor aspnet22:latest
Saída do terminal mostrando o monitoramento do Snyk para a imagem Docker aspnet22:latest e um link para visualizar o histórico do projeto.

O comando snyk container monitor gera uma lista dos componentes instalados na imagem, envia essa lista ao serviço do Snyk e retorna um link para o serviço do Snyk em http://app.snyk.io/org/{YOUR-ACCOUNT}/, onde você pode ver os resultados:

Tabela intitulada “Recomendações para atualizar a imagem base”, que compara imagens base atuais e alternativas do .NET de acordo com as vulnerabilidades e a gravidade.

3 dicas essenciais para conteinerização

Vimos muitas vantagens para desenvolvedores e engenheiros de DevOps conteinerizarem aplicações .NET. No entanto, os contêineres não são uma solução mágica para todos os problemas. Ainda precisamos adotar algumas práticas recomendadas para desmistificar os contêineres e orientar você sobre como aproveitá-los ao máximo.

Apesar da ideia equivocada e persistente de que os contêineres servem apenas para aplicações .NET Core, vimos que eles também podem beneficiar aplicações do .NET Framework 4.x.

Quando se trata do tamanho da imagem do contêiner, quanto menor, melhor. Felizmente, aprendemos que algumas imagens base são pequenas o bastante para conter apenas o que nossa aplicação precisa para funcionar e reduzir a superfície de ataque do contêiner.

Por fim, vimos como reduzir riscos de segurança analisando as imagens de contêiner e mantendo-as atualizadas. Os comandos Snyk container test e Snyk container monitor são ferramentas indispensáveis para analisar continuamente nossos contêineres .NET e monitorar vulnerabilidades. Quando usada corretamente, a conteinerização pode oferecer uma camada extra de segurança e flexibilidade às nossas aplicações, independentemente da idade delas.

Segurança de contêineres que prioriza os desenvolvedores

O Snyk encontra e corrige automaticamente vulnerabilidades em imagens de contêiner e workloads do Kubernetes.