O Docker revolucionou a forma como construímos, distribuímos e executamos aplicações. Compreender o Docker em profundidade — para além dos comandos básicos — é o que separa fluxos de trabalho DevOps eficientes de sessões de depuração penosas. Este guia aborda comandos essenciais do Docker e melhores práticas para produção, na perspetiva de um programador sénior.
Porque é que Dominar o Docker é Importante
Um conhecimento aprofundado do Docker permite:
- Desenvolvimento Eficiente: Iteração rápida com containers
- Ambientes Consistentes: O mesmo container em todo o lado
- Otimização de Recursos: Imagens mais pequenas, deployments mais rápidos
- Competências de Depuração: Identificação rápida de problemas
- Prontidão para Produção: Ajustes de segurança e desempenho
Comandos Essenciais
Ciclo de Vida do Container
# Executar container em segundo plano
docker run -d --name my-app nginx:latest
# Executar com mapeamento de portas
docker run -d -p 8080:80 nginx:latest
# Executar com múltiplos mapeamentos de portas
docker run -d -p 8080:80 -p 3000:3000 my-app
# Executar com variáveis de ambiente
docker run -d -e NODE_ENV=production -e API_KEY=secret my-app
# Executar com limites de recursos
docker run -d --cpus=0.5 --memory=256m my-app
# Executar de forma interativa
docker run -it ubuntu:latest bash
# Executar e remover ao sair
docker run --rm -it python:3.11 python
Gestão de Containers
# Listar containers em execução
docker ps
# Listar todos os containers (incluindo os parados)
docker ps -a
# Formato de saída personalizado
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"
# Parar container
docker stop my-app
# Iniciar container parado
docker start my-app
# Reiniciar container
docker restart my-app
# Remover container
docker rm my-app
# Forçar a remoção de um container em execução
docker rm -f my-app
# Remover todos os containers parados
docker rm $(docker ps -aq -f status=exited)
Executar Comandos em Containers
# Executar comando num container em execução
docker exec my-app ls -la
# Shell interativa
docker exec -it my-app bash
docker exec -it my-app sh # Para imagens baseadas em Alpine
# Executar como utilizador específico
docker exec -u root -it my-app bash
# Executar com variável de ambiente
docker exec -e DEBUG=true my-app npm test
# Obter container por padrão de nome
docker exec -it $(docker ps -aqf "name=my-app") bash
Logs e Monitorização
# Ver logs
docker logs my-app
# Seguir logs (streaming)
docker logs -f my-app
# Mostrar as últimas N linhas
docker logs --tail 100 my-app
# Mostrar logs com timestamps
docker logs -t my-app
# Mostrar logs desde um timestamp
docker logs --since 2024-01-01T00:00:00 my-app
# Utilização de recursos do container
docker stats
# Estatísticas de um container específico
docker stats my-app --no-stream
# Inspecionar detalhes do container
docker inspect my-app
# Obter campo específico
docker inspect --format '{{.NetworkSettings.IPAddress}}' my-app
Gestão de Imagens
Construir Imagens
# Build a partir do Dockerfile no diretório atual
docker build -t my-app .
# Build com Dockerfile específico
docker build -f Dockerfile.prod -t my-app:prod .
# Build com argumentos de build
docker build --build-arg NODE_VERSION=18 -t my-app .
# Build sem cache
docker build --no-cache -t my-app .
# Build com stage de destino (multi-stage)
docker build --target builder -t my-app:builder .
# Atribuir tag à imagem
docker tag my-app:latest my-registry.com/my-app:v1.0.0
Gerir Imagens
# Listar imagens
docker images
# Listar com tamanho
docker images --format "{{.Repository}}:{{.Tag}} - {{.Size}}"
# Remover imagem
docker rmi my-app:latest
# Remover imagens não utilizadas
docker image prune
# Remover todas as imagens não utilizadas (não apenas as dangling)
docker image prune -a
# Fazer pull da imagem
docker pull nginx:alpine
# Fazer push da imagem
docker push my-registry.com/my-app:v1.0.0
Volumes e Armazenamento
Gestão de Volumes
# Criar volume com nome
docker volume create my-data
# Listar volumes
docker volume ls
# Inspecionar volume
docker volume inspect my-data
# Remover volume
docker volume rm my-data
# Remover volumes não utilizados
docker volume prune
Montar Volumes
# Volume com nome
docker run -v my-data:/app/data my-app
# Bind mount (caminho do host)
docker run -v /host/path:/container/path my-app
# Bind mount do diretório atual
docker run -v $(pwd):/app my-app
# Montagem só de leitura
docker run -v /host/path:/container/path:ro my-app
# Volumes de outro container
docker run --volumes-from data-container my-app
Rede
Gestão de Redes
# Listar redes
docker network ls
# Criar rede
docker network create my-network
# Criar rede bridge com subnet
docker network create --driver bridge --subnet 172.20.0.0/16 my-network
# Ligar container à rede
docker network connect my-network my-app
# Desligar da rede
docker network disconnect my-network my-app
# Inspecionar rede
docker network inspect my-network
Rede de Containers
# Executar numa rede específica
docker run --network my-network my-app
# Executar na rede do host (sem isolamento)
docker run --network host my-app
# Ligar containers (legado; use redes em vez disso)
docker run --link db:database my-app
Melhores Práticas de Dockerfile
Dockerfile Otimizado
# Usar tags de versão específicas
FROM node:20-alpine AS builder
# Definir diretório de trabalho
WORKDIR /app
# Copiar primeiro os ficheiros de dependências (cache de camadas)
COPY package*.json ./
# Instalar dependências
RUN npm ci --only=production
# Copiar código-fonte
COPY . .
# Compilar a aplicação
RUN npm run build
# Stage de produção
FROM node:20-alpine AS production
# Criar utilizador não-root
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
WORKDIR /app
# Copiar apenas os ficheiros necessários do builder
COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./
# Mudar para utilizador não-root
USER nextjs
# Expor porta
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
# Iniciar a aplicação
CMD ["node", "dist/index.js"]
Otimização de Camadas
# MAU: Cria muitas camadas
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN rm -rf /var/lib/apt/lists/*
# BOM: Camada única, com limpeza incluída
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
git && \
rm -rf /var/lib/apt/lists/*
Multi-stage para Imagens Mais Pequenas
# Stage de build com todas as dependências de desenvolvimento
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
# Imagem mínima de produção
FROM alpine:3.18
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
CMD ["./main"]
Manutenção do Sistema
Comandos de Limpeza
# Remover todos os containers parados
docker container prune
# Remover imagens não utilizadas
docker image prune
# Remover volumes não utilizados
docker volume prune
# Remover redes não utilizadas
docker network prune
# Opção nuclear: remover tudo o que não é utilizado
docker system prune
# Incluir volumes e todas as imagens
docker system prune -a --volumes
# Mostrar utilização de disco
docker system df
# Utilização de disco detalhada
docker system df -v
Operações de Base de Dados
Backup MySQL/PostgreSQL
# Backup MySQL a partir do container
docker exec my-mysql mysqldump -u root -ppassword dbname > backup.sql
# Restauro MySQL para o container
cat backup.sql | docker exec -i my-mysql mysql -u root -ppassword dbname
# Backup PostgreSQL
docker exec my-postgres pg_dump -U postgres dbname > backup.sql
# Restauro PostgreSQL
cat backup.sql | docker exec -i my-postgres psql -U postgres dbname
Deployment em Produção
Docker Compose para Produção
version: '3.8'
services:
app:
image: my-app:${VERSION:-latest}
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Melhores Práticas de Segurança
# Não executar como root
USER 1001
# Use COPY em vez de ADD (mais previsível)
COPY requirements.txt .
# Não guardar segredos em imagens
# Use --secret ou variáveis de ambiente em runtime
# Analisar vulnerabilidades
# docker scan my-app:latest
Principais Conclusões
- Use tags específicas: Nunca use
latest em produção - Otimize as camadas: Combine comandos RUN, ordene por frequência de alteração
- Builds multi-stage: Separe os ambientes de build e de runtime
- Utilizadores não-root: Melhor prática de segurança
- Health checks: Ative a autorrecuperação do orquestrador
- Limpe regularmente: Previna problemas de espaço em disco
O domínio do Docker resulta de compreender tanto os comandos como os conceitos subjacentes — pratique estes padrões até se tornarem naturais.