
Hoje veremos como definir os comandos do arquivo Dockerfile quando temos um projeto referenciando outro projeto.
Se você não conhece o Docker↳Docker46 conteúdosE o Docker Swarm? Contextos e motivadores diáriosDevSecOps · ago 2024Automatizando o ambiente de desenvolvimento e testes com DockerDevSecOps · mai 2019MySQL + Adminer + Docker Compose: montando rapidamente um ambiente para usoData · abr 2019Ver tudo em DevSecOps → sugiro que acompanhe a série de artigos : Docker uma introdução básica.
A maioria dos exemplos mostra como dockerizar um projeto dotnet↳.NET113 conteúdosNovidades do .NET 9 – o tipo genérico OrderedDictionaryDev (Back & Front) · dez 2024Novidades .NET 10: novas formas de uso do .NET CLIDev (Back & Front) · dez 2025Novidades do .NET 5: implementando um proxy reverso com YARP + ASP.NET 5Dev (Back & Front) · nov 2020Ver tudo em Dev (Back & Front) →, supondo que ele não possui dependências locais. Então vamos analisar o que podemos fazer, quando nosso projeto tem referências a outros projetos na solução. Começaremos mergulhando em um exemplo simples sem dependências primeiro, para entender quais mudanças introduzimos e por quê.
Vamos partir do exemplo oficial de como dockerizar um projet .NET Core que mostra o seguinte código no arquivo Dockerfile localizado na pasta do projeto (onde o arquivo .csproj está armazenado):
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env |
E os comandos usados para criar a imagem a partir deste arquivo Dockerfile:
|
Vamos iniciar analizando as instruções do arquivo Dockerfile :
Instrução FROM
Nosso Dockerfile começa com a instrução FROM:
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
Isso significa que baseamos nossa imagem no SDK oficial do Microsoft na versão 6.0. Usamos o SDK neste momento, não o runtime de produção, pois compilaremos nosso aplicativo no Docker durante a criação da imagem.
Portanto, você nem precisa ter o SDK instalado em sua máquina host, este Dockerfile é preparado de forma que você não compile seu aplicativo para a imagem do Docker – o Docker o compilará.
Você pode usar binários construídos em sua máquina host, mas não é seguro – pode não funcionar devido a problemas de compatibilidade.
Por que há instrução AS build-env ?
Veremos isso mais adiante…
Instrução WORKDIR
Na segunda linha, vemos a instrução WORKDIR /app, o que significa que as instruções RUN, CMD, ENTRYPOINT, COPY e ADD em nosso Dockerfile serão executadas no diretório /app.
Se ele não existir, será criado (mesmo que não seja usado).
Instrução COPY
Em seguida, vemos a instrução COPY *.csproj ./ , o que significa que todos os arquivos csproj do contexto de compilação do Docker serão copiados para o diretório workdir (/app) dentro da imagem do Docker.
O comando de compilação do Docker será explicado posteriormente, mas em resumo – o contexto de compilação é o diretório da sua máquina host, apontado no comando de compilação do Docker. Se você apontar. path, o diretório onde você executa o comando é tomado. Portanto, no nosso caso, copiamos apenas um arquivo csproj, porque executamos o comando build com o diretório do projeto definido como contexto de compilação.
Instrução RUN
A seguir temos a instrução RUN dotnet restore, que simplesmente executa o comando dotnet restore em nosso diretório workdir (/app).
Neste momento dentro do diretório /app em nossa imagem, nada mais é que o .csproj do nosso projeto, pois copiamos apenas ele no passo anterior, mas é suficiente para restaurar as dependências do nuget.
Copiar e compilar a fonte do aplicativo
Novamente vemos a instrução COPY – COPY. ./ para copiar tudo do nosso contexto de compilação – no nosso caso, significa arquivos de projeto (arquivos .cs etc.), porque executamos o comando docker build com o diretório do projeto definido como contexto de compilação.
Em seguida, com a instrução run – RUN dotnet publish -c Release -o out, simplesmente executamos dotnet publish em nosso diretório workdir (/app) dentro da imagem, com os parâmetros -c Release -o out.
Este comando dotnet compila nosso aplicativo com a configuração de release e publica os resultados no diretório out (no nosso caso /app/out). Podemos compilar o código-fonte porque baseamos essa imagem no SDK do desenvolvedor.
Compilação de vários estágios do Docker
Mais uma vez vemos a instrução FROM, que define em qual imagem baseamos nossa imagem…
Como é possível especificá-la novamente, com uma base diferente?
É um recurso do Docker (desde a versão do Docker 17.05) chamado de compilações de vários estágios. Quando usamos a palavra-chave FROM novamente, queremos dizer que a imagem anterior especificada acima é temporária e foi usada apenas para servir a algum propósito.
No nosso caso foi feito apenas para compilar nossa aplicação – por isso usamos o SDK como imagem base. Agora especificamos a imagem base novamente e desta vez estamos preparando nossa imagem real – aquela que será implantada em produção, e esta não se baseia em SDK, apenas no runtime de produção, o que resulta em tamanho menor.
FROM mcr.microsoft.com/dotnet/aspnet:6.0
A seguir vamos apenas copiar nosso aplicativo compilado da imagem temporária.
Então, novamente, especificamos o diretório de trabalho para /app catalog e, em seguida, copiamos nossos binários – COPY –from=build-env /app/out . o que significa copiar arquivos de /app/out/ da imagem build-env (é por isso que demos um nome na primeira linha) para o diretório de trabalho atual (/app).
Instrução ENTRYPOINT
A última instrução neste Dockerfile é ENTRYPOINT, que (em termos simples) especifica um comando que será executado quando o contêiner for iniciado.
Então, no nosso caso – ENTRYPOINT [“dotnet”, “aspnetapp.dll”] – o Docker executará o dotnet com o parâmetro aspnetapp.dll para iniciar nosso aplicativo.
Comando de compilação do Docker: build
Com base nesse Dockerfile, somos instruídos a executar o comando docker build -t aspnetapp . no diretório do projeto (onde o Dockerfile está armazenado).
A opção: -t name (–tag name) não é obrigatória – ela permite marcar a imagem (para nomeá-la e, opcionalmente e dar-lhe uma tag no formato ‘name:tag’), então o comando principal é : docker build .
O contexto de compilação é o caminho na máquina host que estará acessível durante a criação da imagem para instruções do Dockerfile. No nosso caso é o caminho . o que significa que o diretório onde executamos este comando é passado como contexto de construção. Como nos dizem para executar este comando no diretório do projeto (onde o arquivo .csproj está armazenado), nossos arquivos de projeto são passados como contexto de compilação.
Comando de execução do Docker : run
O comando run do Docker cria um contêiner a partir da imagem. A imagem é um manual somente leitura para o Docker, para criar o contêiner, e o contêiner está funcionando na máquina virtual onde nosso aplicativo reside.
Podemos pensar assim: a imagem é como uma classe na programação orientada a objetos, e container é como uma instância, criada a partir dessa classe.
Assim, podemos criar quantos contêineres (instâncias) quisermos, e isso não afeta a imagem (classe) – a imagem é necessária apenas para que o Docker saiba como criar o contêiner.
Exemplo de comando para criar o container:
docker run -d -p 8080:80 –name meucontainer aspnetapp
Sem a opção –detach (-d), começaremos a ver a saída do console do aplicativo do contêiner.
Com a opção –publish (-p) vinculamos a(s) porta(s) do contêiner ao host (por padrão com TCP, mas você também pode especificar UDP e SCTP).
Com a opção –name atribuímos um nome ao container (sem esta opção o Docker irá escolher algum nome engraçado para nós).
No final passamos o nome da imagem, que o Docker lerá para criar o container. Como nomeamos nossa imagem como aspnetapp, usamos esse nome aqui.
Docker com múltiplos projetos
Uma vez que entendemos o que acontece no exemplo básico, vamos ver como alterá-lo, para fazê-lo funcionar quando nosso projeto tem referências a outros projetos de solução.
O problema é que executamos o comando build do Docker a partir do diretório do projeto passando o caminho . como contexto de construção. Isso significa que somente os arquivos deste diretório estarão acessíveis durante a construção da imagem e, dependendo dos projetos, é claro que os arquivos podem estar em outros diretórios.
Como resolver isso ?
Temos várias opções para corrigir isso.
Podemos mover o Dockerfile um nível acima (para o diretório da solução) e executar o docker build a partir daí. Mas é recomendado ter o Dockerfile no diretório do projeto, para poder ter mais de um Dockerfile na solução (para diferentes projetos).
Você também pode executar o docker build como antes (do diretório do projeto), mas alterar o caminho do contexto de compilação para um nível acima (..).
Uma solução elegante é executar o docker build do diretório da solução, passando . como contexto de compilação e para especificar qual Dockerfile queremos ler com a opção –file (-f), da seguinte forma:
docker build -f PROJECT_DIRECTORY/Dockerfile -t IMAGE_NAME .
Como ajustar o Dockerfile
Para que isso funcione precisamos ajustar o Dockerfile, porque o exemplo do Dockerfile padrão na página do Docker assume que temos o diretório do projeto como contexto de compilação.
Uma opção a isso seria usar este código:
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env |
Neste exemplo foi ignorado a restauração de pacotes nuget como uma única etapa para simplificar, a restauração está incluída em dotnet publish e, se falhar devido à falha do nuget, a mensagem de erro será legível.
Mas se você tiver muitas dependências nuget, você pode querer ter uma etapa separada, porque dessa forma o Docker a trata como uma camada distinta e a reutiliza se nenhum arquivo csproj for alterado, o que dá um tempo de compilação menor.
Assim, copiamos todos os projetos (porque o contexto de compilação agora é o diretório da solução) para o diretório /app dentro do contêiner.
Em seguida, em /app workdir, executamos o comando dotnet publish, especificando qual projeto compilar :
RUN dotnet publish PROJECT_NAME -c Release -o out
Aqui PROJECT_NAME é o nome do diretório que contém o arquivo .csproj
As demais instruções permanecem inalteradas com uma pequena alteração – durante a cópia do aplicativo compilado da imagem temporária, desta vez precisamos passar o nome do projeto para o caminho:
COPY –from=build-env /app/PROJECT_NAME/out .
Com isso podemos tratar os casos onde temos mais de um projeto na solução e suas dependências.







