Um desenvolvedor júnior reduziu uma imagem Docker de Python de 1,2 GB para 85 MB, cortando o pipeline de CI de 11 minutos para 90 segundos. Imagens menores baixam mais rápido, custam menos para armazenar e expõem menos falhas de segurança.
Por que o tamanho da imagem importa
Toda vez que um container é baixado, o registro transmite a imagem inteira. Uma camada de 85 MB chega em segundos; uma camada de 1,2 GB pode levar minutos em uma rede modesta. Agentes de build também precisam fazer o upload e o cache da imagem completa, inflando o tempo de CI e as faturas de armazenamento em nuvem. Cada pacote extra é uma vulnerabilidade potencial, então reduzir a base diminui a superfície de ataque.
De onde vem o excesso
- Ferramentas de build como gcc permanecem na imagem final se forem instaladas no mesmo estágio que executa o app.
- Caches de gerenciadores de pacotes (ex: caches de
aptoupip) ficam no disco e nunca são limpos por padrão. - Cada instrução
RUNcria uma nova camada de apenas leitura; arquivos duplicados entre camadas se acumulam. - Imagens base grandes como
ubuntu:latestvêm com um SO completo, muito mais do que um runtime minimalista de Python precisa.
O encolhimento em três etapas
| Etapa | Imagem base | Abordagem de build | Tamanho resultante |
|---|---|---|---|
| 1 | Python padrão (completo) | Estágio único, todas as ferramentas presentes | 1,18 GB |
| 2 | python:slim |
Multi-stage: builder com gcc, estágio final copia apenas pacotes compilados | 210 MB |
| 3 | python:alpine |
Multi-stage no Alpine Linux, que por si só é minúsculo | 85 MB |
Etapa 1 – a linha de base
Começando com a imagem padrão do Python, o desenvolvedor obteve um artefato de 1,18 GB. A imagem continha a stack Debian completa, headers de desenvolvimento e o cache do pip.
Etapa 2 – slim com um builder
Mudar para python:slim reduziu a pegada do SO, mas as ferramentas de build permaneceram. Adicionar um estágio de builder permitiu que o gcc, make e outras dependências de tempo de compilação fossem instalados, compilados e depois desaparecessem. O estágio final usou COPY --from=builder para puxar apenas as wheels compiladas e arquivos de runtime, reduzindo o tamanho para 210 MB.
Etapa 3 – Alpine vence
O Alpine Linux é construído sobre musl libc e busybox. Repetir o padrão multi-stage no Alpine produziu uma imagem de 85 MB — uma redução de 93% em relação à original. O desenvolvedor observou que o Kubernetes baixou a imagem em segundos e o job de CI terminou em 90 segundos.
Impacto no mundo real
- Menores custos de armazenamento – O armazenamento no registro diminui.
- Segurança aprimorada – Menos pacotes significam menos CVEs para monitorar. A imagem Alpine contém apenas o runtime do Python e o código da aplicação.
- CI mais rápido – O tempo de execução do pipeline caiu de 11 minutos para 90 segundos.
Dicas práticas para reduzir seu Dockerfile
- Evite tags
:latest; escolha variantes:slimou:alpineque atendam às suas necessidades. - Use builds multi-stage: um estágio de builder dedicado para compilação, um estágio de runtime que recebe apenas os artefatos que você realmente precisa.
- Copie seletivamente com
COPY --from=builder /path/to/installed /path/in/final. - Ordene os comandos para que a instalação de dependências ocorra antes da cópia do código-fonte; isso maximiza o cache de camadas.
- Limpe os caches explicitamente, ex:
rm -rf /var/lib/apt/lists/* ~/.cache/pip.
Se você adotar o Alpine, adicione o pacote nss quando sua aplicação apresentar problemas de resolução de DNS. Ao instalar com o pip, adicione /root/.local/bin ao PATH para que os scripts instalados localmente sejam encontrados em tempo de execução.
Ressalvas
A musl libc do Alpine pode entrar em conflito com wheels binários compilados para glibc, causando erros em tempo de execução. Nesses casos, reconstrua as wheels dentro do builder do Alpine ou utilize uma base slim. O pacote extra nss é um preço pequeno pela confiabilidade do DNS.
O que observar a seguir
- Escaneie suas imagens existentes em busca de camadas grandes que possam ser candidatas a uma reescrita multi-stage.
- Monitore os logs de CI para tempos de upload e download para detectar excesso de tamanho nas imagens.
- Fique de olho nos relatórios de vulnerabilidade da distribuição base que você escolher.
A lição é clara: um Dockerfile disciplinado, uma base leve e um estágio de builder podem reduzir uma imagem Python em mais de uma ordem de magnitude, entregando benefícios tangíveis de velocidade e custo sem sacrificar a funcionalidade.
