Files
athletic-map-deploy/tenants/teste5/00-namespace-quota-netpol.yaml
T
provisionamento Athletic Map 706a6e67ab feat(tenant): provisiona teste5
Cliente: Teste5
Assinatura: sub_zx7fdtz40b8is2gk
Plano: (nao informado)
Realm: athleticmap-9

Gerado pelo provisionamento automatico (P5.2/P5.3) a partir do molde
consolidado de P4.9. O ApplicationSet cria a Application sozinho pelo
gerador de diretorio sobre tenants/*.
2026-09-25 15:26:54 +00:00

177 lines
7.4 KiB
YAML

# =============================================================================
# P4.9 — o molde consolidado: 4 Deployments no lugar de 15.
#
# ── POR QUE FORA DE `tenants/` ───────────────────────────────────────────────
#
# O ApplicationSet do ArgoCD tem um gerador de diretorio sobre `tenants/*`. Uma
# pasta de MOLDE ali dentro seria tratada como tenant e implantada — com nome de
# namespace de mentira e tudo. Por isso os moldes vivem em `moldes/`, que o
# gerador nao enxerga.
#
# `scripts/provisionar_tenant.py` procura o molde em `tenants/<nome>`: ele
# precisa aprender este caminho novo. Esta no diario.
#
# ── A COTA, COM OS NUMEROS MEDIDOS ───────────────────────────────────────────
#
# Hoje, um tenant (`escolinha`, medido em 2026-09-18): **5253 Mi em 18 pods**.
#
# Com a consolidacao, medido container a container no mesmo dia:
#
# runtime-core 384 MiB
# runtime-operacao 403 MiB
# runtime-saude 366 MiB
# frontend-spa 24 MiB
# ----------------------------
# soma 1.177 MiB
#
# OS NUMEROS DA TABELA ACIMA SAO DE QUANDO ERAM QUATRO DEPLOYMENTS. Hoje sao
# cinco (o `servico-bff` entrou em 2026-09-24), e os tetos ja viveram duas
# correcoes: requests.memory 1.5Gi -> 2Gi, limits.memory 2.5Gi -> 3.5Gi ->
# 4352Mi, pods 8 -> 10. A razao de cada valor esta ao lado dele, la embaixo.
#
# A REGRA QUE VALE PARA TODOS: a cota tem de caber o REPOUSO MAIS UMA TROCA.
# Um Deployment sobe o pod novo ANTES de derrubar o velho, entao no pico existe
# um pod a mais do que o desenho sugere -- e o `maxSurge: 25%` sobre uma unica
# replica arredonda para cima, ou seja, sempre um inteiro.
#
# Ja custou duas vezes, pela mesma causa em dimensoes diferentes: derrubou o
# provisionamento do `plataforma` em 2026-09-17 (faltou `pods`), e prendeu os
# dois tenants pagos por 12h em 2026-09-24 (faltou `limits.memory`), com o
# ArgoCD dizendo "Synced" enquanto o pod novo era recusado pela cota.
#
#
# NAO ha Postgres nem Keycloak aqui: os dois passam a viver em `plataforma-prod`
# (P4.7 e P4.8).
# =============================================================================
apiVersion: v1
kind: Namespace
metadata:
name: teste5-prod
labels:
kubernetes.io/metadata.name: teste5-prod
athleticmap.io/tenant: teste5
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: cota
namespace: teste5-prod
spec:
hard:
# SUBIU em 2026-09-24 para caber o BFF, o quinto Deployment.
#
# Nao e folga generosa: com quatro Deployments o tenant ja usava 1232Mi dos
# 1536Mi, e o BFF pede 256Mi. Caberia no limite antigo em repouso, e
# estouraria no primeiro rollout — que e quando um Deployment sobe o pod
# novo antes de derrubar o velho. Foi essa conta que derrubou o
# provisionamento do `plataforma` em 17/09, e o registro dela esta ali.
#
# `pods` vai a 10 pelo mesmo motivo: cinco Deployments, um surge cada.
requests.cpu: "1.5"
requests.memory: 2Gi
limits.cpu: "5"
# SUBIU de 3.5Gi em 2026-09-25: faltava por 128Mi na hora da troca.
#
# A conta que o comentario acima comecou, agora terminada. Em repouso os
# cinco Deployments somam 2944Mi (128 + 768*3 + 512). O `maxSurge: 25%` sobre
# UMA replica arredonda para cima e pede um pod inteiro a mais: 768Mi, se o
# que esta trocando e um runtime. 2944 + 768 = 3712, contra um teto de 3584.
#
# Nao foi hipotese: os dois tenants pagos ficaram 12h presos em `1.1-demo`
# sem conseguir ir para `1.2-auditoria`, com o ArgoCD dizendo "Synced" e o
# pod novo recusado pela cota a cada ~17min.
#
# 4352Mi = 2944 de repouso + 768 da troca + 640 de sobra.
#
# So `limits.memory` travava. Medido em 2026-09-25: requests.memory tinha
# 560Mi livres (a troca pede 400), requests.cpu 1100m (pede 100), limits.cpu
# 1300m (pede 1000) e pods 5 de 10. Subir a memoria basta.
limits.memory: 4352Mi
pods: "10"
---
# =============================================================================
# A politica de rede.
#
# ── O QUE MUDOU EM RELACAO AO MOLDE ANTIGO ──────────────────────────────────
#
# O `deny-cross-tenant` antigo liberava egress para `ipBlock: 10.43.0.0/16` — a
# CIDR de Services do cluster INTEIRO. Era mais largo do que o nome dizia: um pod
# de qualquer tenant alcancava, pela rede, o ClusterIP de qualquer outro.
#
# Aqui o egress interno e nominal: DNS, os pods do proprio namespace, e o
# namespace `plataforma-prod` nas portas que importam.
#
# ── O QUE NAO FOI POSSIVEL, E O MOTIVO E O CNI ──────────────────────────────
#
# O card pede "egress so ... os destinos externos reais (Asaas, provedor fiscal,
# Garmin) — nada de egress irrestrito".
#
# **Nao da com o CNI deste cluster.** Conferido em 2026-09-19: k3s com flannel
# embutido, sem Cilium e sem Calico (nenhum CRD dos dois). NetworkPolicy padrao
# do Kubernetes so aceita `ipBlock` — CIDR, nao nome. E Asaas, provedor fiscal e
# Garmin sao SaaS atras de CDN: os IPs mudam, e uma lista de CIDR quebraria a
# cobranca sem aviso, num dia qualquer.
#
# Entao a regra de 443 continua, e continua sendo egress irrestrito para a
# internet. O `except` preserva o que a politica de fato protege: um tenant nao
# alcanca a rede interna do outro.
#
# **O caminho para fechar isso de verdade** esta no diario: um proxy de saida no
# `plataforma-prod`, com lista de hosts permitidos, e os tenants alcancando so
# ele. Funciona com flannel, e nao exige trocar o CNI.
# =============================================================================
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-cross-tenant
namespace: teste5-prod
spec:
podSelector: {}
policyTypes: [Ingress, Egress]
ingress:
- from:
- podSelector: {} # mesma namespace
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system # Traefik (ingress)
egress:
# 1. Dentro do proprio namespace.
- to:
- podSelector: {}
# 2. DNS.
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- { protocol: UDP, port: 53 }
- { protocol: TCP, port: 53 }
# 3. A plataforma: banco e identidade, so nas portas que importam.
#
# 5432 direto no Postgres e para o `pg_dump` do backup: ele abre uma
# transacao unica e longa, o oposto do que transaction pooling serve.
# 6432 e o PgBouncer, por onde os runtimes falam.
# 8080 e o Keycloak (P4.8).
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: plataforma-prod
ports:
- { protocol: TCP, port: 5432 }
- { protocol: TCP, port: 6432 }
- { protocol: TCP, port: 8080 }
# 4. HTTPS para a internet publica. Ver o cabecalho: nao da para estreitar
# com flannel, e uma lista de CIDR de SaaS quebraria a cobranca sem aviso.
#
# O `except` e o que a politica de fato garante: nenhum tenant alcanca a
# rede interna de outro por este caminho.
- to:
- ipBlock:
cidr: 0.0.0.0/0
except: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]
ports:
- { protocol: TCP, port: 443 }