Dockerfile: escrevendo do zero
1. O que é um Dockerfile e sua estrutura básica
Um Dockerfile é um documento de texto que contém todas as instruções necessárias para construir uma imagem Docker automaticamente. No ciclo DevOps, ele funciona como a "receita" da aplicação, garantindo que o ambiente de execução seja reproduzível, consistente e versionável.
A estrutura básica de um Dockerfile utiliza diretivas fundamentais:
FROM: define a imagem baseRUN: executa comandos durante o buildCMD: especifica o comando padrão quando o container iniciaENTRYPOINT: define o executável principal do container
Exemplo de um Dockerfile mínimo para uma aplicação Node.js:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "index.js"]
2. Escolhendo a imagem base correta
Imagens oficiais vs. imagens de terceiros
Imagens oficiais são mantidas pela Docker Inc. ou pelos próprios desenvolvedores da tecnologia (Node.js, Python, Nginx). Elas passam por revisões de segurança e são atualizadas regularmente. Imagens de terceiros podem conter vulnerabilidades ou malware.
Alpine, Slim e Full: trade-offs
- Alpine (~5MB): baseada em musl libc e BusyBox. Extremamente leve, mas pode causar incompatibilidades com algumas bibliotecas nativas (ex: bcrypt em Node.js).
- Slim (~50-150MB): versão reduzida da imagem completa, mantendo compatibilidade.
- Full (~300MB+): contém todas as ferramentas do sistema, útil para debugging.
Boas práticas
Use sempre tags específicas em vez de latest:
# Evite
FROM node:latest
# Prefira
FROM node:18.17.1-alpine
Tags específicas garantem builds reproduzíveis e evitam surpresas com atualizações inesperadas.
3. Instalação de dependências e execução de comandos
A diretiva RUN cria uma nova camada (layer) na imagem. Muitas camadas aumentam o tamanho final. Combine comandos com && e limpe caches para reduzir o número de layers.
Exemplo prático: instalando pacotes Python
FROM python:3.11-slim
# Instala dependências do sistema e limpa cache em um único RUN
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
Exemplo prático: instalando pacotes Node.js
FROM node:18-alpine
RUN apk add --no-cache \
python3 \
make \
g++ \
&& npm cache clean --force
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
4. Copiando arquivos e configurando o ambiente de execução
COPY vs. ADD
COPY: copia arquivos do host para a imagem. Simples e previsível.ADD: similar ao COPY, mas suporta URLs e extração automática de arquivos tar. Use apenas quando necessário, pois seu comportamento pode ser surpreendente.
# Prefira COPY para arquivos locais
COPY ./app /app
# Use ADD apenas para extrair tarballs automaticamente
ADD https://example.com/file.tar.gz /tmp/
Uso de .dockerignore
Crie um arquivo .dockerignore para evitar copiar arquivos desnecessários:
node_modules
.git
.env
*.log
__pycache__
Configurando ambiente
ENV NODE_ENV=production
ENV PORT=3000
WORKDIR /app
5. Definindo o comportamento do container em execução
CMD vs. ENTRYPOINT
ENTRYPOINT: define o executável principal (não pode ser sobrescrito facilmente)CMD: fornece argumentos padrão para o ENTRYPOINT ou define o comando completo
Combinação comum
ENTRYPOINT ["python"]
CMD ["app.py"]
Ao executar docker run minha-imagem, o container roda python app.py. Se o usuário passar argumentos, eles substituem o CMD: docker run minha-imagem server.py executa python server.py.
Exemplo: servidor web com Nginx
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY ./static /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Exemplo: servidor Flask
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
6. Otimizações para build eficiente e segurança
Ordenação estratégica de instruções
O Docker cacheia cada layer. Instruções que mudam com menos frequência devem vir primeiro:
# 1. Imagem base (quase nunca muda)
FROM node:18-alpine
# 2. Dependências do sistema (mudam raramente)
RUN apk add --no-cache curl
# 3. Arquivos de dependências (mudam com commits)
COPY package*.json ./
RUN npm ci
# 4. Código fonte (muda frequentemente)
COPY . .
Executando como usuário não-root
FROM node:18-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
WORKDIR /app
COPY --chown=appuser:appgroup . .
Removendo credenciais durante o build
Nunca copie arquivos .env ou credenciais para a imagem. Use segredos do Docker BuildKit:
# syntax=docker/dockerfile:1
FROM node:18-alpine
RUN --mount=type=secret,id=mysecret \
cat /run/secrets/mysecret
7. Integrando o Dockerfile no pipeline DevOps e Kubernetes
Multi-stage builds
Reduzem drasticamente o tamanho da imagem final. Exemplo para aplicação Go:
# Stage 1: Build
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
# Stage 2: Runtime
FROM alpine:3.18
RUN apk add --no-cache ca-certificates
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
Exemplo para React
# Stage 1: Build
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Serve com Nginx
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Dicas para Kubernetes
Configure liveness e readiness probes no deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: minha-app
spec:
template:
spec:
containers:
- name: app
image: minha-app:latest
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
Referências
- Documentação oficial do Dockerfile — Guia completo com todas as instruções suportadas pelo Dockerfile, exemplos e boas práticas.
- Best practices for writing Dockerfiles — Documentação oficial com recomendações de otimização, segurança e organização de Dockerfiles.
- Multi-stage builds na prática — Tutorial oficial sobre como usar builds multi-estágio para reduzir o tamanho das imagens.
- Dockerfile security best practices — Artigo técnico da Snyk com 10 práticas essenciais de segurança para Dockerfiles.
- Kubernetes Pod lifecycle and probes — Documentação oficial do Kubernetes sobre como configurar liveness, readiness e startup probes em pods.