Seu primeiro Dockerfile do zero: passo a passo

Docker & Containers · Por · Publicado em · Atualizado em · 7 min de leitura

Mãos digitando em notebook com código aberto no editor visível
Ilustra o fluxo prático: editar, buildar e testar seu Dockerfile no laptop Foto: Lukas Blazek / Pexels

Este guia ensina, na prática, como criar seu primeiro Dockerfile do zero, construir a imagem e rodar um container com uma pequena aplicação de exemplo. Você entenderá as diretivas essenciais, como funciona o cache de camadas, .dockerignore e um ajuste simples de segurança. Siga os passos numerados e valide tudo no final.

Pré-requisitos e visão rápida do que você fará

Você precisará de:

- Docker instalado e em execução. Em Linux, seu usuário deve poder usar o Docker sem sudo.

- Editor de texto e terminal.

- Algum espaço em disco para imagens.

Vamos criar um app simples, escrever o Dockerfile, fazer o build, executar e otimizar com .dockerignore e usuário não‑root. Se quiser comparar quando usar containers ou VMs, leia o comparativo Docker vs VMs para HA.

  • Docker instalado (Desktop, Engine ou similar)
  • Terminal com acesso a internet
  • Editor de texto para criar arquivos do projeto
# Verifique se o Docker está funcionando
docker --version
# (Opcional) Teste rápido do daemon
docker run --rm hello-world

Estrutura básica de um Dockerfile

Um Dockerfile descreve como montar uma imagem a partir de camadas. Cada instrução cria ou influencia uma camada em cache. Abaixo, as diretivas mais usadas e um exemplo mínimo. Use nomes de imagem leves (ex.: variantes slim) para reduzir tamanho.

Diretiva Para que serve Exemplo
FROM Imagem base inicial FROM python:3.12-slim
WORKDIR Define diretório de trabalho WORKDIR /app
COPY Copia arquivos para a imagem COPY . .
RUN Executa comandos de build RUN pip install -r requirements.txt
EXPOSE Documenta a porta usada EXPOSE 8000
CMD Comando padrão ao iniciar CMD ["python", "app.py"]
# Exemplo mínimo
FROM alpine:3.20
CMD ["echo", "Hello from Docker!"]

Prepare o projeto de exemplo (Flask)

Vamos criar uma API mínima em Flask para validar rede e logs. No Windows, se preferir, crie os arquivos manualmente em vez de usar o heredoc. Os arquivos serão: requirements.txt e app.py.

mkdir hello-docker && cd hello-docker

# requirements.txt
cat > requirements.txt <<'REQ'
flask
REQ

# app.py
cat > app.py <<'PY'
from flask import Flask
app = Flask(__name__)

@app.get("/")
def index():
    return {"message": "Hello from Docker"}

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)
PY

Escreva o Dockerfile passo a passo

Crie um arquivo chamado Dockerfile na raiz do projeto. Primeiro copiamos dependências para aproveitar o cache e depois o código. Exponha a porta do app e defina o comando de inicialização.

# Dockerfile (versão inicial)
FROM python:3.12-slim

# Impede criação de .pyc e ativa logs imediatos no stdout/stderr
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

# Define diretório de trabalho
WORKDIR /app

# Copia dependências primeiro para aproveitar cache
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# Copia o restante do código
COPY . .

# Documenta a porta usada
EXPOSE 8000

# Comando padrão
CMD ["python", "app.py"]

Faça o build e entenda o cache de camadas

O build cria a imagem executando as instruções do Dockerfile. Alterações em arquivos copiados antes invalidam o cache das etapas seguintes. Modificar apenas o código, mantendo requirements.txt igual, reaproveita o cache de dependências. Para CI/CD, automatize estes comandos (veja o guia de CI/CD com GitHub Actions).

# Execute a partir da pasta do projeto (onde está o Dockerfile)
docker build -t hello-docker:dev .

# Verifique a imagem criada
docker image ls | grep hello-docker

# Rode novamente para observar o uso de cache
docker build -t hello-docker:dev .

# (Opcional) Inspecione o histórico de camadas
docker image history hello-docker:dev

Rode o container e mapeie a porta

Agora vamos subir o container e mapear a porta 8000 do host para a 8000 do container. Use -d para rodar em background. Para parar, use docker stop. Mapear portas permite acessar a aplicação no navegador.

# Executa em foreground (Ctrl+C para parar)
docker run --rm -p 8000:8000 --name hello hello-docker:dev

# Ou em background (daemon)
# docker run -d --rm -p 8000:8000 --name hello hello-docker:dev

# Em outro terminal, teste:
# curl http://localhost:8000

Otimize: .dockerignore e usuário não‑root

Reduza o contexto de build e melhore segurança. O .dockerignore evita enviar arquivos desnecessários para o daemon. Rodar como não‑root reduz impacto de falhas. Se sua imagem roda uma API voltada à internet, veja práticas de segurança em APIs seguras com OAuth2 e rate limiting.

# .dockerignore (crie este arquivo na raiz)
__pycache__/
*.pyc
.env
.git
.gitignore
README*

# Dockerfile (otimizado)
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1
WORKDIR /app

# Camada de dependências (cacheável)
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# Copia o código
COPY . .

# Cria usuário não-root e ajusta permissões
RUN adduser --disabled-password --gecos "" appuser \
    && chown -R appuser:appuser /app
USER appuser

EXPOSE 8000
CMD ["python", "app.py"]

Como confirmar que funcionou e solucionar problemas

Verifique a aplicação, logs e saúde do container. Em caso de erro, confira mensagens e portas. Para padronizar logs da sua app, considere adotar logs estruturados; veja o guia de logs em JSON e correlação.

  • Não abre no navegador: confirme se mapeou -p 8000:8000 e acesse http://localhost:8000.
  • Porta já em uso: troque para -p 8080:8000 e tente novamente.
  • Permissão negada ao usar USER: garanta chown -R appuser:appuser /app no Dockerfile.
  • Dependência não encontrada: atualize requirements.txt e faça build sem cache (use --no-cache).
  • Daemon inacessível: inicie o serviço Docker/Desktop e verifique permissões do usuário (no Linux, grupo docker).
  • Imagem grande: use base slim, .dockerignore e limpe caches de build quando possível.
# Teste HTTP e logs
curl -s http://localhost:8000 | jq .

docker ps --filter name=hello

docker logs -f hello

# (Opcional) Acesse o shell do container para inspeção
# docker exec -it hello sh

Perguntas frequentes

O que é um Dockerfile e por que eu preciso dele?

É um arquivo de texto com instruções para construir uma imagem de container. Ele garante builds reproduzíveis, padroniza ambiente e facilita distribuição da sua aplicação. Sem um Dockerfile, você dependeria de ambientes manuais e menos previsíveis.

Preciso ter Python instalado localmente para seguir o tutorial?

Não. Você só cria os arquivos de código e quem fornece o Python é a própria imagem base no build e na execução. Se preferir outro runtime, adapte FROM, portas e o comando CMD de acordo com sua stack.

Qual a diferença entre CMD e ENTRYPOINT?

CMD define o comando padrão quando o container inicia, podendo ser sobrescrito pela linha de comando. ENTRYPOINT define o executável principal; argumentos adicionais podem vir de CMD. Use ENTRYPOINT quando o processo principal não deve mudar.

É obrigatório usar .dockerignore?

Não é obrigatório, mas é altamente recomendado. Ele reduz o contexto de build, acelera o processo e evita vazar arquivos sensíveis para a imagem. Inclua diretórios de build, caches, VCS e segredos que não devem ir para a imagem.

Como reduzir o tempo de build e aproveitar cache?

Copie e instale dependências antes do código-fonte, pois elas mudam com menos frequência. Evite RUN desnecessários, una comandos quando fizer sentido e mantenha a imagem base enxuta. Se alterar apenas o código, as camadas de dependências serão reaproveitadas.

Como publicar a imagem em um registry?

Escolha um registry, faça login com a CLI, tagueie sua imagem com o namespace do registry e faça o push. Em pipelines de CI/CD, automatize login, build, tag e push. Verifique políticas de acesso e nomes consistentes para ambientes.

Pronto para o próximo passo?

Automatize builds e deploys com pipelines. Comece com GitHub Actions para criar, testar e publicar imagens a cada push.

Ler guia de CI/CD

Veja também