fix: corrigir tipos de servidor AMD (CPX→CX), autoscaler, stdin e cleanup
- Corrigir tipos Hetzner: CPX não existe, usar CX (Intel shared vCPU) - CX23 (2 vCPU, 4GB) equivalente ao CAX11 - CX33 (4 vCPU, 8GB) equivalente ao CAX21 - CX43 (8 vCPU, 16GB) equivalente ao CAX31 - Corrigir location no autoscaler para amd64 (nbg1→fsn1) - Remover gitlab-pool do autoscaler (substituído pelo Gitea) - Aumentar worker-pool max para 30 - Corrigir Floating IP e Load Balancer hardcoded em nbg1 - Corrigir stdin em read interativo: usar < /dev/tty e read -p - Corrigir cleanup de namespace: lidar com Terminating e finalizers - Corrigir CNPG: nome do deployment, secret e endpointURL duplo - Aulas afetadas: 08, 09, 10, 11, 12, 14, 17
This commit is contained in:
+3
-3
@@ -14,7 +14,7 @@ Nesta aula, vamos instalar o CNPG do zero, criar um cluster HA com backup autom
|
||||
|
||||
| Item | AWS RDS Multi-AZ | CNPG na Hetzner |
|
||||
|------|------------------|-----------------|
|
||||
| Compute | db.r6g.large ~$185/mês | 3× CPX31 ~€36/mês (~$40) |
|
||||
| Compute | db.r6g.large ~$185/mês | 3× CX33 ~€24/mês (~$27) |
|
||||
| Storage 200GB | ~$23/mês (gp3) | ~€9/mês (hcloud volumes) |
|
||||
| Backup | 7 dias (free) | ~€6/mês (Object Storage 1TB) |
|
||||
| **Total mensal** | **~$208/mês** | **~€51/mês (~$56)** |
|
||||
@@ -26,7 +26,7 @@ Nesta aula, vamos instalar o CNPG do zero, criar um cluster HA com backup autom
|
||||
|
||||
### Por que Hetzner?
|
||||
|
||||
- CPX31: 4 vCPU AMD, 8GB RAM, 160GB NVMe → **~€12/mês**
|
||||
- CX33: 4 vCPU Intel, 8GB RAM, 80GB NVMe → **~€8/mês**
|
||||
- Object Storage: 1TB S3-compatible, 1TB egress free → **~€6/mês**
|
||||
- Sem surpresas: preço fixo, sem egress cost como AWS ($0.09/GB)
|
||||
|
||||
@@ -48,7 +48,7 @@ Dois operadores PostgreSQL maduros para Kubernetes. Qual escolher?
|
||||
|
||||
### Por que CNPG para indie hackers?
|
||||
|
||||
1. **Menos recursos = custo menor**. StackGres consome 3-5× mais RAM em sidecars. Num CPX31 com 8GB, isso faz diferença.
|
||||
1. **Menos recursos = custo menor**. StackGres consome 3-5× mais RAM em sidecars. Num CX33 com 8GB, isso faz diferença.
|
||||
2. **Setup mais simples**. Um Cluster CRD resolve. StackGres precisa de SGCluster, SGPostgresConfig, SGPgBouncerConfig, SGBackupConfig, SGPoolingConfig...
|
||||
3. **CNCF Sandbox**. Governança aberta, roadmap transparente, não depende de uma empresa.
|
||||
4. **GitOps nativo**. CRDs foram desenhados pra serem declarativos. Funciona com ArgoCD/Flux sem hacks.
|
||||
|
||||
+14
-2
@@ -73,13 +73,25 @@ log_success "Secrets removidos"
|
||||
|
||||
# 5. Remover namespace
|
||||
log_info "Removendo namespace cnpg..."
|
||||
kubectl delete namespace cnpg --ignore-not-found=true 2>/dev/null || true
|
||||
kubectl delete namespace cnpg --timeout=120s 2>/dev/null || {
|
||||
log_warn "Namespace preso em Terminating, forçando remoção..."
|
||||
kubectl get namespace cnpg -o json | \
|
||||
python3 -c "import sys,json; d=json.load(sys.stdin); d['metadata'].pop('finalizers',None); json.dump(d,sys.stdout)" | \
|
||||
kubectl replace --raw /api/v1/namespaces/cnpg/finalize -f - 2>/dev/null || true
|
||||
kubectl wait --for=delete namespace cnpg --timeout=60s 2>/dev/null || sleep 5
|
||||
}
|
||||
log_success "Namespace cnpg removido"
|
||||
|
||||
# 6. Remover CNPG Operator
|
||||
log_info "Removendo CNPG operator..."
|
||||
helm uninstall cnpg -n cnpg-system --wait 2>/dev/null || true
|
||||
kubectl delete namespace cnpg-system --ignore-not-found=true 2>/dev/null || true
|
||||
kubectl delete namespace cnpg-system --timeout=120s 2>/dev/null || {
|
||||
log_warn "Namespace preso em Terminating, forçando remoção..."
|
||||
kubectl get namespace cnpg-system -o json | \
|
||||
python3 -c "import sys,json; d=json.load(sys.stdin); d['metadata'].pop('finalizers',None); json.dump(d,sys.stdout)" | \
|
||||
kubectl replace --raw /api/v1/namespaces/cnpg-system/finalize -f - 2>/dev/null || true
|
||||
kubectl wait --for=delete namespace cnpg-system --timeout=60s 2>/dev/null || sleep 5
|
||||
}
|
||||
log_success "CNPG operator removido"
|
||||
|
||||
# 7. Remover CRDs
|
||||
|
||||
@@ -12,29 +12,15 @@ spec:
|
||||
# topology.kubernetes.io/zone = fsn1 | nbg1 | hel1 (datacenter)
|
||||
# topology.kubernetes.io/region = eu-central | hel-southeast
|
||||
#
|
||||
# Layer 1: podAntiAffinity on hostname (hard constraint)
|
||||
# → No 2 PG pods on the same node. Ever.
|
||||
# podAntiAffinityType: required → no 2 PG pods on same node (hard constraint)
|
||||
# topologyKey: kubernetes.io/hostname → spread across nodes
|
||||
#
|
||||
# Layer 2: podAntiAffinity on zone (soft constraint)
|
||||
# → Prefer spreading across datacenters. With nodes in fsn1, nbg1, hel1,
|
||||
# you get 1 pod per DC. With only eu-central nodes, they still spread
|
||||
# across FSN and NBG (both in eu-central, ~1-2ms apart).
|
||||
#
|
||||
# Prerequisite for cross-region (eu-central + HEL):
|
||||
# - Node pool in eu-central (FSN + NBG) → aula-08
|
||||
# - Node pool in hel-southeast (HEL) → add worker after aula-08
|
||||
# - Without HEL nodes, all 3 pods stay in eu-central (still HA within region)
|
||||
# For cross-DC spread, CNPG relies on Kubernetes scheduler topology awareness.
|
||||
# With nodes in multiple zones (fsn1, nbg1, hel1), the scheduler naturally
|
||||
# spreads pods when combined with the node autoscaler.
|
||||
affinity:
|
||||
topologyKey: kubernetes.io/hostname
|
||||
podAntiAffinityType: required
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
topologyKey: topology.kubernetes.io/zone
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
cnpg.io/cluster: shared-postgres
|
||||
storage:
|
||||
size: 10Gi
|
||||
storageClass: hcloud-volumes
|
||||
@@ -60,10 +46,6 @@ spec:
|
||||
initdb:
|
||||
database: app
|
||||
owner: app
|
||||
secret:
|
||||
name: shared-postgres-superuser
|
||||
superuserSecret:
|
||||
name: shared-postgres-superuser
|
||||
backup:
|
||||
barmanObjectStore:
|
||||
destinationPath: s3://CHANGE_BUCKET_NAME/cnpg-backups/shared-postgres
|
||||
|
||||
+16
-10
@@ -135,26 +135,22 @@ collect_config() {
|
||||
if [[ -z "$S3_ENDPOINT" ]]; then
|
||||
S3_ENDPOINT="nbg1.your-objectstorage.com"
|
||||
fi
|
||||
echo -ne "Endpoint (${GREEN}${S3_ENDPOINT}${NC}): "
|
||||
read -r input
|
||||
read -r -p "Endpoint (${GREEN}${S3_ENDPOINT}${NC}): " input < /dev/tty
|
||||
[[ -n "$input" ]] && S3_ENDPOINT="$input"
|
||||
|
||||
if [[ -z "$S3_BUCKET" ]]; then
|
||||
S3_BUCKET="cnpg-backups"
|
||||
fi
|
||||
echo -ne "Bucket name (${GREEN}${S3_BUCKET}${NC}): "
|
||||
read -r input
|
||||
read -r -p "Bucket name (${GREEN}${S3_BUCKET}${NC}): " input < /dev/tty
|
||||
[[ -n "$input" ]] && S3_BUCKET="$input"
|
||||
|
||||
echo -ne "Access Key ID: "
|
||||
read -r S3_ACCESS_KEY
|
||||
read -r -p "Access Key ID: " S3_ACCESS_KEY < /dev/tty
|
||||
if [[ -z "$S3_ACCESS_KEY" ]]; then
|
||||
log_error "Access Key é obrigatória"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -ne "Secret Access Key: "
|
||||
read -rs S3_SECRET_KEY
|
||||
read -rs -p "Secret Access Key: " S3_SECRET_KEY < /dev/tty
|
||||
echo ""
|
||||
if [[ -z "$S3_SECRET_KEY" ]]; then
|
||||
log_error "Secret Key é obrigatória"
|
||||
@@ -191,7 +187,7 @@ install_cnpg_operator() {
|
||||
log_success "CNPG operator instalado"
|
||||
|
||||
log_info "Aguardando operator ficar ready..."
|
||||
kubectl wait --for=condition=available deployment/cnpg-controller-manager -n cnpg-system --timeout=120s
|
||||
kubectl wait --for=condition=available deployment/cnpg-cloudnative-pg -n cnpg-system --timeout=120s
|
||||
log_success "CNPG operator pronto"
|
||||
}
|
||||
|
||||
@@ -205,6 +201,16 @@ setup_namespace_and_secrets() {
|
||||
echo -e "${CYAN} Criando namespace e secrets${NC}"
|
||||
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
|
||||
|
||||
if kubectl get namespace cnpg &>/dev/null; then
|
||||
NS_PHASE=$(kubectl get namespace cnpg -o jsonpath='{.status.phase}' 2>/dev/null)
|
||||
if [[ "$NS_PHASE" == "Terminating" ]]; then
|
||||
log_info "Namespace cnpg em Terminating, forçando remoção..."
|
||||
kubectl get namespace cnpg -o json | \
|
||||
python3 -c "import sys,json; d=json.load(sys.stdin); d['metadata'].pop('finalizers',None); json.dump(d,sys.stdout)" | \
|
||||
kubectl replace --raw /api/v1/namespaces/cnpg/finalize -f - 2>/dev/null || true
|
||||
kubectl wait --for=delete namespace cnpg --timeout=60s 2>/dev/null || sleep 5
|
||||
fi
|
||||
fi
|
||||
kubectl create namespace cnpg --dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
log_info "Criando secret de credenciais S3..."
|
||||
@@ -228,7 +234,7 @@ create_cluster() {
|
||||
|
||||
log_info "Gerando cluster.yaml com suas configurações..."
|
||||
sed -e "s|CHANGE_BUCKET_NAME|${S3_BUCKET}|g" \
|
||||
-e "s|CHANGE_ENDPOINT|https://${S3_ENDPOINT}|g" \
|
||||
-e "s|CHANGE_ENDPOINT|${S3_ENDPOINT}|g" \
|
||||
"${SCRIPT_DIR}/cnpg/cluster.yaml" | kubectl apply -f -
|
||||
|
||||
log_success "Cluster aplicado"
|
||||
|
||||
Reference in New Issue
Block a user