Conceitos basicos do Docker
Docker e uma plataforma que empacota aplicacoes como containers, garantindo comportamento consistente em qualquer ambiente.
Virtualizacao tradicional vs Virtualizacao de container
flowchart TB
subgraph VM["Virtualizacao Tradicional (VM)"]
direction TB
AppA1["App A"] --> GuestA["Guest OS"]
AppB1["App B"] --> GuestB["Guest OS"]
AppC1["App C"] --> GuestC["Guest OS"]
GuestA & GuestB & GuestC --> Hypervisor["Hypervisor"]
Hypervisor --> HostOS1["Host OS"]
end
subgraph Container["Virtualizacao de Container (Docker)"]
direction TB
AppA2["App A"] --> LibsA["Libs A"]
AppB2["App B"] --> LibsB["Libs B"]
AppC2["App C"] --> LibsC["Libs C"]
LibsA & LibsB & LibsC --> DockerEngine["Docker Engine"]
DockerEngine --> HostOS2["Host OS (compartilhado)"]
end
Comparacao:
- VM: Cada app precisa de um Guest OS completo (pesado)
- Container: Apenas bibliotecas, compartilhando Host OS (leve)
Fundamentos do Dockerfile
Aplicacao Node.js
# Dockerfile
FROM node:20-alpine
WORKDIR /app
# Instalacao de dependencias (aproveitando cache)
COPY package*.json ./
RUN npm ci --only=production
# Copiar codigo da aplicacao
COPY . .
# Executar como usuario nao-root
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]
Build multi-estagio
# Dockerfile.multi-stage
# =========================================
# Stage 1: Instalacao de dependencias
# =========================================
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
# =========================================
# Stage 2: Build
# =========================================
FROM node:20-alpine AS builder
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
# Variavel de ambiente (build time)
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
RUN npm run build
# =========================================
# Stage 3: Imagem de producao
# =========================================
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Seguranca: Usuario nao-root
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copiar apenas arquivos necessarios
COPY /app/dist ./dist
COPY /app/node_modules ./node_modules
COPY /app/package.json ./
USER nextjs
EXPOSE 3000
CMD ["node", "dist/server.js"]
Aplicacao Next.js
# Dockerfile.nextjs
FROM node:20-alpine AS base
# Stage 1: Dependencias
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml* ./
RUN corepack enable pnpm && pnpm i --frozen-lockfile
# Stage 2: Build
FROM base AS builder
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
# Desabilitar telemetria do Next.js
ENV NEXT_TELEMETRY_DISABLED=1
RUN corepack enable pnpm && pnpm run build
# Stage 3: Producao
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY /app/public ./public
# Usar saida standalone
COPY /app/.next/standalone ./
COPY /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]
Docker Compose
Ambiente de desenvolvimento
# docker-compose.yml
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: myapp
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
adminer:
image: adminer
ports:
- "8080:8080"
depends_on:
- db
volumes:
postgres_data:
redis_data:
Ambiente de producao
# docker-compose.prod.yml
services:
app:
image: myapp:${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
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- app
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
deploy:
resources:
limits:
memory: 1G
volumes:
postgres_data:
driver: local
Otimizacao do Dockerfile
Pontos de otimizacao do Dockerfile
1. Aproveitamento do cache de camadas
| Metodo | Codigo |
|---|---|
| Exemplo ruim | COPY . . → RUN npm install |
| Exemplo bom | COPY package*.json ./ → RUN npm ci → COPY . . |
2. Minimizacao do tamanho da imagem
| Imagem base | Tamanho |
|---|---|
| node:20 | 1.1GB |
| node:20-slim | 250MB |
| node:20-alpine | 140MB |
| Build multi-estagio final | 50-100MB |
3. Seguranca
- Executar como usuario nao-root
- Nao incluir pacotes desnecessarios
- Nao incluir secrets na imagem
- Usar .dockerignore
.dockerignore
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
.env*
.env.local
.env.*.local
Dockerfile*
docker-compose*
.dockerignore
README.md
.next
.cache
coverage
.nyc_output
*.log
.DS_Store
Health check
# Lado da aplicacao
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci --only=production
# Endpoint de health check
HEALTHCHECK \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "server.js"]
// server.ts - Endpoint de health check
import express from 'express';
const app = express();
app.get('/health', async (req, res) => {
try {
// Verificar conexao com banco de dados
await db.query('SELECT 1');
// Verificar Redis
await redis.ping();
res.status(200).json({
status: 'healthy',
timestamp: new Date().toISOString(),
checks: {
database: 'ok',
redis: 'ok',
},
});
} catch (error) {
res.status(503).json({
status: 'unhealthy',
error: error.message,
});
}
});
app.get('/ready', (req, res) => {
// Verificar se a aplicacao esta pronta
if (appIsReady) {
res.status(200).send('Ready');
} else {
res.status(503).send('Not Ready');
}
});
Gerenciamento de logs
// logger.ts - Logging para Docker
import pino from 'pino';
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
// Formato JSON recomendado para ambiente Docker
transport:
process.env.NODE_ENV === 'development'
? {
target: 'pino-pretty',
options: { colorize: true },
}
: undefined,
});
// Log estruturado
logger.info({ userId: 123, action: 'login' }, 'User logged in');
logger.error({ err: error, requestId: 'abc-123' }, 'Request failed');
export default logger;
# docker-compose.yml - Configuracao de logs
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Integracao CI/CD
# .github/workflows/docker.yml
name: Docker Build and Push
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=sha
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
Comandos mais usados
# Build de imagem
docker build -t myapp:latest .
# Executar container
docker run -d -p 3000:3000 --name myapp myapp:latest
# Verificar logs
docker logs -f myapp
# Entrar no container
docker exec -it myapp sh
# Verificar tamanho da imagem
docker images myapp
# Remover recursos nao utilizados
docker system prune -a
# Operacoes Docker Compose
docker compose up -d
docker compose down
docker compose logs -f app
docker compose exec app sh
Links de referencia
- Documentacao oficial do Docker
- Melhores praticas de Dockerfile
- Especificacao do Docker Compose
- Guia de Dockerizacao Node.js