Olá! Na lição anterior, você aprendeu a usar o comando docker build e a gerenciar o fundamental contexto de build com o arquivo .dockerignore. Vimos que cada instrução em um Dockerfile pode criar uma nova camada, empilhada sobre as anteriores para formar a imagem final.
Nesta lição, vamos dar o próximo passo lógico e investigar a anatomia de uma imagem. O objetivo é que você consiga analisar as camadas e o tamanho da imagem usando docker history. Compreender a composição de uma imagem, camada por camada, é uma habilidade diagnóstica crucial. Ela permite identificar exatamente quais partes do seu processo de build contribuem para o tamanho final da imagem, abrindo caminho para otimizações que resultam em builds mais rápidos, deployments mais ágeis e uma superfície de segurança menor.
A Estrutura em Camadas de uma Imagem Docker
Como vimos, uma imagem Docker não é um bloco monolítico. Ela é uma coleção de camadas somente leitura (read-only) empilhadas umas sobre as outras. Pense nisso como os commits em um repositório Git: cada camada representa um conjunto de alterações (um "diff") em relação à camada anterior.
Instruções do Dockerfile como RUN, COPY e ADD são as que normalmente criam novas camadas contendo dados, e, portanto, contribuem para o tamanho da imagem. Outras instruções, como CMD, WORKDIR, e ENV, geralmente criam apenas "camadas de metadados" com 0 bytes de tamanho, pois apenas modificam a configuração de como a imagem se comportará em tempo de execução.
Para revisar quais instruções criam camadas e como elas se empilham, a documentação oficial do Docker oferece a explicação mais precisa. Leia a seção 'Images and layers'.
Concentre-se no exemplo do Dockerfile e na explicação de quais comandos (como COPY e RUN) criam uma nova camada e quais (como LABEL e CMD) apenas modificam metadados. Note o ponto importante de que remover um arquivo em uma camada posterior não o remove das camadas anteriores, ele continua ocupando espaço.
Inspecionando a História com docker history
A principal ferramenta para dissecar uma imagem é o comando docker history. Ele exibe a lista de camadas que compõem a imagem, mostrando o comando que a criou e o seu tamanho.
A sintaxe é simples:docker history <NOME_DA_IMAGEM>:<TAG>
A saída do comando apresenta várias colunas:
- IMAGE: O ID da camada. Você verá
<missing>para camadas que fazem parte da imagem base (que foi construída em outra máquina) ou para builds feitos com o BuildKit. - CREATED: Há quanto tempo a camada foi criada.
- CREATED BY: O comando do
Dockerfileque gerou a camada. Esta é a coluna mais informativa. - SIZE: O tamanho que esta camada específica adiciona à imagem. É aqui que você identificará os "vilões" do tamanho.
- COMMENT: Comentários adicionais, geralmente vazios, mas podem indicar o uso do BuildKit.

Para ver uma demonstração prática do comando e entender melhor sua saída, o vídeo a seguir é um excelente guia.
Docker Layers and Multistage Builds | Docker Optimization | Reduce Layer Size
Este vídeo de 'Cloud With Raj' demonstra o uso do docker history em um exemplo prático e explica o significado de cada camada.
Assista do timestamp 01:48 a 03:25. O apresentador constrói uma imagem e imediatamente usa docker history para analisar seu conteúdo, apontando qual camada ocupa mais espaço. Isso conecta diretamente o Dockerfile com o resultado da análise.
A Importância de Analisar o Tamanho das Camadas
Por que dedicar tempo a essa análise? Imagens menores e mais limpas trazem benefícios diretos:
- Performance: Imagens menores são transferidas mais rapidamente da registry para o host, acelerando o startup de contêineres. Isso é especialmente crítico em ambientes de nuvem com auto-scaling, onde novas instâncias precisam subir o mais rápido possível.
- Custos de Armazenamento: Menos dados significam menor custo de armazenamento, tanto na sua registry (Docker Hub, AWS ECR, etc.) quanto no disco dos seus hosts.
- Segurança: Imagens infladas frequentemente contêm ferramentas de build, bibliotecas e outros binários que não são necessários para a execução da aplicação. Cada um desses componentes extras aumenta a "superfície de ataque", oferecendo mais vetores para potenciais vulnerabilidades.
O próximo trecho do vídeo que acabamos de ver articula perfeitamente essa motivação.
Docker Layers and Multistage Builds | Docker Optimization | Reduce Layer Size
Agora, vamos entender as implicações práticas de ter imagens grandes em produção.
Assista do timestamp 03:25 a 04:06. O foco é a conexão entre o tamanho da imagem e a performance em um ambiente de produção, especialmente em cenários de escalabilidade e recuperação de falhas.
Exemplo Prático: Mão na Massa
A melhor forma de entender é praticando. A documentação do Docker tem um excelente exercício guiado que demonstra como duas imagens diferentes podem compartilhar camadas comuns, economizando espaço.
Sharing promotes smaller images
Siga este tutorial prático da documentação do Docker. Você criará dois Dockerfiles, construirá duas imagens (uma baseada na outra) e usará docker image history para ver as camadas compartilhadas e as novas camadas.
Leia e execute os passos da seção 'The copy-on-write (CoW) strategy', especificamente a subseção 'Sharing promotes smaller images'. Execute os comandos em seu terminal para ver os resultados em tempo real. Preste atenção especial nos passos 8 e 9, onde você compara a saída de docker image history para as duas imagens.
Ao final deste exercício, você terá uma compreensão concreta de como as camadas são reutilizadas entre as imagens, um dos pilares da eficiência do Docker.
Ferramentas Avançadas para Análise de Camadas
Embora docker history seja a ferramenta padrão, existem utilitários de terceiros que oferecem uma visão ainda mais profunda. Uma ferramenta popular é o dive. Ela não apenas lista as camadas, mas também permite que você explore o sistema de arquivos de cada uma, mostrando exatamente quais arquivos foram adicionados, modificados ou removidos.
Isso é extremamente útil para identificar "espaço desperdiçado" – por exemplo, quando você baixa um arquivo .zip em uma camada e o extrai em outra, mas esquece de remover o .zip original.

Não vamos nos aprofundar no uso do dive agora, mas é uma excelente ferramenta para ter em seu arsenal quando você precisar otimizar seriamente uma imagem.
Teste seu entendimento!
Considere o seguinte Dockerfile simples:
# Dockerfile
FROM python:3.9-slim
WORKDIR /app
# Instala dependências de build, baixa o código-fonte, compila, e depois limpa
RUN apt-get update && \
apt-get install -y build-essential wget && \
wget https://example.com/source-code.tar.gz && \
tar -xzf source-code.tar.gz && \
cd source-code && \
make && \
make install
# Copia um pequeno script de entrada
COPY entry.sh .
CMD ["./entry.sh"]
Ao executar docker history nesta imagem, você observa que a camada criada pela instrução RUN é muito grande (ex: 500MB). Olhando o comando, qual é a principal causa do tamanho excessivo e como você poderia começar a otimizá-lo?
Show answer
A principal causa do tamanho excessivo da camada RUN é que ela está fazendo muitas coisas em uma única camada sem limpar os artefatos intermediários. Especificamente:
- Ferramentas de Build:
build-essentialewgetsão instalados, mas provavelmente não são necessários para a execução final da aplicação. - Código-Fonte Baixado: O arquivo
source-code.tar.gzé baixado e extraído, mas o arquivo.tar.gzem si permanece no sistema de arquivos da camada, ocupando espaço desnecessariamente.
A solução ideal aqui seria usar um build multi-stage, que você verá em uma próxima lição. No entanto, com o que sabemos até agora, uma melhoria seria tentar limpar os artefatos no final da mesma instrução RUN. Por exemplo:
RUN apt-get update && \
apt-get install -y build-essential wget && \
# ... (passos de compilação) ... && \
apt-get purge -y --auto-remove build-essential wget && \
rm -rf /source-code.tar.gz /var/lib/apt/lists/*
Adicionar a limpeza (apt-get purge e rm) na mesma camada RUN garante que os arquivos sejam removidos dentro da mesma "transação" do sistema de arquivos, efetivamente reduzindo o tamanho final daquela camada. Se a limpeza fosse feita em uma instrução RUN separada, os arquivos ainda existiriam na camada anterior.
Conclusão
Parabéns! Você agora sabe como "olhar para dentro" de uma imagem Docker e entender sua estrutura. Esta é uma habilidade que separa o uso básico do Docker do uso profissional e otimizado.
Principais pontos a reter:
docker historyé o comando principal para inspecionar as camadas que compõem uma imagem.- Cada camada tem um tamanho associado, e o tamanho total da imagem é a soma do tamanho de suas camadas.
- Instruções como
RUN,COPY, eADDsão as que mais contribuem para o tamanho da imagem. - Analisar as camadas é o primeiro passo para otimizar imagens, visando melhor performance, menor custo e maior segurança.
- Imagens diferentes podem compartilhar camadas, o que economiza espaço e acelera os pulls.
Agora que você sabe construir e analisar uma imagem, o próximo passo é aprender a gerenciá-la e distribuí-la corretamente. Na próxima lição, vamos abordar como etiquetar e versionar imagens Docker seguindo convenções de nomenclatura, uma prática essencial para manter seus artefatos organizados e prontos para o deploy.