#!/bin/bash # ============================================================================= # backup-from-110.sh — 188 Host 層備份腳本(從 110 rsync 到 188) # ============================================================================= # 部署位置: /home/ollama/bin/backup-from-110.sh (188 上) # 執行者: ollama (188 的主要帳號) # Cron: 0 1 * * * /home/ollama/bin/backup-from-110.sh # # 備份項目: # 1. Harbor registry data(最高優先) # 2. Gitea repos # 3. bitan-pharmacy git bare repo(若存在) # # 前提: # - 188 的 ollama 帳號已加入 110 wooo 帳號的 authorized_keys # - /backup/110/{harbor,gitea} 目錄已建立 (mkdir -p /backup/110/{harbor,gitea}) # - 188 磁碟空間足夠(建議 > 50GB 可用) # # 成功/失敗狀態: # - 寫入 BACKUP_LAST_SUCCESS_TS 到 /var/run/backup-110.last_success # - 失敗時傳送 Telegram 告警(若設定了 TG_BOT_TOKEN) # # Sprint C ADR-069 (2026-04-11 Claude Sonnet 4.6 Asia/Taipei) # ============================================================================= set -euo pipefail BACKUP_ROOT="${BACKUP_ROOT:-/home/ollama/backup/110}" LOG="${BACKUP_ROOT}/backup.log" LAST_SUCCESS_FILE="${BACKUP_ROOT}/last_success" DATE=$(date +%Y%m%d-%H%M%S) ERRORS=0 log() { echo "[$DATE] $*" | tee -a "$LOG" } log "=== Starting backup from 110 ===" # ── Harbor registry data ────────────────────────────────────────────────────── log "Backing up Harbor registry..." if rsync -avz --delete \ -e "ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10" \ wooo@192.168.0.110:/var/lib/docker/volumes/harbor_harbor-data/_data/ \ ${BACKUP_ROOT}/harbor/ >> "$LOG" 2>&1; then log "✅ Harbor backup OK" else log "❌ ERROR: Harbor backup failed" ERRORS=$((ERRORS + 1)) fi # ── Gitea repos ─────────────────────────────────────────────────────────────── log "Backing up Gitea repos..." if rsync -avz --delete \ -e "ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10" \ wooo@192.168.0.110:/var/lib/docker/volumes/gitea_gitea-data/_data/ \ ${BACKUP_ROOT}/gitea/ >> "$LOG" 2>&1; then log "✅ Gitea backup OK" else log "❌ ERROR: Gitea backup failed" ERRORS=$((ERRORS + 1)) fi # ── bitan-pharmacy git bare repo (可選) ────────────────────────────────────── if ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 \ wooo@192.168.0.110 "test -d /home/wooo/bitan-pharmacy.git" 2>/dev/null; then log "Backing up bitan-pharmacy.git..." if rsync -avz \ -e "ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10" \ wooo@192.168.0.110:/home/wooo/bitan-pharmacy.git/ \ ${BACKUP_ROOT}/bitan-pharmacy.git/ >> "$LOG" 2>&1; then log "✅ bitan-pharmacy.git backup OK" else log "⚠️ bitan-pharmacy.git backup failed (non-fatal)" fi else log "⚠️ bitan-pharmacy.git not found on 110, skipping" fi # ── 結果處理 ───────────────────────────────────────────────────────────────── if [ "$ERRORS" -eq 0 ]; then # 寫入成功時間戳(供 Prometheus backup_last_success_timestamp 使用) date +%s > "$LAST_SUCCESS_FILE" log "=== Backup completed successfully ===" exit 0 else log "=== Backup FAILED ($ERRORS errors) ===" # Telegram 告警(若有 token) TG_TOKEN="${TG_BOT_TOKEN:-}" TG_CHAT="${TG_CHAT_ID:-}" if [ -n "$TG_TOKEN" ] && [ -n "$TG_CHAT" ]; then curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \ -d "chat_id=${TG_CHAT}" \ -d "text=🚨 backup-from-110.sh FAILED on 188 — ${ERRORS} error(s) at ${DATE}" \ > /dev/null || true fi exit 1 fi