Files
workshop/aula-08/README.md
ArgoCD Setup 2480c82944 fix(aula-08): prevenir volume stalling com CSI tolerations e PDB
- Adicionar hcloud-csi-values.yaml com tolerations para node failures
- Configurar 2 replicas do CSI controller para HA
- Criar statefulset-pdb.yaml para proteger StatefulSets durante drain
- Documentar troubleshooting de volumes stuck no README
2026-01-23 18:45:24 -03:00

6.9 KiB

Aula 08 - Cluster Kubernetes HA na Hetzner Cloud

Objetivo

Provisionar um cluster Kubernetes Talos de producao na Hetzner Cloud usando OpenTofu, com opcoes de Alta Disponibilidade (HA) e LoadBalancer.

Arquitetura

Modo HA com LoadBalancer (Recomendado)

                    Internet
                        │
                        ▼
            ┌───────────────────────┐
            │   Hetzner Load        │
            │   Balancer (LB11)     │
            │   IP: 1.2.3.4         │
            └───────────────────────┘
                        │
        ┌───────────────┼───────────────┐
        │               │               │
        ▼               ▼               ▼
   ┌─────────┐    ┌─────────┐    ┌─────────┐
   │  CP-0   │    │  CP-1   │    │  CP-2   │
   │ CAX11   │    │ CAX11   │    │ CAX11   │
   │10.0.1.10│    │10.0.1.11│    │10.0.1.12│
   └─────────┘    └─────────┘    └─────────┘
        │               │               │
        └───────────────┼───────────────┘
                        │
                        ▼
                  ┌──────────┐
                  │ Worker-0 │
                  │  CAX11   │
                  │10.0.1.20 │
                  └──────────┘

Servicos do LoadBalancer

O LoadBalancer centraliza todo o trafego externo:

Porta Destino Uso
6443 Control Planes Kubernetes API
50000 Control Planes Talos API
80 Workers HTTP (NGINX Ingress)
443 Workers HTTPS (NGINX Ingress)
22 Workers SSH (GitLab)

Roteamento L7 (por dominio)

O LoadBalancer faz apenas roteamento L4 (por porta). O roteamento por dominio e feito pelo NGINX Ingress:

LB :443 → NGINX Ingress → n8n.kube.quest      → n8n pods
                        → git.kube.quest      → gitlab pods
                        → argocd.kube.quest   → argocd pods
                        → registry.git...     → registry pods

Custos Estimados

Precos baseados em Hetzner Cloud (NBG1 - Nuremberg):

Configuracao CPs LB Custo/mes
Single 1 Floating IP ~$13
HA 3 Floating IP ~$22
HA + LB 3 LB11 ~$24
HA + LB + Autoscaler (max 5 workers) 3 LB11 ~$43

Recursos: CAX11 $4.59, LB11 $5.99, Floating IP $3.29

Pre-requisitos

# macOS
brew install opentofu
brew install siderolabs/tap/talosctl
brew install kubectl
brew install helm

# Criar imagem Talos (aula-07)
# Obter ID: hcloud image list --type snapshot

Comandos

# Provisionar cluster (interativo)
./setup.sh

# Destruir infraestrutura
./cleanup.sh

Fluxo do Setup

1. Verifica pre-requisitos
2. Coleta credenciais:
   - Token Hetzner Cloud
   - Chave SSH
   - ID da imagem Talos
3. Pergunta configuracao:
   - Cluster HA? (S/n)
   - LoadBalancer? (S/n) [se HA]
4. Cria terraform.tfvars
5. Executa tofu init/plan/apply
6. Aguarda cluster ficar pronto
7. Instala CCM (Cloud Controller Manager)
8. Instala Cluster Autoscaler
9. Instala Hetzner CSI Driver
10. Instala Metrics Server
11. Instala NGINX Ingress Controller

Componentes Instalados

Componente Funcao
Hetzner CCM Remove taints dos workers, provisiona LoadBalancers
Cluster Autoscaler Escala workers de 1 a 5 automaticamente
Hetzner CSI Driver Provisiona volumes persistentes (StorageClass: hcloud-volumes)
Metrics Server Habilita kubectl top e HPA baseado em CPU/memoria
NGINX Ingress Expoe servicos HTTP/HTTPS/SSH via LoadBalancer

Apos o Setup

Configurar kubectl

export KUBECONFIG=$PWD/kubeconfig
kubectl get nodes

Configurar talosctl

export TALOSCONFIG=$PWD/talosconfig
talosctl -n <IP> health

Ver logs do Autoscaler

kubectl logs -n cluster-autoscaler -l app=cluster-autoscaler -f

Ver IP do LoadBalancer

kubectl get svc -n ingress-nginx ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

Ver StorageClass

kubectl get storageclass
# Esperado: hcloud-volumes (default)

Ver uso de recursos

kubectl top nodes    # Uso de CPU/memoria por no
kubectl top pods -A  # Uso de CPU/memoria por pod

Testar Autoscaler

# Criar pods pending (vai escalar workers)
kubectl create deployment test --image=nginx --replicas=20

# Acompanhar
kubectl get nodes -w

# Limpar
kubectl delete deployment test

Proximos Passos

  1. Configurar DNS - Apontar dominio para o IP do LoadBalancer
  2. Deploy n8n (aula-09) - Workflow automation com PostgreSQL e Redis
  3. Deploy GitLab (aula-10) - Git + Container Registry + SSH

Arquivos

aula-08/
├── main.tf                    # Recursos principais (servers, LB, Talos)
├── variables.tf               # Variaveis de entrada
├── outputs.tf                 # Outputs do cluster
├── versions.tf                # Versoes dos providers
├── setup.sh                   # Script de setup interativo
├── cleanup.sh                 # Script de destruicao
├── cluster-autoscaler.yaml    # Manifesto do autoscaler
├── install-nginx-ingress.sh   # Instala NGINX Ingress com LB
├── install-metrics-server.sh  # Instala Metrics Server (kubectl top, HPA)
├── nginx-ingress-values.yaml  # Configuracao do NGINX Ingress
├── talos-patches/             # Patches de configuracao Talos
│   ├── control-plane.yaml
│   └── worker.yaml
├── hcloud-csi-values.yaml     # Configuracao do CSI Driver
└── statefulset-pdb.yaml       # PDB para proteger StatefulSets

Troubleshooting: Volume Stuck

Se um pod ficar Pending aguardando volume:

1. Verificar VolumeAttachment

kubectl get volumeattachments
kubectl describe volumeattachment <name>

2. Se o node de origem nao existe mais

# Deletar o VolumeAttachment orfao (seguro pois node nao existe)
kubectl delete volumeattachment <name>

3. Se o node existe mas pod morreu

# Aguardar - Kubernetes vai liberar automaticamente
# Timeout padrao: 6 minutos

4. Verificar no Hetzner

hcloud volume list
# Se volume mostra attached a server que nao existe, abrir ticket

Limitacoes do Block Storage

  • Volumes Hetzner sao RWO (ReadWriteOnce) - single-attach por design
  • Podem ficar stuck por ate 6 min (timeout do Kubernetes)
  • Se node morrer abruptamente, recuperacao pode ser manual (deletar VolumeAttachment)