Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions script/database-backup/.env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
DATABASE_HOST=10.0.10.80
DATABASE_HOST=127.0.0.1
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=masterkey
DATABASE_NAME=herbario_prod
DATABASE_NAME=herbario_dev

# Google Drive (Dados reais que você gerou)
GDRIVE_TOKEN={"access_token":"SEU_ACCESS_TOKEN_AQUI","token_type":"Bearer","refresh_token":"SEU_REFRESH_TOKEN_AQUI","expiry":"2026-01-01T00:00:00Z"}
Expand All @@ -14,3 +14,15 @@ RETENTION_DAILY=5
RETENTION_WEEKLY=4
CRON_SCHEDULE="0 2 * * *"
TZ=America/Sao_Paulo

# SMTP (notificação de falha do backup)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER="seu-email@gmail.com"
SMTP_PASS="sua-senha-de-app-de-16-digitos"
SMTP_FROM="Sistema HCF <no-reply@hcf.com>"

# Destinatários do alerta (1 ou mais, separados por vírgula)
NOTIFY_EMAIL_TO=ops@exemplo.com,curadoria@exemplo.com
# Desliga notificação sem remover config (default: true)
NOTIFY_EMAIL_ENABLED=true
4 changes: 2 additions & 2 deletions script/database-backup/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ RUN \
curl \
ca-certificates \
rclone \
gzip && \
gzip \
msmtp && \
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgresql.gpg && \
echo "deb [signed-by=/usr/share/keyrings/postgresql.gpg] https://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
apt-get update && \
apt-get install -y \
postgresql-client-18 && \
apt-get remove -y \
curl \
ca-certificates \
gnupg && \
rm -rf /var/lib/apt/lists/*

Expand Down
19 changes: 18 additions & 1 deletion script/database-backup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Arquitetura:

Fluxo:

`cron -> backup.sh -> pg_dump -Fp -> gzip -> rclone copy -> retenção`
`cron -> backup.sh -> pg_dump -Fp -> gzip -> rclone copy -> retenção (-> notificação por e-mail em caso de falha)`

## Formato do backup

Expand All @@ -37,6 +37,23 @@ Veja `.env.example` para o contrato completo.
- `RETENTION_WEEKLY` (default: `4`)
- `CRON_SCHEDULE` (ex.: `0 2 * * *`)
- `TZ` (ex.: `America/Sao_Paulo`)
- `SMTP_HOST`
- `SMTP_PORT`
- `SMTP_USER`
- `SMTP_PASS`
- `SMTP_FROM`
- `NOTIFY_EMAIL_TO` (1 ou mais e-mails separados por vírgula)
- `NOTIFY_EMAIL_ENABLED` (default: `true`)

## Notificação de falha

O container instala e configura o cliente `msmtp` (via `/etc/msmtprc`, gerado no `entrypoint.sh` a partir das variáveis `SMTP_*`).

- O `backup.sh` captura toda a sua saída em um log temporário e usa um `trap ERR` para detectar qualquer falha (`pg_dump`, `rclone`, retenção, etc.).
- Em caso de falha, um e-mail é enviado via `msmtp` para todos os endereços listados em `NOTIFY_EMAIL_TO` (separados por vírgula), com assunto, horário (`TZ`) e as últimas linhas do log.
- Em caso de sucesso, nenhum e-mail é enviado.
- `NOTIFY_EMAIL_ENABLED=false` desliga a notificação sem precisar remover as demais variáveis.
- Se o próprio envio do e-mail falhar (SMTP fora do ar, credenciais inválidas etc.), isso é apenas logado — o script continua terminando com o código de saída original da falha do backup (a notificação nunca mascara o erro real).

## Política de retenção

Expand Down
49 changes: 49 additions & 0 deletions script/database-backup/backup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,55 @@

set -euo pipefail

LOG_FILE=$(mktemp)
exec > >(tee -a "${LOG_FILE}") 2>&1

notify_failure() {
local exit_code=$1
local line_no=$2

if [ "${NOTIFY_EMAIL_ENABLED:-true}" != "true" ]; then
return 0
fi

if [ -z "${NOTIFY_EMAIL_TO:-}" ]; then
echo "NOTIFY_EMAIL_TO não configurado, pulando notificação por e-mail" >&2
return 0
fi

IFS=',' read -ra RAW_RECIPIENTS <<< "${NOTIFY_EMAIL_TO}"
local recipients=()
for r in "${RAW_RECIPIENTS[@]}"; do
r="$(echo -n "$r" | xargs)"
[ -n "$r" ] && recipients+=("$r")
done

if [ "${#recipients[@]}" -eq 0 ]; then
echo "Nenhum destinatário válido em NOTIFY_EMAIL_TO" >&2
return 0
fi

local subject="[FALHA] Backup do banco ${DATABASE_NAME} - $(date '+%Y-%m-%d %H:%M:%S') (${TZ:-UTC})"

{
echo "Subject: ${subject}"
echo "From: ${SMTP_FROM}"
echo "To: $(IFS=,; echo "${recipients[*]}")"
echo "Content-Type: text/plain; charset=UTF-8"
echo
echo "Falha no backup do banco: ${DATABASE_NAME}"
echo "Horário da tentativa: $(date '+%Y-%m-%d %H:%M:%S') (${TZ:-UTC})"
echo "Código de saída: ${exit_code} (linha ${line_no})"
echo
echo "Últimas linhas do log:"
tail -n 50 "${LOG_FILE}" 2>/dev/null || echo "(log indisponível)"
} | msmtp "${recipients[@]}" || echo "Falha ao enviar e-mail de notificação via msmtp" >&2

return 0
}

trap 'notify_failure $? $LINENO' ERR

TIMESTAMP=$(date +%s)
FILE_NAME="${DATABASE_NAME}_${TIMESTAMP}.sql.gz"
TMP_FILE="/tmp/${FILE_NAME}"
Expand Down
11 changes: 11 additions & 0 deletions script/database-backup/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ services:
image: database-backup:local
container_name: database-backup
build: .
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
# PostgreSQL
DATABASE_HOST: "${DATABASE_HOST}"
Expand All @@ -20,3 +22,12 @@ services:

CRON_SCHEDULE: "${CRON_SCHEDULE}"
TZ: "${TZ}"

# SMTP / Notificações
SMTP_HOST: "${SMTP_HOST}"
SMTP_PORT: "${SMTP_PORT}"
SMTP_USER: "${SMTP_USER}"
SMTP_PASS: "${SMTP_PASS}"
SMTP_FROM: "${SMTP_FROM}"
NOTIFY_EMAIL_TO: "${NOTIFY_EMAIL_TO}"
NOTIFY_EMAIL_ENABLED: "${NOTIFY_EMAIL_ENABLED}"
19 changes: 18 additions & 1 deletion script/database-backup/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,26 @@ token = ${GDRIVE_TOKEN}
root_folder_id = ${GDRIVE_FOLDER_ID}
EOF

echo "Configurando msmtp..."
cat <<EOF > /etc/msmtprc
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile /var/log/msmtp.log

account default
host ${SMTP_HOST}
port ${SMTP_PORT}
from ${SMTP_USER}
user ${SMTP_USER}
password ${SMTP_PASS}
EOF
chmod 600 /etc/msmtprc

echo "Configuring cron job with schedule: $CRON_SCHEDULE ($TZ)"

printenv | grep -E "^(DATABASE_|GDRIVE_|RETENTION_|CRON_SCHEDULE|TZ)" >> /etc/environment
printenv | grep -E "^(DATABASE_|GDRIVE_|RETENTION_|CRON_SCHEDULE|TZ|SMTP_|NOTIFY_)" >> /etc/environment

echo "$CRON_SCHEDULE /backup.sh 1> /proc/1/fd/1 2> /proc/1/fd/2" | crontab -

Expand Down
Loading