📚 Série: DevOps & Deploy → Flask Python | Deploy Aplicação | VPS Servidor
O que é Docker?
Docker é uma plataforma open-source para criar, distribuir e executar aplicações em containers. Containers empacotam código + dependências, garantindo que aplicações rodem identicamente em qualquer ambiente (dev, staging, produção). Docker é usado por 85% das empresas Fortune 500, incluindo Netflix, Spotify e Uber. Criado em 2013, Docker revolucionou deploy de aplicações.
Site oficial: docker.com GitHub: docker/docker-ce
Por que usar Docker em 2025
Problemas que Docker resolve:
Sem Docker:
- ❌ “Funciona na minha máquina” (diferenças de ambiente)
- ❌ Conflitos de dependências (Python 3.10 vs 3.11)
- ❌ Setup complexo (instalar 10+ dependências manualmente)
- ❌ Deploy manual demorado (30-60 min)
Com Docker:
- ✅ Ambiente idêntico (dev = produção)
- ✅ Isolamento total (sem conflitos)
- ✅ Setup em 1 comando (
docker run) - ✅ Deploy em segundos
Docker vs Máquinas Virtuais:
| Característica | Docker | VM (VirtualBox) |
|---|---|---|
| Tamanho | 50-200 MB | 2-10 GB |
| Startup | <1 segundo | 30-60 segundos |
| Performance | ✅ Nativa | ⚠️ Overhead 10-15% |
| Isolamento | ✅ Processo | ✅ Sistema completo |
| Uso de recursos | ✅ Baixo | ❌ Alto |
| Portabilidade | ✅ Total | ⚠️ Limitada |
Instalação Docker
Linux (Ubuntu/Debian):
# Remover versões antigas
sudo apt remove docker docker-engine docker.io containerd runc
# Atualizar
sudo apt update
sudo apt install ca-certificates curl gnupg
# Adicionar chave GPG
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Adicionar repositório
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Instalar Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Adicionar usuário ao grupo docker
sudo usermod -aG docker $USER
newgrp docker
# Verificar
docker --version
# Docker version 24.0.7
macOS:
- Baixar: Docker Desktop for Mac
- Instalar (drag & drop)
- Abrir Docker Desktop
- Verificar:
docker --version
Windows:
- Habilitar WSL 2: Docs Microsoft
- Baixar: Docker Desktop for Windows
- Instalar
- Verificar no PowerShell:
docker --version
Conceitos fundamentais
1. Image (Imagem)
Template imutável com código + dependências.
Exemplo: python:3.11-slim (imagem oficial Python)
2. Container
Instância executável de uma imagem.
Analogia: Imagem = receita de bolo | Container = bolo assado
3. Dockerfile
Arquivo texto com instruções para criar imagem.
FROM python:3.11
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
4. Docker Compose
Ferramenta para rodar múltiplos containers (ex: app + banco).
Primeiro container: Hello World
# Baixar e executar imagem hello-world
docker run hello-world
# Saída:
# Hello from Docker!
# This message shows that your installation appears to be working correctly.
O que aconteceu:
- Docker procurou imagem
hello-worldlocalmente - Não encontrou, baixou do Docker Hub
- Criou container a partir da imagem
- Executou comando padrão
- Mostrou mensagem
- Container parou
Criar Dockerfile (aplicação Python)
Projeto exemplo: API Flask
Estrutura:
meu-projeto/
├── app.py
├── requirements.txt
└── Dockerfile
app.py:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return {'message': 'Hello from Docker!'}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
requirements.txt:
flask==3.0.0
Dockerfile:
# Imagem base (Python 3.11 slim = menor tamanho)
FROM python:3.11-slim
# Metadados
LABEL maintainer="seu@email.com"
# Diretório de trabalho
WORKDIR /app
# Copiar requirements primeiro (cache layer)
COPY requirements.txt .
# Instalar dependências
RUN pip install --no-cache-dir -r requirements.txt
# Copiar código
COPY . .
# Expor porta
EXPOSE 8000
# Comando padrão
CMD ["python", "app.py"]
Build e run:
# Build imagem
docker build -t minha-api:v1 .
# Listar imagens
docker images
# REPOSITORY TAG IMAGE ID SIZE
# minha-api v1 abc123def456 150MB
# Executar container
docker run -d -p 8000:8000 --name minha-api-container minha-api:v1
# Testar
curl http://localhost:8000
# {"message":"Hello from Docker!"}
Flags explicadas:
-d: detached (background)-p 8000:8000: mapear porta host:container--name: nome do container
Comandos essenciais
Containers:
# Listar containers rodando
docker ps
# Listar todos (incluindo parados)
docker ps -a
# Parar container
docker stop minha-api-container
# Iniciar container parado
docker start minha-api-container
# Remover container
docker rm minha-api-container
# Logs
docker logs minha-api-container
# Logs em tempo real
docker logs -f minha-api-container
# Executar comando em container rodando
docker exec -it minha-api-container bash
# Inspecionar container
docker inspect minha-api-container
Images:
# Listar imagens
docker images
# Baixar imagem
docker pull python:3.11
# Remover imagem
docker rmi minha-api:v1
# Fazer push (Docker Hub)
docker push usuario/minha-api:v1
Docker Compose (múltiplos containers)
Caso de uso: Flask + PostgreSQL
docker-compose.yml:
version: '3.8'
services:
# Banco de dados
db:
image: postgres:15
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: senha123
POSTGRES_DB: mydb
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
# API Flask
api:
build: .
command: python app.py
environment:
DATABASE_URL: postgresql://admin:senha123@db:5432/mydb
ports:
- "8000:8000"
depends_on:
- db
volumes:
- .:/app
volumes:
postgres_data:
Comandos Docker Compose:
# Subir todos containers
docker-compose up -d
# Ver logs
docker-compose logs -f
# Parar todos
docker-compose down
# Rebuild e subir
docker-compose up --build
# Ver containers rodando
docker-compose ps
Volumes (persistência de dados)
Sem volume: Dados deletados quando container para.
Com volume: Dados persistem.
# Criar volume
docker volume create meu-volume
# Usar volume
docker run -d -v meu-volume:/data alpine
# Listar volumes
docker volume ls
# Inspecionar
docker volume inspect meu-volume
No Dockerfile:
VOLUME ["/data"]
No docker-compose.yml:
volumes:
- ./local-folder:/container-folder
Caso Real: Deploy Evolution API
docker-compose.yml:
version: '3.8'
services:
evolution-api:
image: atendai/evolution-api:latest
environment:
AUTHENTICATION_API_KEY: minha_chave_secreta
DATABASE_ENABLED: true
DATABASE_PROVIDER: postgresql
DATABASE_CONNECTION_URI: postgresql://user:pass@db:5432/evolution
ports:
- "8080:8080"
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_USER: evolution
POSTGRES_PASSWORD: senha123
POSTGRES_DB: evolution
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Subir:
docker-compose up -d
# Acessar: http://localhost:8080
Boas práticas Dockerfile
1. Use imagens oficiais e slim
❌ Ruim:
FROM ubuntu:latest # 77 MB
RUN apt install python3
✅ Bom:
FROM python:3.11-slim # 45 MB
2. Multi-stage builds (reduzir tamanho)
# Stage 1: Build
FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
# Stage 2: Runtime
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
CMD ["python", "app.py"]
Resultado: Imagem 60% menor (não inclui ferramentas de build).
3. Order layers (cache inteligente)
❌ Ruim (rebuild tudo sempre):
COPY . .
RUN pip install -r requirements.txt
✅ Bom (cache se requirements não muda):
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
4. .dockerignore
# .dockerignore
__pycache__/
*.pyc
.git/
.env
node_modules/
venv/
Deploy em produção
Opção 1: VPS com Docker
# SSH no servidor
ssh user@meu-servidor.com
# Clonar repo
git clone https://github.com/user/projeto.git
cd projeto
# Subir com Docker Compose
docker-compose up -d
# Configurar Traefik (reverse proxy)
# Ver tutorial completo: https://doc.traefik.io/traefik/
Opção 2: Render.com
- Criar
Dockerfileno projeto - Conectar GitHub ao Render
- Deploy automático a cada push
Docs: Render Docker
Opção 3: AWS ECS/Fargate
# Push imagem para ECR
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com
docker tag minha-api:v1 123456789.dkr.ecr.us-east-1.amazonaws.com/minha-api:v1
docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/minha-api:v1
Troubleshooting
Container não inicia:
# Ver logs
docker logs container-name
# Ver detalhes
docker inspect container-name
Porta já em uso:
# Matar processo na porta 8000
lsof -ti:8000 | xargs kill -9
# Ou usar porta diferente
docker run -p 8001:8000 minha-api
Disco cheio (imagens antigas):
# Limpar containers parados
docker container prune
# Limpar imagens não usadas
docker image prune
# Limpar TUDO (cuidado!)
docker system prune -a
Docker Hub (registry público)
Fazer push:
# Login
docker login
# Tag com username
docker tag minha-api:v1 meuusername/minha-api:v1
# Push
docker push meuusername/minha-api:v1
Usar imagem pública:
docker pull meuusername/minha-api:v1
docker run -p 8000:8000 meuusername/minha-api:v1
Imagens populares:
nginx:latest- Web serverpostgres:15- Banco de dadosredis:latest- Cachepython:3.11- Python runtime
Caso Real: Startup reduziu custos 70%
Empresa: SaaS B2B (10 microservices)
Antes do Docker:
- 10 VPS separados ($50/cada = $500/mês)
- Deploy manual (30 min por service)
- Downtime frequente (inconsistências de ambiente)
Depois do Docker:
- 2 VPS com Docker Swarm ($150/mês total)
- Deploy automático (< 1 min)
- Zero downtime (rolling updates)
Resultados:
- ✅ Custo: $500 → $150/mês (70% economia)
- ✅ Deploy time: 30 min → 1 min
- ✅ Uptime: 95% → 99.9%
- ✅ Produtividade dev: +40%
Documentação oficial
Próximos passos
- Deploy aplicação - Produção completa
- VPS Servidor - Configurar VPS
- Flask Python - Criar API
- Evolution API - Deploy com Docker
Sobre o autor: Felipe Zanoni é especialista em DevOps e Docker, com 300+ deploys em containers para produção.