Docker: Fundamentos do Dockerfile

Última atualização: 2026-08-26

Um Dockerfile é o "código fonte" de uma imagem — escrevendo um Dockerfile, você pode construir uma imagem de aplicação reproduzível com um único comando.

1. O Que Você Vai Aprender



2. Uma História Real de uma Pessoa Desenvolvedora Python

(1) Ponto de Dor: Ter que configurar manualmente o ambiente a cada implantação

Alice escreveu uma aplicação web Python. Toda vez que ela implanta, precisa instalar manualmente o Python, configurar um ambiente virtual, instalar dependências e copiar o código. Ela precisa repetir esse processo três vezes — uma para o servidor de teste, uma para o ambiente de pré-produção e uma para o servidor de produção — totalizando três repetições, cada uma com pequenas variações.

(2) Soluções para Automação com Dockerfile

Bob disse: "Escreva um Dockerfile, 'empacote' sua aplicação em uma imagem e então você poderá executá-la em qualquer lugar com um único comando."

DOCKERFILE
# Um Dockerfile simples para uma aplicação Flask
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]

(3) Benefício: Construir Uma Vez, Executar em Qualquer Lugar

Depois que Alice construiu a imagem usando docker build -t myapp:1.0 ., todos os três ambientes rodaram a mesma imagem, reduzindo o tempo de implantação de 30 minutos para 3 minutos e eliminando inconsistências de ambiente.



3. Estrutura Básica de um Dockerfile

Um Dockerfile é um arquivo de texto puro que contém uma sequência de instruções para construir uma imagem. Cada instrução constrói uma camada da imagem.

100%
graph LR
    DF["Dockerfile<br/>Sequência de Instruções"] -->|docker build| IMG["Imagem<br/>Sobreposição Somente Leitura"]
    IMG -->|docker run| CTN["Contêiner<br/>Camada gravável + Camada Somente Leitura"]

(1) Momento de Execução das Instruções

Momento Comando Descrição
Durante o build FROM / RUN / COPY / ADD / ARG Gerar camada da imagem
Tempo de execução CMD / ENTRYPOINT / ENV / EXPOSE / USER Define o comportamento do contêiner

(2) Modelo Básico de Dockerfile

DOCKERFILE
# 1. Imagem base
FROM python:3.12-slim

# 2. Definir diretório de trabalho
WORKDIR /app

# 3. Copiar arquivo de dependências primeiro (otimização de cache)
COPY requirements.txt .

# 4. Instalar dependências
RUN pip install --no-cache-dir -r requirements.txt

# 5. Copiar código da aplicação
COPY . .

# 6. Definir o comando padrão
CMD ["python", "app.py"]


4. FROM: Selecionar uma imagem base

FROM é a primeira instrução em um Dockerfile; ela especifica a imagem base para o build.

(1) Estratégia de Seleção de Imagem Base

Estratégia Imagem Tamanho Caso de Uso
Imagem Oficial de Linguagem python:3.12-slim 155 MB Projeto Python
Variante Alpine python:3.12-alpine 50 MB Espaço em disco extremamente baixo
Build multi-estágio golang:1.22alpine 12 MB Linguagens compiladas Go/Rust
SO Minimalista debian:bookworm-slim 74 MB Requer um ambiente personalizado

▶ Exemplo: O Dockerfile Mais Simples (Dificuldade: ⭐)

DOCKERFILE
# Dockerfile mínimo: apenas imprime hello
FROM alpine:3.19
CMD ["echo", "Hello from Docker!"]
BASH
# Construir e executar
docker build -t hello:1.0 .
docker run --rm hello:1.0
💻 Saída:

TEXT 📖 Somente leitura
Hello from Docker!


5. RUN: Executar o comando de build

RUN Executa um comando durante o build e grava o resultado em uma nova camada da imagem.

(1) Dois Formatos

Formato Sintaxe Características
Formato Shell RUN apt-get install nginx Executa /bin/sh -c por padrão; suporta pipes
Modo Exec RUN ["apt-get", "install", "nginx"] Executa diretamente sem iniciar um shell

▶ Exemplo: RUN para instalar dependências (Dificuldade: ⭐⭐)

DOCKERFILE
# Melhor prática: combinar comandos RUN para reduzir camadas
FROM debian:bookworm-slim

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        curl \
        nginx && \
    rm -rf /var/lib/apt/lists/*
📌 Ponto-chave: Combine múltiplos comandos apt-get em um único RUN para reduzir o número de camadas da imagem. rm -rf /var/lib/apt/lists/* limpa o cache APT para reduzir o tamanho da imagem.

(2) Princípios da Fusão em Cadeia RUN

Método Resultado Observações
Múltiplos RUN Cada entrada cria uma camada Muitas camadas, tamanho grande
Fundir RUN && Uma camada por trilha Poucas camadas, tamanho compacto
Limpar Cache rm -rf apt/lists Limpa cache dentro do mesmo nível
Limpar separadamente Próximo RUN rm Inválido — a camada anterior já curou
DOCKERFILE
# Ruim: cria 2 camadas, cache apt é gravado na camada 1
RUN apt-get update
RUN apt-get install -y nginx

# Bom: cria 1 camada, cache limpo na mesma camada
RUN apt-get update && \
    apt-get install -y nginx && \
    rm -rf /var/lib/apt/lists/*


6. CMD e ENTRYPOINT

Ambos CMD e ENTRYPOINT definem os comandos a serem executados quando o contêiner é iniciado, mas eles se comportam de forma diferente.

(1) Comparação dos Três Comandos de Inicialização

Dimensão CMD ENTRYPOINT
Propósito Fornecer comandos padrão Definir um ponto de entrada fixo
Pode ser sobrescrito Parâmetro docker run sobrescreve diretamente Requer --entrypoint para sobrescrever
Combinação Pode ser usado com ENTRYPOINT Pode ser usado com argumentos de linha de comando CMD
Múltiplos Apenas o último tem efeito Apenas o último tem efeito

(2) Os Três Formatos de CMD

Formato Sintaxe Nível de Recomendação Descrição
Formato Exec CMD ["python", "app.py"] ⭐⭐⭐ Executa diretamente; sinais são passados corretamente
Formato Shell CMD python app.py Como processo filho de /bin/sh -c, SIGTERM não é passado
Formato de Parâmetro CMD ["--port", "8080"] ⭐⭐ Usar com ENTRYPOINT

▶ Exemplo: A Diferença Entre CMD e ENTRYPOINT (Dificuldade: ⭐⭐)

DOCKERFILE
# Dockerfile com CMD: comando pode ser facilmente sobrescrito
FROM alpine:3.19
CMD ["echo", "Hello default"]
BASH
# Padrão: executa CMD
docker run --rm test-cmd
# Saída: Hello default

# Sobrescrever CMD com comando personalizado
docker run --rm test-cmd echo "Custom message"
# Saída: Custom message
DOCKERFILE
# Dockerfile com ENTRYPOINT: comando permanece, args são anexados
FROM alpine:3.19
ENTRYPOINT ["echo"]
CMD ["Hello default"]
BASH
# Padrão: executa ENTRYPOINT + CMD
docker run --rm test-entry
# Saída: Hello default

# Anexar argumentos (não sobrescreve ENTRYPOINT)
docker run --rm test-entry "Custom message"
# Saída: Custom message

# Sobrescrever ENTRYPOINT (raramente necessário)
docker run --rm --entrypoint sh test-entry -c "ls /"

▶ Exemplo: Combinação ENTRYPOINT + CMD (Dificuldade: ⭐⭐⭐)

Esta é a abordagem de melhor prática — ENTRYPOINT especifica o programa a ser executado e CMD fornece os argumentos padrão:

DOCKERFILE
# Padrão Entrypoint + CMD
FROM python:3.12-slim
WORKDIR /app
COPY app.py .
ENTRYPOINT ["python", "app.py"]
CMD ["--host", "0.0.0.0", "--port", "5000"]
BASH
# Padrão: usa argumentos CMD
docker run --rm myapp
# Equivalente a: python app.py --host 0.0.0.0 --port 5000

# Sobrescrever apenas os argumentos
docker run --rm myapp --port 8080
# Equivalente a: python app.py --port 8080


7. Configurando o Contexto e .dockerignore

(1) Configurando o Contexto

O último parâmetro de docker build, ., não se refere ao "diretório atual", mas sim ao contexto de build — o Cliente Docker envia todos os arquivos neste diretório para o Daemon.

100%
graph LR
    CTX["Contexto de Build<br/>(. Índice do Diretório)"] -->|Enviar Arquivo| D["Docker Daemon"]
    D -->|Dockerfile em COPY/ADD| IMG["Camadas da Imagem"]
⚠️ Nota: Se houver 1 GB de node_modules no diretório, 1 GB será enviado ao daemon durante o build (mesmo que o Dockerfile não faça COPY dele). .dockerignore pode excluir arquivos desnecessários.

▶ Exemplo: Como .dockerignore Funciona (Dificuldade: ⭐⭐)

TEXT 📖 Somente leitura
# .dockerignore - excluir arquivos do contexto de build
node_modules
.git
__pycache__
*.pyc
.env
Dockerfile
docker-compose*.yml
README.md
.vscode

(2) Por que a diretiva COPY para arquivos de dependência deve vir antes da diretiva COPY para código fonte?

DOCKERFILE
# Bom: taxa de mudança de dependência < taxa de mudança de código
# Quando o código muda, a camada de dependência usa cache
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

# Ruim: qualquer mudança de arquivo invalida a camada pip install
COPY . .
RUN pip install -r requirements.txt
Cenário de Mudança Versão Boa Versão Ruim
Modificar apenas código ✅ Usa cache pip (segundos) ❌ Reconstrói pip (minutos)
Mudar Dependências ✅ Reconstrói camada pip (necessário) ❌ Reconstrói camada pip (como acima)


8. Parâmetros Comuns para docker build

Parâmetro Função Exemplo
-t Nome da Imagem: Tag -t myapp:1.0
-f Especificar caminho do Dockerfile -f Dockerfile.prod .
--build-arg Passar parâmetros de build --build-arg VERSION=2.0
--no-cache Não usar cache --no-cache
--target Construir até um estágio especificado --target builder
--platform Especificar Plataforma Alvo --platform linux/arm64

▶ Exemplo: Construir uma imagem e visualizar o histórico de camadas (Dificuldade: ⭐⭐)

BASH
# Construir com tag
docker build -t myapp:1.0 .

# Visualizar camadas da imagem
docker history myapp:1.0


9. Exemplo Completo: Escrevendo um Dockerfile para uma Aplicação Flask

DOCKERFILE
# ============================================
# Dockerfile para uma aplicação web Flask
# Demonstra: FROM, WORKDIR, COPY, RUN, CMD
# ============================================

# Usar imagem oficial Python slim
FROM python:3.12-slim

# Definir diretório de trabalho dentro do contêiner
WORKDIR /app

# Copiar arquivo de dependências primeiro (otimização de cache)
COPY requirements.txt .

# Instalar dependências (limpar cache na mesma camada)
RUN pip install --no-cache-dir -r requirements.txt

# Copiar código fonte da aplicação
COPY . .

# Expor a porta da aplicação (apenas documentação)
EXPOSE 5000

# Executar a aplicação Flask
CMD ["python", "app.py"]
BASH
# Construir a imagem
docker build -t flask-app:1.0 .

# Executar o contêiner
docker run -d -p 5000:5000 --name my-flask flask-app:1.0

# Testar a aplicação
curl http://localhost:5000

# Visualizar tamanho e camadas da imagem
docker images flask-app
docker history flask-app:1.0
💻 Saída (trecho):

TEXT 📖 Somente leitura
# docker images flask-app
REPOSITORY   TAG   IMAGE ID       SIZE
flask-app    1.0   a1b2c3d4e5f6   180MB

# docker history flask-app:1.0
IMAGE          CREATED        CREATED BY                          SIZE
a1b2c3d4e5f6   5 seconds ago  CMD ["python" "app.py"]             0B
<missing>      5 seconds ago  COPY . .                            2.5kB
<missing>      5 seconds ago  RUN pip install --no-cache-dir...   45MB
<missing>      5 seconds ago  COPY requirements.txt .             58B
<missing>      5 seconds ago  WORKDIR /app                        0B

❓ Perguntas Frequentes

P: Por que devemos fazer COPY dos arquivos de dependência primeiro e COPY do código fonte depois? R: Para aproveitar o mecanismo de cache de camadas. As dependências mudam com muito menos frequência do que o código. Fazendo COPY dos arquivos de dependência e instalando-os primeiro, esta camada é armazenada em cache; quando apenas o código é modificado depois, a camada de dependência usa diretamente o cache, reduzindo o tempo de build de minutos para segundos. Se todos os arquivos fossem copiados primeiro, qualquer mudança de arquivo invalidaria o cache da camada pip install.

P: CMD e ENTRYPOINT podem ser usados juntos? R: Sim, esta é a abordagem recomendada. ENTRYPOINT define um executável fixo (como python app.py), enquanto CMD fornece argumentos padrão (como --port 5000). Os argumentos passados para docker run sobrescrevem CMD, mas não ENTRYPOINT, permitindo uma configuração de "executável fixo + argumentos flexíveis".

P: O que significa "contexto de build"? R: O . no final do comando docker build especifica o diretório de contexto de build. O cliente Docker empacota todos os arquivos neste diretório e os envia ao daemon. Os comandos COPY e ADD no Dockerfile só podem referenciar arquivos dentro do contexto de build. Use .dockerignore para excluir arquivos desnecessários, o que acelera o build e reduz o tamanho do contexto de build.

P: Como escrevo um arquivo .dockerignore? *R: A sintaxe é a mesma do .gitignore. Você deve excluir: node_modules, .git, pycache, .env, .pyc e o próprio Dockerfile. Regra prática: Exclua quaisquer arquivos que não precisem ser copiados para a imagem para reduzir o tamanho do contexto e acelerar o build.

P: Como soluciono uma falha de build? R: Siga estas três etapas: ① Revise a mensagem de erro — o Docker indicará o comando com falha e o número da linha; ② Verifique o contexto — verifique se o arquivo especificado por COPY existe; ③ Depure interativamente — docker run -it <última-camada-bem-sucedida> bash entre na última camada de imagem bem-sucedida para solucionar manualmente.

P: O que devo fazer se uma linha em RUN for muito longa? R: Use \ para continuar a linha e && para encadear comandos. Esta é a maneira padrão de escrever um Dockerfile, que reduz o número de camadas enquanto mantém a legibilidade. Por exemplo: RUN apt-get update && \ + apt-get install -y nginx && \ + rm -rf /var/lib/apt/lists/*.


📖 Resumo


📝 Exercícios

  1. Problema Básico (Dificuldade: ⭐): Escreva um Dockerfile para uma aplicação Node.js, usando node:20-alpine como imagem base, npm install para instalar dependências e node server.js para iniciar a aplicação.
  2. Problema Avançado (Dificuldade: ⭐⭐): Construa uma imagem e execute um contêiner. Use docker history para analisar o tamanho de cada camada na imagem, identifique a maior camada e explique por quê.
  3. Desafio (Dificuldade: ⭐⭐⭐): Crie um arquivo .dockerignore para excluir node_modules e .git, e compare a diferença no tamanho do contexto de build com e sem o arquivo .dockerignore (Dica: Procure a linha "Sending build context to Docker daemon" na saída do docker build).
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%