Aula 08 - Cluster Kubernetes HA: - Setup interativo com OpenTofu para Talos na Hetzner - CCM, CSI Driver, Cluster Autoscaler, Metrics Server - NGINX Ingress com LoadBalancer (HTTP/HTTPS/SSH) Aula 09 - n8n na Hetzner: - Deploy via Helm com PostgreSQL e Redis - Suporte multi-tenant com add-client.sh - Integração com Hetzner CSI para volumes persistentes Aula 10 - GitLab na Hetzner: - Setup agnóstico: CloudFlare (trusted proxies) ou Let's Encrypt - Anti-affinity para distribuir webservice/sidekiq em nós diferentes - Container Registry e SSH via TCP passthrough - Documentação do erro 422 e solução com trustedCIDRsForXForwardedFor Melhorias gerais: - READMEs atualizados com arquitetura e troubleshooting - Scripts cleanup.sh para todas as aulas - CLAUDE.md atualizado com contexto do projeto
Aula 01 - O Problema: Apps que Travam mas Nao Morrem
Objetivo
Demonstrar uma limitacao comum em ambientes de producao: aplicacoes que param de responder mas continuam com o processo rodando. O Docker nao consegue detectar esse tipo de falha.
O Problema
Imagine uma aplicacao que:
- Tem um memory leak que causa travamento
- Entra em deadlock
- Perde conexao com o banco e fica em loop infinito
O processo continua vivo, mas a aplicacao nao responde. O Docker ve o processo rodando e nao faz nada.
A Aplicacao "Bugada"
Nossa app Node.js simula esse comportamento:
// Apos MAX_REQUESTS, para de responder mas continua rodando
if (requestCount > MAX_REQUESTS) {
console.log('App travado apos 3 requests');
return; // Nao responde, mas processo vivo
}
Arquivos
aula-01/
├── docker-compose.yml # Configuracao do container
├── app.js # Aplicacao Node.js "bugada"
└── .env # MAX_REQUESTS=3
Comandos
# Iniciar a aplicacao
docker compose up
# Parar a aplicacao
docker compose down
Teste Pratico
-
Inicie a aplicacao:
docker compose up -
Faca 3 requests (funcionam normalmente):
curl localhost:3000 # Req -> 1/3 curl localhost:3000 # Req -> 2/3 curl localhost:3000 # Req -> 3/3 -
Faca mais um request (vai travar):
curl localhost:3000 # Fica esperando para sempre... -
Observe os logs - a app diz que travou:
App travado apos 3 requests -
O container continua rodando:
docker ps # Container esta "Up", mas nao responde
A Limitacao do restart: always
No docker-compose.yml temos:
restart: always
Isso reinicia o container apenas quando o processo morre. Como nossa app trava mas o processo Node.js continua rodando, o Docker nao faz nada.
| Situacao | Processo | Docker reinicia? |
|---|---|---|
| App crasha (exit 1) | Morto | Sim |
| App trava (nosso caso) | Vivo | Nao |
Healthcheck do Docker: Detecta mas Nao Resolve
Adicionamos um healthcheck no docker-compose.yml:
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/health"]
interval: 2s
timeout: 2s
retries: 2
start_period: 5s
Apos a app travar, veja o status mudar para unhealthy:
docker ps
# STATUS: Up 1 minute (unhealthy)
Porem, o Docker apenas DETECTA o problema - nao reinicia o container!
O healthcheck serve para:
- Monitoramento e alertas
- Orquestradores externos tomarem acao
- Load balancers removerem o container do pool
Mas sozinho, nao resolve o problema.
Proximo Passo
Na Aula 02, vamos resolver esse problema usando Kubernetes com Liveness Probes - verificacoes periodicas que detectam quando a aplicacao parou de responder E reiniciam o container automaticamente.