feat(docker): Add Dockerfile, docker-compose and Docker setup guide
This commit is contained in:
324
DOCKER_SETUP_GUIDE.md
Normal file
324
DOCKER_SETUP_GUIDE.md
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
# 🐳 Docker Setup Guide - Task Manager Backend
|
||||||
|
|
||||||
|
## 📋 Pré-requisitos
|
||||||
|
|
||||||
|
Você precisa ter instalado:
|
||||||
|
- ✅ [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
||||||
|
- ✅ [Docker Compose](https://docs.docker.com/compose/install/) (vem com Docker Desktop)
|
||||||
|
|
||||||
|
**Verificar instalação:**
|
||||||
|
```bash
|
||||||
|
docker --version
|
||||||
|
docker-compose --version
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Quick Start
|
||||||
|
|
||||||
|
### 1. Build da Imagem Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navegar para o diretório do projeto
|
||||||
|
cd c:\Users\Erik Silva\Documents\projetos\to-do-list
|
||||||
|
|
||||||
|
# Fazer build da imagem (primeira vez)
|
||||||
|
docker build -t todolist-backend:latest ./backend-api
|
||||||
|
```
|
||||||
|
|
||||||
|
**Esperado:**
|
||||||
|
```
|
||||||
|
[+] Building 45.3s (15/15) FINISHED
|
||||||
|
=> => naming to docker.io/library/todolist-backend:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Rodar o Container
|
||||||
|
|
||||||
|
#### Opção A: Com Docker Compose (RECOMENDADO)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Iniciar todos os serviços
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Ver logs
|
||||||
|
docker-compose logs -f backend
|
||||||
|
|
||||||
|
# Parar serviços
|
||||||
|
docker-compose down
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Opção B: Direto com Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Rodar container
|
||||||
|
docker run -d \
|
||||||
|
--name todolist-backend \
|
||||||
|
-p 3000:3000 \
|
||||||
|
-e SUPABASE_URL=https://seu-projeto.supabase.co \
|
||||||
|
-e SUPABASE_ANON_KEY=sua-anon-key \
|
||||||
|
-e SUPABASE_SERVICE_KEY=sua-service-key \
|
||||||
|
-e JWT_SECRET=sua-chave-secreta-32-chars \
|
||||||
|
todolist-backend:latest
|
||||||
|
|
||||||
|
# Ver logs
|
||||||
|
docker logs -f todolist-backend
|
||||||
|
|
||||||
|
# Parar container
|
||||||
|
docker stop todolist-backend
|
||||||
|
docker rm todolist-backend
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Testar a API
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Health check
|
||||||
|
curl http://localhost:3000/api
|
||||||
|
|
||||||
|
# Criar usuário
|
||||||
|
curl -X POST http://localhost:3000/api/auth/signup \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"email":"test@example.com","password":"Test123456"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Estrutura do Dockerfile
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
STAGE 1: BUILDER (Multi-stage)
|
||||||
|
├── Node 20 Alpine
|
||||||
|
├── npm ci (instalar dependências)
|
||||||
|
├── npm run build (compilar TypeScript)
|
||||||
|
|
||||||
|
STAGE 2: RUNNER (Otimizado para produção)
|
||||||
|
├── Node 20 Alpine (imagem limpa)
|
||||||
|
├── npm ci --only=production (sem devDependencies)
|
||||||
|
├── Usuário não-root (nodejs)
|
||||||
|
├── Health check configurado
|
||||||
|
└── 150-200 MB de tamanho final
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Configuração com Variáveis de Ambiente
|
||||||
|
|
||||||
|
### Arquivo `.env` (LOCAL)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copiar template
|
||||||
|
cp backend-api/.env.example backend-api/.env
|
||||||
|
|
||||||
|
# Editar com seus valores
|
||||||
|
nano backend-api/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
**Conteúdo de exemplo:**
|
||||||
|
```env
|
||||||
|
NODE_ENV=development
|
||||||
|
PORT=3000
|
||||||
|
API_PREFIX=/api
|
||||||
|
|
||||||
|
# Supabase
|
||||||
|
SUPABASE_URL=https://abcdefghijk.supabase.co
|
||||||
|
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||||
|
SUPABASE_SERVICE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||||
|
|
||||||
|
# JWT
|
||||||
|
JWT_SECRET=sua-chave-secreta-com-minimo-32-caracteres
|
||||||
|
JWT_EXPIRATION=7d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variáveis em `docker-compose.yml`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
NODE_ENV: development
|
||||||
|
SUPABASE_URL: ${SUPABASE_URL:-default-value}
|
||||||
|
# ... outras variáveis
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usar arquivo `.env` (NÃO recomendado para produção):**
|
||||||
|
```bash
|
||||||
|
docker-compose --env-file backend-api/.env up
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Comandos Úteis
|
||||||
|
|
||||||
|
### Build e Imagens
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fazer build
|
||||||
|
docker build -t todolist-backend:latest ./backend-api
|
||||||
|
|
||||||
|
# Listar imagens
|
||||||
|
docker images | grep todolist
|
||||||
|
|
||||||
|
# Inspecionar imagem
|
||||||
|
docker inspect todolist-backend:latest
|
||||||
|
|
||||||
|
# Remover imagem
|
||||||
|
docker rmi todolist-backend:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Containers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Listar containers
|
||||||
|
docker ps -a
|
||||||
|
|
||||||
|
# Ver logs
|
||||||
|
docker logs todolist-backend
|
||||||
|
docker logs -f todolist-backend # Follow (tempo real)
|
||||||
|
docker logs --tail 50 todolist-backend # Últimas 50 linhas
|
||||||
|
|
||||||
|
# Executar comando no container
|
||||||
|
docker exec -it todolist-backend sh
|
||||||
|
|
||||||
|
# Ver recursos utilizados
|
||||||
|
docker stats todolist-backend
|
||||||
|
|
||||||
|
# Remover container
|
||||||
|
docker rm todolist-backend
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Compose
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Iniciar
|
||||||
|
docker-compose up # foreground
|
||||||
|
docker-compose up -d # background
|
||||||
|
|
||||||
|
# Ver status
|
||||||
|
docker-compose ps
|
||||||
|
|
||||||
|
# Ver logs
|
||||||
|
docker-compose logs -f backend
|
||||||
|
docker-compose logs backend --tail 50
|
||||||
|
|
||||||
|
# Recriar containers
|
||||||
|
docker-compose restart
|
||||||
|
|
||||||
|
# Remover tudo
|
||||||
|
docker-compose down # para containers
|
||||||
|
docker-compose down -v # remove também volumes
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Health Check
|
||||||
|
|
||||||
|
O Dockerfile inclui um health check automático:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ver status
|
||||||
|
docker inspect --format='{{json .State.Health}}' todolist-backend
|
||||||
|
|
||||||
|
# Esperado:
|
||||||
|
# {"Status":"healthy","FailingStreak":0,"Passes":1,"Fails":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Otimizações
|
||||||
|
|
||||||
|
### Tamanho da Imagem
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verificar tamanho
|
||||||
|
docker images todolist-backend
|
||||||
|
|
||||||
|
# REPOSITORY TAG SIZE
|
||||||
|
# todolist-backend latest 180MB
|
||||||
|
|
||||||
|
# Reduzir size:
|
||||||
|
# - Alpine Linux: 180MB (atual) vs 900MB (sem alpine)
|
||||||
|
# - Multi-stage build: elimina dependências de build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm ci vs npm install
|
||||||
|
# - npm ci: mais rápido, dependências exatas
|
||||||
|
# - Ideal para CI/CD e Docker
|
||||||
|
|
||||||
|
# .dockerignore
|
||||||
|
# - Reduz contexto de build
|
||||||
|
# - Evita copiar arquivos desnecessários
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Troubleshooting
|
||||||
|
|
||||||
|
### Erro: "Cannot find module"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Problema: node_modules não instalado no container
|
||||||
|
# Solução:
|
||||||
|
docker-compose down
|
||||||
|
docker-compose build --no-cache
|
||||||
|
docker-compose up
|
||||||
|
```
|
||||||
|
|
||||||
|
### Erro: "EADDRINUSE: address already in use :::3000"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Problema: Porta 3000 já está em uso
|
||||||
|
# Solução 1: Usar porta diferente
|
||||||
|
docker run -p 3001:3000 todolist-backend:latest
|
||||||
|
|
||||||
|
# Solução 2: Matar processo que está usando porta 3000
|
||||||
|
lsof -i :3000
|
||||||
|
kill -9 <PID>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Erro: Variáveis de ambiente não funcionam
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Problema: .env não está sendo lido
|
||||||
|
# Solução: Usar docker-compose ou passar com -e
|
||||||
|
|
||||||
|
# ❌ Não funciona:
|
||||||
|
docker run todolist-backend:latest
|
||||||
|
|
||||||
|
# ✅ Funciona:
|
||||||
|
docker run -e SUPABASE_URL=... todolist-backend:latest
|
||||||
|
docker-compose up # lê .env automaticamente
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health check falhando
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verificar logs
|
||||||
|
docker logs todolist-backend
|
||||||
|
|
||||||
|
# Testar manualmente
|
||||||
|
docker exec todolist-backend curl http://localhost:3000/api
|
||||||
|
|
||||||
|
# Se falhar, a API não está respondendo
|
||||||
|
# Verificar: .env, credenciais Supabase, conexão de rede
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Referências
|
||||||
|
|
||||||
|
- 📖 [Docker Docs](https://docs.docker.com/)
|
||||||
|
- 📖 [Docker Compose Guide](https://docs.docker.com/compose/)
|
||||||
|
- 📖 [Best Practices](https://docs.docker.com/develop/dev-best-practices/)
|
||||||
|
- 🐳 [Alpine Linux](https://hub.docker.com/_/alpine) - Imagem base
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Próximos Passos
|
||||||
|
|
||||||
|
1. ✅ Dockerfile criado e testado
|
||||||
|
2. ➡️ Fazer commit (`feat(docker): Add Dockerfile and docker-compose`)
|
||||||
|
3. ➡️ Frontend Next.js (Fase 2) - **Próximo grande passo**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Status**: 🐳 Docker ready for local development e produção!
|
||||||
55
backend-api/.dockerignore
Normal file
55
backend-api/.dockerignore
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# .dockerignore - Arquivos/pastas que NÃO devem ser copiados para a imagem
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.gitattributes
|
||||||
|
|
||||||
|
# Node.js
|
||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
.npm
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# Build
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
.next
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
docker-compose.yml
|
||||||
|
.dockerignore
|
||||||
|
Dockerfile
|
||||||
|
|
||||||
|
# Documentação
|
||||||
|
README.md
|
||||||
|
docs
|
||||||
|
*.md
|
||||||
|
|
||||||
|
# CI/CD
|
||||||
|
.github
|
||||||
|
.gitlab-ci.yml
|
||||||
|
.travis.yml
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
test
|
||||||
|
tests
|
||||||
|
*.test.ts
|
||||||
|
*.spec.ts
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.env.example
|
||||||
|
.env.*.local
|
||||||
74
backend-api/Dockerfile
Normal file
74
backend-api/Dockerfile
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# 🐳 Task Manager Backend - Dockerfile
|
||||||
|
# ============================================================================
|
||||||
|
# Build Multi-stage:
|
||||||
|
# 1. Builder: Compila TypeScript → JavaScript
|
||||||
|
# 2. Runner: Executa aplicação em produção
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# STAGE 1: BUILDER (Compilação)
|
||||||
|
# ============================================================================
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copiar package.json e package-lock.json
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Instalar dependências (incluindo dev)
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Copiar código-fonte
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Compilar TypeScript
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# STAGE 2: RUNNER (Produção)
|
||||||
|
# ============================================================================
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 📝 Metadados da imagem
|
||||||
|
LABEL maintainer="Erik Silva <erik@stackbyte.com>"
|
||||||
|
LABEL version="1.0"
|
||||||
|
LABEL description="Task Manager API - Backend NestJS com Supabase"
|
||||||
|
|
||||||
|
# Definir NODE_ENV para produção
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
# Copiar package.json (para saber quais dependências instalar)
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Instalar apenas dependências de produção
|
||||||
|
RUN npm ci --only=production && \
|
||||||
|
npm cache clean --force
|
||||||
|
|
||||||
|
# Copiar código compilado do builder
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
|
||||||
|
# Criar usuário não-root para segurança
|
||||||
|
RUN addgroup -g 1001 -S nodejs && \
|
||||||
|
adduser -S nodejs -u 1001
|
||||||
|
|
||||||
|
# Mudar propriedade dos arquivos
|
||||||
|
RUN chown -R nodejs:nodejs /app
|
||||||
|
|
||||||
|
# Mudar para usuário não-root
|
||||||
|
USER nodejs
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# HEALTH CHECK
|
||||||
|
# ============================================================================
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
|
CMD node -e "require('http').get('http://localhost:3000/api', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})" || exit 1
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# PORTA E COMANDO
|
||||||
|
# ============================================================================
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["node", "dist/main.js"]
|
||||||
97
docker-compose.yml
Normal file
97
docker-compose.yml
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# 🐳 Task Manager - Docker Compose
|
||||||
|
# ============================================================================
|
||||||
|
# Orquestra múltiplos serviços:
|
||||||
|
# - backend: NestJS API
|
||||||
|
# - postgres: Banco de dados (opcional, para desenvolvimento local)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# ============================================================================
|
||||||
|
# BACKEND - NestJS API
|
||||||
|
# ============================================================================
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ./backend-api
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
|
||||||
|
container_name: todolist-backend
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
|
||||||
|
environment:
|
||||||
|
# ⚠️ IMPORTANTE: Use arquivo .env em produção, não em docker-compose
|
||||||
|
NODE_ENV: development
|
||||||
|
PORT: 3000
|
||||||
|
API_PREFIX: /api
|
||||||
|
# Supabase (substitua com seus valores reais)
|
||||||
|
SUPABASE_URL: ${SUPABASE_URL:-https://seu-projeto.supabase.co}
|
||||||
|
SUPABASE_ANON_KEY: ${SUPABASE_ANON_KEY:-sua-anon-key}
|
||||||
|
SUPABASE_SERVICE_KEY: ${SUPABASE_SERVICE_KEY:-sua-service-key}
|
||||||
|
JWT_SECRET: ${JWT_SECRET:-sua-chave-secreta-de-32-caracteres-minimo}
|
||||||
|
JWT_EXPIRATION: 7d
|
||||||
|
|
||||||
|
# Volumes para desenvolvimento (hot reload)
|
||||||
|
volumes:
|
||||||
|
- ./backend-api/src:/app/src
|
||||||
|
- ./backend-api/dist:/app/dist
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:3000/api"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 5s
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "10m"
|
||||||
|
max-file: "3"
|
||||||
|
|
||||||
|
# Reiniciar automaticamente em caso de crash
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# Redes
|
||||||
|
networks:
|
||||||
|
- todolist-network
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# POSTGRES (Opcional - se usar Supabase local)
|
||||||
|
# ============================================================================
|
||||||
|
# postgres:
|
||||||
|
# image: postgres:16-alpine
|
||||||
|
# container_name: todolist-postgres
|
||||||
|
#
|
||||||
|
# environment:
|
||||||
|
# POSTGRES_USER: postgres
|
||||||
|
# POSTGRES_PASSWORD: postgres123
|
||||||
|
# POSTGRES_DB: todolist
|
||||||
|
#
|
||||||
|
# ports:
|
||||||
|
# - "5432:5432"
|
||||||
|
#
|
||||||
|
# volumes:
|
||||||
|
# - postgres-data:/var/lib/postgresql/data
|
||||||
|
#
|
||||||
|
# networks:
|
||||||
|
# - todolist-network
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# VOLUMES (dados persistentes)
|
||||||
|
# ============================================================================
|
||||||
|
volumes:
|
||||||
|
postgres-data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# NETWORKS (comunicação entre serviços)
|
||||||
|
# ============================================================================
|
||||||
|
networks:
|
||||||
|
todolist-network:
|
||||||
|
driver: bridge
|
||||||
Reference in New Issue
Block a user