Files
awoooi/scripts/ops/pg-backup.sh
OG T ec4ebaf310 fix(ops): pg-backup momo_analytics 改用 docker exec (無對外 port)
momo-db 容器無 port binding,TCP 127.0.0.1:5432 連到 host PG 非容器。
改用 docker exec momo-db pg_dump,實際備份 91M。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 09:57:05 +08:00

122 lines
3.9 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# scripts/ops/pg-backup.sh
# Sprint 5.2: PostgreSQL 自動備份腳本
# 部署: cron 0 */6 * * * on 188 (ollama user)
# 備份目標: awoooi_prod + momo_analytics
# 保留策略: 7 天
# 2026-04-09 Claude Sonnet 4.6 Asia/Taipei
set -euo pipefail
BACKUP_DIR="${BACKUP_DIR:-/home/ollama/backups}"
SECRETS_FILE="${SECRETS_FILE:-/home/ollama/awoooi-ops-secrets/secrets.env}"
RETAIN_DAYS="${RETAIN_DAYS:-7}"
AWOOOI_API_URL="${AWOOOI_API_URL:-https://awoooi.wooo.work}"
# 載入 secrets含 Telegram token for fallback
[[ -f "$SECRETS_FILE" ]] && source "$SECRETS_FILE"
TIMESTAMP=$(date '+%Y%m%d_%H%M%S')
LOG_PREFIX="[$(date '+%Y-%m-%d %H:%M:%S %z')]"
log() { echo "${LOG_PREFIX} $*"; }
notify_telegram() {
local msg="$1"
if [[ -n "${TELEGRAM_BOT_TOKEN:-}" && -n "${TELEGRAM_CHAT_ID:-}" ]]; then
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-H "Content-Type: application/json" \
-d "{\"chat_id\":\"${TELEGRAM_CHAT_ID}\",\"text\":\"${msg}\",\"parse_mode\":\"HTML\"}" \
> /dev/null 2>&1 || true
fi
}
backup_db() {
local label="$1" # awoooi_prod | momo_analytics
local host="$2" # 127.0.0.1
local user="$3"
local password="$4"
local dbname="$5"
local outfile="${BACKUP_DIR}/${label}_${TIMESTAMP}.sql.gz"
log "開始備份 ${label}${outfile}"
if PGPASSWORD="$password" pg_dump \
-h "$host" -U "$user" -d "$dbname" \
--no-owner --no-acl \
2>/dev/null | gzip > "$outfile"; then
local size
size=$(du -sh "$outfile" | cut -f1)
log "${label} 備份完成 (${size})"
echo "success:${label}:${size}"
else
log "${label} 備份失敗"
echo "failed:${label}"
fi
}
cleanup_old_backups() {
local label="$1"
local count
count=$(find "$BACKUP_DIR" -name "${label}_*.sql.gz" -mtime "+${RETAIN_DAYS}" | wc -l)
if (( count > 0 )); then
find "$BACKUP_DIR" -name "${label}_*.sql.gz" -mtime "+${RETAIN_DAYS}" -delete
log "🗑️ 清理 ${label} 舊備份 ${count} 個 (>${RETAIN_DAYS}天)"
fi
}
main() {
mkdir -p "$BACKUP_DIR"
log "=== pg-backup 開始 (retain=${RETAIN_DAYS}d) ==="
local results=()
# awoooi_prod (host PostgreSQL, TCP)
results+=("$(backup_db "awoooi_prod" "127.0.0.1" "awoooi" "awoooi_prod_2026" "awoooi_prod")")
# momo_analytics (momo-db 容器,無對外 port用 docker exec 直接 dump)
local outfile_momo="${BACKUP_DIR}/momo_analytics_${TIMESTAMP}.sql.gz"
log "開始備份 momo_analytics (docker exec) → ${outfile_momo}"
if docker exec momo-db pg_dump -U momo momo_analytics 2>/dev/null | gzip > "$outfile_momo"; then
local size_momo
size_momo=$(du -sh "$outfile_momo" | cut -f1)
log "✅ momo_analytics 備份完成 (${size_momo})"
results+=("success:momo_analytics:${size_momo}")
else
log "❌ momo_analytics 備份失敗"
rm -f "$outfile_momo"
results+=("failed:momo_analytics")
fi
# 清理舊備份
cleanup_old_backups "awoooi_prod"
cleanup_old_backups "momo_analytics"
log "=== pg-backup 完成 ==="
# 組裝 Telegram 通知
local success_count=0 fail_count=0 details=""
for r in "${results[@]}"; do
IFS=':' read -r status label size_or_empty <<< "$r"
case "$status" in
success) ((success_count++)) || true; details+="${label} (${size_or_empty})\n" ;;
failed) ((fail_count++)) || true; details+="${label} 失敗\n" ;;
skipped) details+="⏭️ ${label} 跳過\n" ;;
esac
done
local icon="✅"
[[ $fail_count -gt 0 ]] && icon="⚠️"
notify_telegram "${icon} <b>AWOOOI DB 備份</b>
├ 時間: $(date '+%Y-%m-%d %H:%M') +0800
├ 成功: ${success_count} | 失敗: ${fail_count}
${details}"
[[ $fail_count -gt 0 ]] && exit 1
return 0
}
main "$@"