kb.erickguedes.com
Docker: Containers do Dev ao Deploy

Docker em Produção

Aula 7 de 7

Logs e Monitoramento

# Driver de log padrão (json-file)
docker run --log-driver json-file --log-opt max-size=10m --log-opt max-file=3 nginx

# Logs para stdout (melhor para Docker)
# A aplicação deve escrever logs em stdout/stderr
CMD ["node", "app.js"]
# ⚠️ NUNCA logar para arquivo em produção

# Coletar logs (Promtail → Loki, Filebeat → ES)
docker run \
  -v /var/lib/docker/containers:/var/log/containers:ro \
  grafana/promtail:latest \
  -config.file=/etc/promtail/promtail.yaml

Resource Limits

# Limitar recursos
docker run -d --name app \
  --memory=512m \
  --memory-reservation=256m \
  --cpus=1.0 \
  --cpuset-cpus=0,1 \
  --blkio-weight=500 \
  nginx:alpine

# docker-compose
services:
  app:
    image: nginx:alpine
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
        reservations:
          cpus: "0.25"
          memory: 256M

Healthchecks

FROM node:20-alpine
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  --start-period=40s \
  CMD node healthcheck.js
# Verificar status
docker inspect --format='{{.State.Health.Status}}' meu-container
# healthy | unhealthy | starting

# No Swarm/Compose:
services:
  app:
    image: nginx:alpine
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 5s
      retries: 3

Log Drivers

# json-file (padrão) — logs em arquivos JSON
docker run --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  nginx:alpine

# journald — logs no systemd journal
docker run --log-driver journald nginx:alpine
journalctl -u docker CONTAINER_NAME=meu-nginx

# syslog — logs para syslog remoto
docker run --log-driver syslog \
  --log-opt syslog-address=udp://192.168.1.100:514 \
  nginx:alpine

# none — sem logs (quando não precisa)
docker run --log-driver none nginx:alpine

Restart Policies

# Politicas de restart
docker run -d --restart always nginx:alpine
# no        → nunca reinicia (padrão)
# on-failure → reinicia se erro (exit != 0)
# always    → sempre reinicia
# unless-stopped → sempre, exceto se parado manualmente

# Docker Compose
services:
  app:
    image: nginx:alpine
    deploy:
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s

CI/CD Pipeline

# .github/workflows/docker.yml
name: Build & Push

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Docker em Produção Checklist

  • Imagens com tags fixas (não latest)
  • Non-root user no Dockerfile
  • Healthcheck configurado
  • Resource limits definidos
  • Read-only filesystem + tmpfs
  • Secrets montados (não env vars)
  • Logs em stdout (não arquivo)
  • Log driver configurado (max-size, max-file)
  • Image scanning no CI
  • Multi-stage build (imagem mínima)
  • .dockerignore presente
  • Restart policy configurada
  • Capabilities mínimas
  • Dockerfile sem secrets hardcoded

Produção exige disciplina: imagens mínimas, usuário não-root, healthchecks, resource limits e logs gerenciados. Container não é VM — trate como processo efêmero.