Práticas recomendadas para conteinerizar aplicações .NET
Marcelo Oliveira
31 de agosto de 2022
0 minutos de leituraA 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á:
Baixar e instalar o Visual Studio 2022.
Ter um cliente Docker local para executar contêineres localmente. Você pode usar o Docker Desktop, que requer o Windows 10 ou posterior. Não se esqueça de escolher a instalação para Windows.
Baixar e instalar a interface de linha de comando (CLI) do Snyk.
Criar uma conta gratuita do Snyk.
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:

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

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

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.

Em seguida, selecione o tipo Web Forms.

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

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

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

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

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.

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

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

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:

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:

O Visual Studio criará automaticamente o Dockerfile do projeto.

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.

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.

Dê um nome ao projeto, como WebApp.

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

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

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

Agora, execute o comando docker images para ver uma lista das imagens Docker no seu sistema:
O resultado deste comando será semelhante ao seguinte:
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:
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:
Sua lista de imagens será semelhante à seguinte:
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.
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:
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:
Em seguida, execute o comando snyk auth para autenticar a CLI do Snyk:
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:

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:

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

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:

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.
