Files
athletic-map-deploy/tenants/plataforma/50-backup.yaml
T
Athletic Map Deploy ea7da4364a feat(plataforma): tenant proprio da Athletic Map
Namespace, banco, Keycloak e realm proprios, separados dos clientes e do tenant
de demonstracao. Leva 4 contextos (configuracao, cadastro, financeiro, captacao)
mais bff e SPA, e nao os 13 de um cliente: a Athletic Map nao e escolinha.

Ingress escrito do zero, sem o stub backend legado e sem catch-all /api. Duas
rotas publicas, ambas por desenho: /api/public/leads (o formulario da landing
page) e /api/public/webhooks/asaas (o aviso de pagamento, que chega da internet
sem token nosso).

Dominio em *.athleticmap.influxdigital.com.br, e nao no canonico athleticmap.com
do P0.9: aquele ainda nao tem registro A, e com desafio HTTP-01 nascer nele
daria certificado nao emitido e login quebrado.

Tres SealedSecret gerados para ESTE namespace, e a chave publica do backup no
lugar do placeholder. As 7 imagens locais exigidas estao no no, incluindo
servico-captacao:1.0 e atm-pg-backup:1.0, construidas hoje.

Preparado em P3.1 a P3.4. Validado com kubectl --dry-run: 32 documentos.
2026-09-17 17:58:21 +00:00

84 lines
3.3 KiB
YAML

# Backup diario do Postgres do tenant `plataforma` (pg_dump cifrado com age, ver P2.4)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pg-backups
namespace: plataforma-prod
spec:
accessModes: [ReadWriteOnce]
storageClassName: local-path
resources:
requests:
storage: 5Gi
---
# ConfigMap com o DESTINATARIO age (chave PUBLICA).
#
# Publica pode ser versionada: ela so cifra. Quem tem a publica NAO abre o
# backup. A privada e gerada por scripts/backup/gerar_chave_backup.sh na maquina
# de quem restaura, e NUNCA chega neste repositorio nem no VPS.
#
# O valor abaixo e um marcador: substitua pelo destinatario real antes de
# aplicar. Com o marcador, o backup_tenant.sh recusa rodar em vez de gravar em
# claro — e o comportamento certo.
apiVersion: v1
kind: ConfigMap
metadata:
name: pg-backup-chave
namespace: plataforma-prod
data:
# Chave PUBLICA do age. Versionar isto e seguro e proposital: ela so serve
# para CIFRAR. Abrir um backup exige a privada, que por desenho nao esta
# neste repositorio nem no servidor — se estivesse no VPS, quem invadisse a
# maquina levaria a chave junto com o arquivo cifrado, e o backup cifrado
# nao teria servido para nada.
#
# Gerada em 2026-09-17 por `scripts/backup/gerar_chave_backup.sh`, na maquina
# do operador. ANOTE A DATA: rotacionar exige manter a chave antiga enquanto
# houver backup cifrado com ela dentro da retencao de 7 dias.
destinatario: "age1g37gc3gvq0zn7802pqh5dd0m3pkvc4z3g2hqk5w3dgvnaz3hwsrq7ps04y"
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: pg-backup
namespace: plataforma-prod
spec:
schedule: "0 2 * * *" # diariamente 02:00
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
# Imagem propria: postgres:16 + age. O dump precisa ser cifrado
# ANTES de sair do processo, entao as duas ferramentas tem de estar
# no mesmo container. Construida de scripts/backup/Containerfile.
- name: pg-backup
image: docker.io/library/atm-pg-backup:1.0
env:
- name: PGPASSWORD
valueFrom:
secretKeyRef: { name: db-credentials, key: password }
- name: CHAVE_PUBLICA
valueFrom:
configMapKeyRef: { name: pg-backup-chave, key: destinatario }
- { name: PGHOST, value: "postgres" }
- { name: PGUSER, value: "atm" }
- { name: DATABASES, value: "athleticmap keycloak" }
- { name: DESTINO, value: "/backups" }
- { name: RETENCAO_DIAS, value: "7" }
# COMANDO_ENVIO fica vazio ate haver credencial de armazenamento
# externo. Sem ele o backup fica cifrado, mas NO MESMO SERVIDOR —
# e o proprio script avisa isso no fim da execucao.
- { name: COMANDO_ENVIO, value: "" }
command: ["backup_tenant.sh"]
volumeMounts:
- { name: backups, mountPath: /backups }
volumes:
- name: backups
persistentVolumeClaim:
claimName: pg-backups