首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

Linux 自動備份 MySQL 到 Gmail:Shell 腳本 + Crontab + Mutt 完整實施指南

     編輯:MySQL 資料庫相關知識

架構設計與工具鏈

MySQL → mysqldump → 壓縮加密 → Mutt (SMTP) → Gmail (附件) → 保留 30 天標籤自動歸檔
   ↑                    ↑
Crontab 02:00 每日      GPG 對稱加密 (AES256) 保護敏感資料

前置需求安裝 (CentOS/RHEL/Ubuntu/Debian)

# RHEL/CentOS/Rocky/Alma
dnf install -y mysql mysql-server mutt gnupg2 zstd cronie

# Ubuntu/Debian
apt update && apt install -y mysql-client mutt gnupg zstd cron

# 通用:啟用並啟動 cron
systemctl enable --now crond  # 或 cron

Gmail 應用程式密碼配置 (必要步驟)

  1. 開啟 Google 帳號 **兩步驟驗證** (2FA)
  2. 安全性 → 應用程式密碼 → 選擇「郵件」+「其他(自訂名稱)」→ 命名為「MySQL Backup」
  3. 複製生成的 **16 位字元密碼** (如 abcd efgh ijkl mnop,去除空格)

Mutt 配置檔 (~/.muttrc 或 /etc/Muttrc)

set from = "mysql-backup@example.com"
set realname = "MySQL Automated Backup"
set smtp_url = "smtps://mysql-backup@example.com:abcdEFGHijklMNOP@smtp.gmail.com:465/"
set smtp_authenticators = "login"
set ssl_starttls = yes
set ssl_force_tls = yes
set certificate_file = "/etc/ssl/certs/ca-bundle.crt"  # 系統 CA 憑證
set charset = "utf-8"
set send_charset = "utf-8"
set content_type = "text/plain"
set editor = "vim"
# GPG 加密預設收件者 (可被命令列覆蓋)
set pgp_default_key = ""
set crypt_autosign = no
set crypt_autoencrypt = no
set crypt_replyencrypt = no
set crypt_replysign = no
set crypt_verify_sig = yes

備份腳本 (/usr/local/bin/mysql_auto_backup.sh)

#!/bin/bash
# ==========================================
# MySQL 自動備份腳本 v2.1
# 功能:多庫備份 → 壓縮 → GPG 加密 → 郵件發送 → 本地保留
# 依賴:mysqldump, zstd, gpg, mutt, mailx (備用)
# ==========================================

set -euo pipefail

# ----- 配置區 (建議改為讀取 /etc/mysql/backup.conf) -----
DB_USER="backup_user"
DB_PASS="Str0ngP@ssw0rd!"  # 生產環境請用 ~/.my.cnf 或密碼管理器
DB_HOST="127.0.0.1"
DB_PORT="3306"
DATABASES=("app_prod" "app_logs" "app_users")  # 空陣列 = --all-databases
BACKUP_DIR="/backup/mysql/daily"
RETENTION_DAYS=7
GPG_RECIPIENT="dba-team@example.com"  # GPG 公鑰對應的郵箱/Key ID
MAIL_TO="dba-team@example.com,oncall@example.com"
MAIL_SUBJECT="[MySQL Backup] $(hostname) - $(date +%F) - ${#DATABASES[@]} databases"
MAIL_BODY="附件為 $(date +%F) MySQL 每日備份,共 ${#DATABASES[@]} 個資料庫。
請定期驗證還原可用性。
-- 
自動備份系統 $(hostname)"

# ----- 內部變數 -----
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
HOSTNAME=$(hostname)
DUMP_FILE="${BACKUP_DIR}/mysql_${HOSTNAME}_${TIMESTAMP}.sql"
COMPRESSED_FILE="${DUMP_FILE}.zst"
ENCRYPTED_FILE="${COMPRESSED_FILE}.gpg"
LOG_FILE="${BACKUP_DIR}/backup_${TIMESTAMP}.log"

# ----- 函數定義 -----
log() { echo "[$(date +'%F %T')] $*" | tee -a "$LOG_FILE"; }
die() { log "ERROR: $*"; exit 1; }

# ----- 主流程 -----
mkdir -p "$BACKUP_DIR"
log "=== 開始備份 $HOSTNAME ==="

# 1. 執行 mysqldump
log "導出資料庫: ${DATABASES[*]:-ALL}"
if [ ${#DATABASES[@]} -eq 0 ]; then
    mysqldump --defaults-extra-file=<(echo -e "[client]\nuser=$DB_USER\npassword=$DB_PASS\nhost=$DB_HOST\nport=$DB_PORT") \
        --single-transaction --routines --triggers --events --hex-blob --quick \
        --all-databases > "$DUMP_FILE" 2>>"$LOG_FILE" || die "mysqldump 失敗"
else
    mysqldump --defaults-extra-file=<(echo -e "[client]\nuser=$DB_USER\npassword=$DB_PASS\nhost=$DB_HOST\nport=$DB_PORT") \
        --single-transaction --routines --triggers --events --hex-blob --quick \
        --databases "${DATABASES[@]}" > "$DUMP_FILE" 2>>"$LOG_FILE" || die "mysqldump 失敗"
fi

# 2. 壓縮 (zstd 極速高壓縮比)
log "壓縮中..."
zstd -T0 -19 -q "$DUMP_FILE" -o "$COMPRESSED_FILE" || die "壓縮失敗"
rm -f "$DUMP_FILE"
DUMP_SIZE=$(du -h "$COMPRESSED_FILE" | cut -f1)
log "壓縮完成: $DUMP_SIZE"

# 3. GPG 對稱加密 (AES256,無需公鑰分發,適合自動化)
log "加密中..."
gpg --batch --yes --cipher-algo AES256 --compress-algo 2 --symmetric \
    --passphrase "$GPG_PASSPHRASE" \
    --output "$ENCRYPTED_FILE" "$COMPRESSED_FILE" || die "加密失敗"
rm -f "$COMPRESSED_FILE"
ENC_SIZE=$(du -h "$ENCRYPTED_FILE" | cut -f1)
log "加密完成: $ENC_SIZE"

# 4. 發送郵件 (Mutt)
log "發送郵件至 $MAIL_TO..."
echo "$MAIL_BODY" | mutt -s "$MAIL_SUBJECT" -a "$ENCRYPTED_FILE" -- "$MAIL_TO" 2>>"$LOG_FILE" || {
    log "Mutt 發送失敗,嘗試 mailx 備用..."
    echo "$MAIL_BODY" | mailx -s "$MAIL_SUBJECT" -a "$ENCRYPTED_FILE" -r "mysql-backup@example.com" "$MAIL_TO" 2>>"$LOG_FILE" || die "郵件發送完全失敗"
}
log "郵件發送成功"

# 5. 本地保留 (最近 N 天)
log "清理 $RETENTION_DAYS 天前本地備份..."
find "$BACKUP_DIR" -name "mysql_${HOSTNAME}_*.gpg" -mtime +$RETENTION_DAYS -delete
find "$BACKUP_DIR" -name "backup_*.log" -mtime +$RETENTION_DAYS -delete

log "=== 備份完成 ==="
exit 0

GPG 密鑰管理與密碼儲存

方案一:對稱加密 (簡單、無需金鑰分發)

# 腳本中使用環境變數傳遞密碼 (系統服務/環境變數注入)
export GPG_PASSPHRASE="SuperLongRandomPassphrase123!@#"
# 或讀取檔案 (權限 600)
GPG_PASSPHRASE=$(cat /etc/mysql/gpg_passphrase.txt)

方案二:非對稱加密 (團隊協作、輪換金鑰)

# 1. 產生金鑰對 (離線安全機器)
gpg --full-generate-key
# 選擇 RSA 4096, 不設過期, 用戶名 "MySQL Backup", 郵箱 "backup@example.com"

# 2. 匯出公鑰分發至備份伺服器
gpg --armor --export "MySQL Backup" > mysql_backup_pubkey.asc
# 備份伺服器匯入
gpg --import mysql_backup_pubkey.asc
gpg --list-keys  # 確認 Key ID

# 3. 腳本修改為非對稱加密
gpg --batch --yes --trust-model always --encrypt \
    --recipient "MySQL Backup" \
    --output "$ENCRYPTED_FILE" "$COMPRESSED_FILE"

# 4. 解密 (DBA 機器需有私鑰)
gpg --decrypt --output backup.sql.zst backup.sql.zst.gpg

Crontab 部署與日誌輪轉

# 編輯 root crontab
crontab -e

# 每日 02:00 執行 (避開業務高峰)
0 2 * * * /usr/local/bin/mysql_auto_backup.sh >> /var/log/mysql_backup_cron.log 2>&1

# 每週日 03:00 執行完整還原演練 (測試環境)
0 3 * * 0 /usr/local/bin/mysql_restore_drill.sh >> /var/log/mysql_restore_drill.log 2>&1

Logrotate 配置 (/etc/logrotate.d/mysql_backup)

/var/log/mysql_backup_cron.log
/var/log/mysql_restore_drill.log
/backup/mysql/daily/backup_*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 640 root root
    sharedscripts
    postrotate
        systemctl reload crond > /dev/null 2>&1 || true
    endscript
}

進階:大附件分割與 Google Drive 備援

Gmail 單附件限制 25MB,超過需分割或改用雲端硬碟:

# 分割加密檔案 (每片 20MB)
split -b 20M -d "$ENCRYPTED_FILE" "${ENCRYPTED_FILE}.part."

# 發送多封郵件 (Mutt 不直接支援多附件分割,需腳本迴圈)
for part in "${ENCRYPTED_FILE}.part."*; do
    echo "$MAIL_BODY (Part $(basename $part))" | mutt -s "$MAIL_SUBJECT (Part $(basename $part))" -a "$part" -- "$MAIL_TO"
    sleep 5  # 避免觸發 Gmail 發送頻率限制
done

# 或使用 rclone 上傳至 Google Drive (無大小限制、版本控制、共用連結)
rclone copy "$ENCRYPTED_FILE" gdrive:mysql_backups/$(hostname)/ --progress

驗證清單 (部署後必做)

  1. bash -n /usr/local/bin/mysql_auto_backup.sh 語法檢查
  2. /usr/local/bin/mysql_auto_backup.sh 手動執行一次,觀察完整流程
  3. 收件箱確認收到郵件、附件可下載、GPG 解密成功、SQL 可匯入測試庫
  4. 檢查 /var/log/mysql_backup_cron.log 無錯誤
  5. 模擬刪除本地備份,確認郵件附件為唯一存活副本
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved