feat(backup): envio para fora do servidor (atm-pg-backup:1.2 com rclone)
This commit is contained in:
+43
-20
@@ -11,13 +11,30 @@ spec:
|
||||
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: acme-prod
|
||||
data:
|
||||
destinatario: "SUBSTITUA_PELO_DESTINATARIO_age1"
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: pg-backup
|
||||
namespace: acme-prod
|
||||
spec:
|
||||
schedule: "0 2 * * *"
|
||||
schedule: "0 2 * * *" # diariamente 02:00
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 3
|
||||
concurrencyPolicy: Forbid
|
||||
@@ -27,30 +44,36 @@ spec:
|
||||
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: postgres:16
|
||||
image: docker.io/library/atm-pg-backup:1.0
|
||||
env:
|
||||
- name: PGPASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: db-credentials
|
||||
key: password
|
||||
command: ["/bin/sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
set -eo pipefail
|
||||
echo "aguardando postgres ficar acessivel..."
|
||||
for i in $(seq 1 30); do pg_isready -h postgres -U atm -t 3 >/dev/null 2>&1 && break; sleep 2; done
|
||||
TS=$(date +%Y%m%d-%H%M%S)
|
||||
for DB in athleticmap keycloak; do
|
||||
echo "dump $DB ..."
|
||||
pg_dump -h postgres -U atm -d "$DB" | gzip > "/backups/${DB}-${TS}.sql.gz"
|
||||
done
|
||||
find /backups -name '*.sql.gz' -mtime +7 -delete
|
||||
echo "backups atuais:"; ls -lh /backups | tail -20
|
||||
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" }
|
||||
# O envio para fora. O script se cala quando o Secret nao existe, e
|
||||
# falha ALTO quando existe e nao funciona — sao coisas diferentes,
|
||||
# e um CronJob que falha toda madrugada por falta de credencial
|
||||
# ensina todo mundo a ignorar o unico alerta que nao se pode ignorar.
|
||||
- { name: COMANDO_ENVIO, value: "enviar_offsite.sh {}" }
|
||||
# `optional: true`: enquanto o Secret `backup-offsite` nao existir, o
|
||||
# CronJob roda igual e guarda local. No dia em que ele existir, o
|
||||
# envio liga sozinho — sem tocar neste arquivo.
|
||||
envFrom:
|
||||
- secretRef: { name: backup-offsite, optional: true }
|
||||
command: ["backup_tenant.sh"]
|
||||
volumeMounts:
|
||||
- name: backups
|
||||
mountPath: /backups
|
||||
- { name: backups, mountPath: /backups }
|
||||
volumes:
|
||||
- name: backups
|
||||
persistentVolumeClaim:
|
||||
|
||||
+43
-20
@@ -11,13 +11,30 @@ spec:
|
||||
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: demo-prod
|
||||
data:
|
||||
destinatario: "SUBSTITUA_PELO_DESTINATARIO_age1"
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: pg-backup
|
||||
namespace: demo-prod
|
||||
spec:
|
||||
schedule: "0 2 * * *"
|
||||
schedule: "0 2 * * *" # diariamente 02:00
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 3
|
||||
concurrencyPolicy: Forbid
|
||||
@@ -27,30 +44,36 @@ spec:
|
||||
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: postgres:16
|
||||
image: docker.io/library/atm-pg-backup:1.0
|
||||
env:
|
||||
- name: PGPASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: db-credentials
|
||||
key: password
|
||||
command: ["/bin/sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
set -eo pipefail
|
||||
echo "aguardando postgres ficar acessivel..."
|
||||
for i in $(seq 1 30); do pg_isready -h postgres -U atm -t 3 >/dev/null 2>&1 && break; sleep 2; done
|
||||
TS=$(date +%Y%m%d-%H%M%S)
|
||||
for DB in athleticmap keycloak; do
|
||||
echo "dump $DB ..."
|
||||
pg_dump -h postgres -U atm -d "$DB" | gzip > "/backups/${DB}-${TS}.sql.gz"
|
||||
done
|
||||
find /backups -name '*.sql.gz' -mtime +7 -delete
|
||||
echo "backups atuais:"; ls -lh /backups | tail -20
|
||||
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" }
|
||||
# O envio para fora. O script se cala quando o Secret nao existe, e
|
||||
# falha ALTO quando existe e nao funciona — sao coisas diferentes,
|
||||
# e um CronJob que falha toda madrugada por falta de credencial
|
||||
# ensina todo mundo a ignorar o unico alerta que nao se pode ignorar.
|
||||
- { name: COMANDO_ENVIO, value: "enviar_offsite.sh {}" }
|
||||
# `optional: true`: enquanto o Secret `backup-offsite` nao existir, o
|
||||
# CronJob roda igual e guarda local. No dia em que ele existir, o
|
||||
# envio liga sozinho — sem tocar neste arquivo.
|
||||
envFrom:
|
||||
- secretRef: { name: backup-offsite, optional: true }
|
||||
command: ["backup_tenant.sh"]
|
||||
volumeMounts:
|
||||
- name: backups
|
||||
mountPath: /backups
|
||||
- { name: backups, mountPath: /backups }
|
||||
volumes:
|
||||
- name: backups
|
||||
persistentVolumeClaim:
|
||||
|
||||
@@ -11,6 +11,23 @@ spec:
|
||||
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: piloto-prod
|
||||
data:
|
||||
destinatario: "SUBSTITUA_PELO_DESTINATARIO_age1"
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
@@ -27,30 +44,36 @@ spec:
|
||||
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: postgres:16
|
||||
image: docker.io/library/atm-pg-backup:1.0
|
||||
env:
|
||||
- name: PGPASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: db-credentials
|
||||
key: password
|
||||
command: ["/bin/sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
set -eo pipefail
|
||||
echo "aguardando postgres ficar acessivel..."
|
||||
for i in $(seq 1 30); do pg_isready -h postgres -U atm -t 3 >/dev/null 2>&1 && break; sleep 2; done
|
||||
TS=$(date +%Y%m%d-%H%M%S)
|
||||
for DB in athleticmap keycloak; do
|
||||
echo "dump $DB ..."
|
||||
pg_dump -h postgres -U atm -d "$DB" | gzip > "/backups/${DB}-${TS}.sql.gz"
|
||||
done
|
||||
find /backups -name '*.sql.gz' -mtime +7 -delete
|
||||
echo "backups atuais:"; ls -lh /backups | tail -20
|
||||
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" }
|
||||
# O envio para fora. O script se cala quando o Secret nao existe, e
|
||||
# falha ALTO quando existe e nao funciona — sao coisas diferentes,
|
||||
# e um CronJob que falha toda madrugada por falta de credencial
|
||||
# ensina todo mundo a ignorar o unico alerta que nao se pode ignorar.
|
||||
- { name: COMANDO_ENVIO, value: "enviar_offsite.sh {}" }
|
||||
# `optional: true`: enquanto o Secret `backup-offsite` nao existir, o
|
||||
# CronJob roda igual e guarda local. No dia em que ele existir, o
|
||||
# envio liga sozinho — sem tocar neste arquivo.
|
||||
envFrom:
|
||||
- secretRef: { name: backup-offsite, optional: true }
|
||||
command: ["backup_tenant.sh"]
|
||||
volumeMounts:
|
||||
- name: backups
|
||||
mountPath: /backups
|
||||
- { name: backups, mountPath: /backups }
|
||||
volumes:
|
||||
- name: backups
|
||||
persistentVolumeClaim:
|
||||
|
||||
@@ -65,15 +65,36 @@ spec:
|
||||
- name: CHAVE_PUBLICA
|
||||
valueFrom:
|
||||
configMapKeyRef: { name: pg-backup-chave, key: destinatario }
|
||||
# ── QUANDO ESTE TENANT MIGRAR PARA O BANCO COMPARTILHADO (P4.7)
|
||||
#
|
||||
# Estas tres linhas mudam JUNTO com a migracao, e nao antes:
|
||||
#
|
||||
# PGHOST postgres -> pg-compartilhado
|
||||
# PGUSER atm -> r_<tenant>
|
||||
# DATABASES athleticmap ... -> athleticmap_<tenant>
|
||||
#
|
||||
# O `keycloak` sai da lista se o Keycloak tambem for compartilhado
|
||||
# (P4.8, card 156) — ate la ele continua no banco do tenant.
|
||||
#
|
||||
# E `PGHOST` aponta para o POSTGRES, e nao para o PgBouncer: o
|
||||
# `pg_dump` abre uma transacao unica e longa, que e exatamente o
|
||||
# que transaction pooling nao serve. Pelo bouncer, um dump grande
|
||||
# seguraria uma conexao do pool pelo tempo inteiro do backup.
|
||||
- { 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: "" }
|
||||
# O envio para fora. O script se cala quando o Secret nao existe, e
|
||||
# falha ALTO quando existe e nao funciona — sao coisas diferentes,
|
||||
# e um CronJob que falha toda madrugada por falta de credencial
|
||||
# ensina todo mundo a ignorar o unico alerta que nao se pode ignorar.
|
||||
- { name: COMANDO_ENVIO, value: "enviar_offsite.sh {}" }
|
||||
# `optional: true`: enquanto o Secret `backup-offsite` nao existir, o
|
||||
# CronJob roda igual e guarda local. No dia em que ele existir, o
|
||||
# envio liga sozinho — sem tocar neste arquivo.
|
||||
envFrom:
|
||||
- secretRef: { name: backup-offsite, optional: true }
|
||||
command: ["backup_tenant.sh"]
|
||||
volumeMounts:
|
||||
- { name: backups, mountPath: /backups }
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#
|
||||
# ── ANTES DE APLICAR ─────────────────────────────────────────────────────────
|
||||
#
|
||||
# 1. A imagem `atm-pg-backup:1.1` tem o `backup_tenant.sh` com `auto:` e ainda
|
||||
# 1. A imagem `atm-pg-backup:1.2` tem o `backup_tenant.sh` com `auto:` e ainda
|
||||
# NAO FOI CONSTRUIDA. Construir de scripts/backup/Containerfile e importar no
|
||||
# k3s, como a 1.0. Com a 1.0, o CronJob falharia: ela nao entende `auto:`.
|
||||
# 2. Zero tenants no compartilhado faz o job terminar com ERRO, de proposito
|
||||
@@ -61,7 +61,7 @@ spec:
|
||||
restartPolicy: OnFailure
|
||||
containers:
|
||||
- name: pg-backup
|
||||
image: docker.io/library/atm-pg-backup:1.1
|
||||
image: docker.io/library/atm-pg-backup:1.2
|
||||
env:
|
||||
# O admin do compartilhado: e o unico papel que le TODOS os
|
||||
# databases. O `r_<tenant>` de cada cliente so ve o proprio.
|
||||
@@ -77,9 +77,16 @@ spec:
|
||||
- { name: DATABASES, value: "auto:athleticmap_" }
|
||||
- { name: DESTINO, value: "/backups" }
|
||||
- { name: RETENCAO_DIAS, value: "7" }
|
||||
# Vazio pelo mesmo motivo do 50-backup: falta credencial de
|
||||
# armazenamento externo. O script avisa no fim de cada rodada.
|
||||
- { name: COMANDO_ENVIO, value: "" }
|
||||
# O envio para fora. O script se cala quando o Secret nao existe, e
|
||||
# falha ALTO quando existe e nao funciona — sao coisas diferentes,
|
||||
# e um CronJob que falha toda madrugada por falta de credencial
|
||||
# ensina todo mundo a ignorar o unico alerta que nao se pode ignorar.
|
||||
- { name: COMANDO_ENVIO, value: "enviar_offsite.sh {}" }
|
||||
# `optional: true`: enquanto o Secret `backup-offsite` nao existir, o
|
||||
# CronJob roda igual e guarda local. No dia em que ele existir, o
|
||||
# envio liga sozinho — sem tocar neste arquivo.
|
||||
envFrom:
|
||||
- secretRef: { name: backup-offsite, optional: true }
|
||||
command: ["backup_tenant.sh"]
|
||||
volumeMounts:
|
||||
- { name: backups, mountPath: /backups }
|
||||
|
||||
Reference in New Issue
Block a user