Docker em Produção: Containerização Eficiente
Docker é essencial para qualquer infraestrutura moderna. Um container Docker encapsula sua aplicação com todas as dependências, garantindo que funcione identicamente em desenvolvimento, teste e produção. A vantagem crítica é eliminar o famoso "funciona na minha máquina" — você entrega um artefato testado e imutável.
Para começar, você precisa criar um Dockerfile bem estruturado. Aqui está um exemplo prático com uma aplicação Node.js:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD node healthcheck.js
CMD ["node", "server.js"]
Use alpine como imagem base — é 50x menor que versões padrão, reduzindo superfície de ataque e tempo de deploy. Sempre use npm ci ao invés de npm install em produção para garantir versões exatas. O HEALTHCHECK é crucial: Kubernetes usa isso para monitorar a saúde do seu container.
Multi-stage Builds para Otimização
Imagens grandes causam pulls lentos e aumentam latência de deploys. Use multi-stage builds para separar ambiente de build do runtime:
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package*.json ./
EXPOSE 3000
CMD ["node", "dist/index.js"]
Isso reduz drasticamente o tamanho final — você descarta ferramentas de build que não são necessárias em runtime. A imagem final contém apenas o essencial.
Kubernetes em Produção: Orquestração em Escala
Kubernetes (K8s) gerencia containers automaticamente em clusters. Enquanto Docker é sobre criar e empacotar, Kubernetes é sobre orquestrar centenas de containers, gerenciar recursos, escalar e recuperar falhas. Você define o estado desejado e K8s trabalha para mantê-lo.
Um manifesto Kubernetes básico (arquivo YAML) define como sua aplicação deve rodar:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: api-server
template:
metadata:
labels:
app: api-server
spec:
containers:
- name: api-server
image: seu-registry.com/api-server:1.2.0
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: "production"
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-credentials
key: host
resources:
requests:
cpu: "500m"
memory: "256Mi"
limits:
cpu: "1000m"
memory: "512Mi"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
Este Deployment garante 3 réplicas sempre rodando. Se uma falhar, K8s cria outra automaticamente. Os resources definem quanto CPU e memória cada pod pode usar — essencial para evitar que uma aplicação mate outras no cluster. Os probes (liveness e readiness) informam ao K8s quando remover um pod do tráfego.
Exposição de Serviços e Load Balancing
Um Deployment precisa de um Service para ser acessível. O Service funciona como um load balancer interno:
apiVersion: v1
kind: Service
metadata:
name: api-server-service
namespace: production
spec:
type: LoadBalancer
selector:
app: api-server
ports:
- protocol: TCP
port: 80
targetPort: 3000
Para HTTPS em produção, use um Ingress com controlador Nginx:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.seu-dominio.com
secretName: api-tls-cert
rules:
- host: api.seu-dominio.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-server-service
port:
number: 80
Gerenciamento de Configuração e Secrets
Nunca hardcode credenciais. Use ConfigMaps para configurações e Secrets para dados sensíveis:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
LOG_LEVEL: "info"
CACHE_TTL: "3600"
---
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: production
type: Opaque
stringData:
host: postgres.internal
user: appuser
password: senhaForte123!
Boas Práticas para Produção
1. Versionamento de Imagens: Nunca use latest em produção. Use tags semânticas (v1.2.0) e atualize manifestos Kubernetes explicitamente. Isso torna rollbacks triviais — basta mudar a tag na imagem.
2. Resource Quotas e Limits: Configure limits não apenas em containers individuais, mas em namespaces inteiros. Previne uma aplicação malformada de consumir todos os recursos do cluster:
apiVersion: v1
kind: Namespace
metadata:
name: production
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "50"
requests.memory: "100Gi"
limits.cpu: "100"
limits.memory: "200Gi"
3. Monitoramento Ativo: Configure prometheus + alertmanager. Um Deployment sem observabilidade é como pilotar no escuro. Configure alertas para CPU >80%, memória >85% e taxa de erro >1%.
4. GitOps: Mantenha todo manifesto Kubernetes em git. Use ferramentas como ArgoCD para sincronizar automaticamente o estado do cluster com o repositório. Isso torna mudanças rastreáveis e revertíveis.
Conclusão
Docker containeriza suas aplicações de forma reproduzível; Kubernetes as orquestra em escala. Na prática: (1) construa imagens Docker otimizadas com multi-stage builds e use secrets/configs separados, (2) defina Deployments, Services e Ingress em YAML descritivo, deixando K8s resolver scheduling e recuperação de falhas, (3) implemente limits de recursos, health checks e monitore tudo — observabilidade não é luxo.
O caminho para dominar essa stack é iterativo: comece com um cluster local (minikube), progresse para managed services (EKS, GKE) e evolua sua arquitetura conforme a complexidade cresce.