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.