Olá! Na lição anterior, mergulhamos no funcionamento do cache de camadas do Docker e vimos como a ordenação correta das instruções em um Dockerfile pode acelerar drasticamente os builds subsequentes. Essa otimização é um dos segredos para um fluxo de desenvolvimento ágil e eficiente.
Nesta lição, vamos focar no comando que inicia todo esse processo: docker build. Nosso objetivo é que você seja capaz de construir uma imagem Docker a partir de um Dockerfile usando docker build e explicar o papel do contexto de build (build context). Compreender o que é o contexto de build e como ele funciona internamente é fundamental, pois ele dita quais arquivos do seu ambiente de desenvolvimento estão disponíveis para a construção da imagem, impactando diretamente o desempenho, a segurança e a corretude do processo.
O Comando docker build
Até agora, usamos o comando docker build de forma bastante direta. Vamos formalizar seu uso mais comum. A sintaxe básica é docker build [OPTIONS] PATH.
docker build: O comando em si.[OPTIONS]: Flags que modificam o comportamento do comando. A mais comum e importante é-t(ou--tag), que permite nomear e etiquetar sua imagem em um formatonome:tag(por exemplo,meu-app:1.0).PATH: Um caminho para um diretório no seu sistema de arquivos. Este caminho especifica o contexto de build.
O vídeo a seguir demonstra o uso prático deste comando.
Dockerfile Tutorial - Docker in Practice || Docker Tutorial 10
Para começar, assista a este trecho do vídeo 'Dockerfile Tutorial' do canal TechWorld with Nana. Ela demonstra como usar docker build com a flag -t para construir e nomear uma imagem, e introduz o . como o caminho para o Dockerfile (e o contexto).
Assista do timestamp 11:46 a 13:16. O foco é entender a sintaxe básica: docker build -t <nome>:<tag> <caminho_do_contexto>.
No exemplo docker build -t my-app:1.0 ., o . no final é crucial. Ele diz ao Docker: "use o diretório atual como o contexto de build". Mas o que isso significa exatamente?
O que é o Contexto de Build?
O contexto de build é o conjunto de arquivos e diretórios no PATH especificado que são enviados ao daemon do Docker. Uma vez que o daemon tem acesso a esse "pacote" de arquivos, as instruções no seu Dockerfile, como COPY e ADD, podem referenciá-los para incluí-los na imagem.
Pense no Dockerfile como uma receita de bolo e no contexto de build como todos os ingredientes que você colocou na sua bancada. A receita só pode usar os ingredientes que estão na bancada.
A imagem a seguir ilustra o fluxo completo, destacando onde o contexto se encaixa.

É fundamental entender a importância do contexto por três razões:
- Funcionalidade: Sua instrução
COPY ./app /appsó funcionará se um diretório chamadoappexistir dentro do contexto de build. - Performance: Antigamente, todo o conteúdo do contexto era enviado para o daemon Docker no início do build. Um contexto grande (com centenas de megabytes de arquivos desnecessários) tornava o início do build lento.
- Segurança: Incluir arquivos sensíveis (como chaves SSH, arquivos
.envcom senhas) no contexto de build cria o risco de que eles sejam acidentalmente copiados para a imagem final.
Para solidificar essa definição, o artigo a seguir oferece uma explicação concisa e clara.
Docker Build Tutorial: What is a Build Context?
Leia esta seção do artigo 'Docker Build Tutorial' do freeCodeCamp para obter uma definição formal do contexto de build e entender por que ele é tão importante.
Leia a seção 'What is a Build Context?'. Foque nos quatro pontos listados: Security, Performance, Functionality, e Efficiency.
Como o Contexto de Build Funciona Internamente
Dado seu interesse em entender "como as coisas funcionam", vamos aprofundar um pouco. O Docker opera em uma arquitetura cliente-servidor. O comando docker que você executa no terminal é o cliente. Ele se comunica com o daemon do Docker (o servidor, dockerd), que é o processo em segundo plano que gerencia contêineres, imagens, etc.
Quando você executa docker build, o cliente Docker é responsável por empacotar o contexto de build e enviá-lo para o daemon.
No entanto, as versões modernas do Docker usam um subsistema de build chamado BuildKit. O BuildKit introduziu uma otimização massiva: em vez de o cliente enviar todo o contexto de uma vez, o BuildKit (que roda no lado do daemon) analisa o Dockerfile e solicita ao cliente apenas os arquivos de que precisa, quando precisa deles.
Por exemplo, para a instrução COPY package.json ., o BuildKit pedirá apenas o arquivo package.json. Mais tarde, para a instrução COPY src/ ./src/, ele pedirá o conteúdo do diretório src. Isso é muito mais eficiente e é um dos motivos pelos quais os builds modernos são mais rápidos.
O artigo a seguir detalha essa arquitetura de forma excelente.
Docker Build Tutorial: Docker Build Architecture
Esta seção do mesmo artigo do freeCodeCamp explora a arquitetura por trás do docker build, explicando os papéis do cliente (Buildx) e do servidor (BuildKit) e como a transferência de contexto sob demanda funciona.
Leia a seção 'Docker Build Architecture: How It All Works'. Preste atenção especial na subseção 'How They Communicate' e no diagrama que ilustra a transferência de arquivos sob demanda. Isso é o cerne do funcionamento moderno do build.
Gerenciando o Contexto com .dockerignore
Então, como garantimos que nosso contexto de build seja enxuto e seguro, contendo apenas o que é estritamente necessário? A resposta é o arquivo .dockerignore.
Funcionando de maneira muito semelhante a um arquivo .gitignore, o .dockerignore permite que você liste arquivos e diretórios a serem excluídos do contexto de build antes que ele seja enviado ao daemon do Docker.
Para um projeto .NET, um .dockerignore típico excluiria os diretórios bin/ e obj/, arquivos de configuração de usuário como .vs/, e talvez logs ou outros artefatos locais.
A imagem a seguir visualiza perfeitamente o papel do .dockerignore.

A sintaxe é direta, suportando wildcards (*) e negações (!). Para uma referência completa sobre a sintaxe e o comportamento, a documentação oficial é o melhor recurso.
Build context: .dockerignore files
A documentação oficial do Docker detalha tudo o que você precisa saber sobre o arquivo .dockerignore, incluindo sua sintaxe, regras de correspondência e precedência.
Leia a seção '.dockerignore files'. Não é preciso memorizar tudo, mas entenda o propósito principal, a sintaxe básica (comentários, wildcards) e como as exceções com ! funcionam.
Contexto de Build: Um Erro Comum
Um dos erros mais comuns ao começar é executar docker build do diretório errado. Lembre-se, o Dockerfile pode apenas usar COPY para arquivos que estão dentro do contexto.
Imagine a seguinte estrutura:
/workspace/
├── my-dotnet-api/
│ ├── Controllers/
│ ├── MyApi.csproj
│ └── Dockerfile
└── shared-library/
└── Shared.csproj
Se o seu Dockerfile em my-dotnet-api/ precisa do Shared.csproj, e você está no diretório my-dotnet-api/ e executa:
docker build .
O contexto é my-dotnet-api/. Uma instrução como COPY ../shared-library/Shared.csproj . falhará, porque ../shared-library/ está fora do contexto.
A solução é executar o build a partir do diretório /workspace/, ajustando o comando para apontar para o Dockerfile correto:
docker build -f my-dotnet-api/Dockerfile .
Neste caso:
-f my-dotnet-api/Dockerfile: Especifica o caminho para o seu Dockerfile..: Define o contexto de build como o diretório atual (/workspace/), que agora inclui tantomy-dotnet-api/quantoshared-library/.
Teste seu entendimento!
Você tem um projeto de API .NET com a seguinte estrutura de arquivos:
/my-awesome-api/
├── src/
│ └── My.Api/
│ ├── Controllers/
│ │ └── WeatherForecastController.cs
│ ├── My.Api.csproj
│ ├── Program.cs
│ └── appsettings.json
├── test/
│ └── My.Api.Tests/
│ └── ... (arquivos de teste)
├── .dockerignore
├── .gitignore
├── Dockerfile
└── my-awesome-api.sln
O Dockerfile foi escrito para ser executado a partir do diretório raiz /my-awesome-api/.
- Qual comando você executaria, e de qual diretório, para construir a imagem
my-api:1.0? - Quais diretórios você definitivamente incluiria no seu arquivo
.dockerignorepara otimizar o contexto de build?
Show answer
-
Você deve estar no diretório raiz do projeto,
/my-awesome-api/. O comando correto seria:docker build -t my-api:1.0 .O
.no final é fundamental, pois define/my-awesome-api/como o contexto de build, dando ao Dockerfile acesso a tudo o que ele precisa (o diretóriosrc, o arquivo.sln, etc.). -
Um bom arquivo
.dockerignorepara um projeto .NET deve excluir, no mínimo, os artefatos de build, configurações de IDE e diretórios de teste.# Artefatos de build do .NET **/bin/ **/obj/ # Arquivos de IDE (ex: Visual Studio) .vs/ # Diretório de testes, não é necessário na imagem final da API test/ # Arquivos de controle de versão (embora geralmente já sejam ignorados, é bom ser explícito) .git/ .gitignore # O próprio .dockerignore não precisa entrar na imagem .dockerignore DockerfileExcluir
bineobjé crucial para evitar que artefatos de compilação locais sejam copiados para a imagem. Excluirtest/mantém a imagem de produção enxuta e focada apenas no código da aplicação.
Conclusão
Excelente! Agora você tem uma compreensão profunda de um dos conceitos mais fundamentais do Docker. Saber como o docker build funciona e como gerenciar seu contexto de build é uma habilidade essencial para criar imagens de forma eficiente e segura.
Principais pontos a reter:
- O comando
docker buildusa umDockerfilee um contexto de build para criar uma imagem. - O contexto de build é o conjunto de arquivos enviados ao daemon do Docker, definindo o que está disponível para as instruções
COPYeADD. - O caminho para o contexto é o último argumento do comando
docker build(geralmente.). - O BuildKit, o moderno motor de build do Docker, otimiza o processo solicitando arquivos do contexto sob demanda, em vez de transferir tudo de uma vez.
- Use um arquivo
.dockerignorepara excluir arquivos desnecessários (artefatos de build, logs, diretórios de teste, arquivos sensíveis) do contexto, melhorando a velocidade e a segurança.
Na lição anterior, discutimos como cada instrução em um Dockerfile cria uma camada. Na próxima lição, vamos aprender a inspecionar essas camadas. Você irá analisar as camadas e o tamanho da imagem usando docker history, o que nos permitirá ver "por dentro" da imagem que acabamos de construir e entender melhor sua composição.