数据库备份攻略:支持Docker/本地部署

文章大纲

  1. Docker、本地部署的MySQL数据文件备份
  2. 支持命令行指定数据库(逗号分隔),未指定时自动备份所有非系统库
  3. 按时间分目录存储压缩备份,保存指定日期范围的备份信息
  4. Linux系统-定时执行备份

创建MySQL账号并授权

sql 复制代码
CREATE USER 'backup'@'localhost' IDENTIFIED BY '123456';

GRANT SELECT, SHOW VIEW, EVENT, LOCK TABLES, RELOAD, PROCESS ON *.* TO 'backup'@'localhost';
FLUSH PRIVILEGES;

【Docker】模式

touch docker_mysql_backup.sh

shell 复制代码
#!/bin/bash

# ---------------------------- 配置区 ----------------------------
BACKUP_ROOT="/data/mysql_backup"      # 备份根目录
MYSQL_CONTAINER="mysql"               # Docker容器名称
MYSQL_USER="backup"                   # MySQL备份账号
MYSQL_PASS="123456"     		  			  # 密码建议从密钥管理服务获取
RETENTION_DAYS=7                      # 备份保留天数
LOG_FILE="/var/log/mysql_backup.log"  # 日志文件路径
EXCLUDE_DBS="information_schema,performance_schema,mysql,sys" # 排除的系统库
# ----------------------------------------------------------------

# ---------------------------- 初始化 ----------------------------
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="${BACKUP_ROOT}/${TIMESTAMP}"
mkdir -p "$BACKUP_DIR"
touch "$LOG_FILE"

# 日志记录函数
log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

log "===== 备份开始 [${TIMESTAMP}] ====="

# ---------------------------- 参数处理 ----------------------------
if [ -n "$1" ]; then
  # 处理用户输入的数据库列表(兼容逗号/空格分隔)
  USER_DBS=$(echo "$1" | tr ',' ' ')
  log "已指定数据库: ${USER_DBS}"
  
  # 验证数据库是否存在
  ALL_DBS=$(docker exec "$MYSQL_CONTAINER" \
    sh -c "export MYSQL_PWD='${MYSQL_PASS}'; \
           mysql -u ${MYSQL_USER} -N -e 'SHOW DATABASES;'")
  
  DATABASES=""
  for DB in $USER_DBS; do
    if echo "$ALL_DBS" | grep -qw "$DB"; then
      DATABASES="$DATABASES $DB"
    else
      log "警告:数据库 ${DB} 不存在,已跳过"
    fi
  done
  
  if [ -z "$DATABASES" ]; then
    log "错误:没有有效的可备份数据库"
    exit 1
  fi
else
  # 获取所有非系统库
  log "未指定数据库,备份所有非系统库"
  DATABASES=$(docker exec "$MYSQL_CONTAINER" \
    sh -c "export MYSQL_PWD='${MYSQL_PASS}'; \
           mysql -u ${MYSQL_USER} -N -e 'SHOW DATABASES;'" | \
    grep -Ev "^(${EXCLUDE_DBS//,/|})$")
fi

# ---------------------------- 备份执行 ----------------------------
TOTAL_SIZE=0
for DB in $DATABASES; do
  BACKUP_FILE="${BACKUP_DIR}/${DB}.sql.gz"
  START_TIME=$(date +%s)
  
  log "备份启动: ${DB}"
  
  # 核心备份命令
  docker exec "$MYSQL_CONTAINER" \
    sh -c "export MYSQL_PWD='${MYSQL_PASS}'; \
           mysqldump -u ${MYSQL_USER} \
           --routines --triggers --events \
           --single-transaction \
           --hex-blob \
           ${DB}" | gzip > "$BACKUP_FILE"

  # 结果检查
  if [ $? -eq 0 ]; then
    FILE_SIZE=$(du -h "$BACKUP_FILE" | awk '{print $1}')
    TIME_TAKEN=$(( $(date +%s) - START_TIME ))
    TOTAL_SIZE=$(( TOTAL_SIZE + $(stat -c %s "$BACKUP_FILE") ))
    
    log "备份成功: ${DB} (大小: ${FILE_SIZE}, 耗时: ${TIME_TAKEN}秒)"
    
    # 验证压缩文件
    if ! gzip -t "$BACKUP_FILE" 2>/dev/null; then
      log "警告:压缩文件校验失败 ${BACKUP_FILE}"
    fi
  else
    log "错误:${DB} 备份失败"
    rm -f "$BACKUP_FILE"
  fi
done

# ---------------------------- 清理旧备份 ----------------------------
if [ -n "$(ls -A "$BACKUP_DIR")" ]; then
  log "正在清理超过 ${RETENTION_DAYS} 天的旧备份..."
  find "$BACKUP_ROOT" -mindepth 1 -maxdepth 1 -type d -mtime +"$RETENTION_DAYS" \
    -exec sh -c 'log "删除旧备份: {}"; rm -rf "{}"' \;
else
  log "警告:未生成有效备份,跳过清理"
  rm -rf "$BACKUP_DIR"
fi

# ---------------------------- 完成报告 ----------------------------
if [ -d "$BACKUP_DIR" ]; then
  HUMAN_SIZE=$(numfmt --to=iec $TOTAL_SIZE)
  log "备份完成: ${BACKUP_DIR} (总大小: ${HUMAN_SIZE})"
else
  log "错误:未生成任何有效备份"
fi

log "===== 备份结束 [${TIMESTAMP}] ====="
echo "" >> "$LOG_FILE"
exit 0

手动执行备份

  • 备份指定库:sh docker_mysql_backup.sh neo_dbv1,shop
  • 备份全部库:sh docker_mysql_backup.sh

【本地】模式

将账号密码以环境变量保存

shell 复制代码
sudo tee /etc/mysql/backup.cnf > /dev/null <<EOF
[client]
user = backup
password = 123456
EOF
sudo chmod 600 /etc/mysql/backup.cnf

touch mysql_backup.sh

shell 复制代码
#!/bin/bash

# ---------------------------- 配置区 ----------------------------
BACKUP_ROOT="/data/mysql_backup"      # 备份根目录
RETENTION_DAYS=30                     # 备份保留天数
LOG_FILE="/var/log/mysql_backup.log"  # 日志文件路径
CONFIG_FILE="/etc/mysql/backup.cnf"   # 必须存在的配置文件
EXCLUDE_DBS="information_schema,performance_schema,mysql,sys" # 排除的系统库
# ----------------------------------------------------------------

# ---------------------------- 初始化 ----------------------------
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="${BACKUP_ROOT}/${TIMESTAMP}"
mkdir -p "$BACKUP_DIR"
touch "$LOG_FILE"

# 日志记录函数
log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

log "===== 备份开始 [${TIMESTAMP}] ====="

# ---------------------------- 配置文件检查 ----------------------------
if [ ! -f "$CONFIG_FILE" ]; then
  log "错误:MySQL配置文件 $CONFIG_FILE 不存在"
  log "请创建包含以下内容的配置文件:"
  log "[client]"
  log "user = backup"
  log "password = your_password"
  exit 1
fi

if [ $(stat -c %a "$CONFIG_FILE") -ne 600 ]; then
  log "警告:配置文件权限不安全,正在设置为600"
  chmod 600 "$CONFIG_FILE"
fi

# ---------------------------- 参数处理 ----------------------------
if [ -n "$1" ]; then
  # 处理用户输入的数据库列表
  USER_DBS=$(echo "$1" | tr ',' ' ')
  log "已指定数据库: ${USER_DBS}"
  
  # 验证数据库是否存在
  ALL_DBS=$(mysql --defaults-file="$CONFIG_FILE" -N -e "SHOW DATABASES;")
  
  DATABASES=""
  for DB in $USER_DBS; do
    if echo "$ALL_DBS" | grep -qw "$DB"; then
      DATABASES="$DATABASES $DB"
    else
      log "警告:数据库 ${DB} 不存在,已跳过"
    fi
  done
  
  if [ -z "$DATABASES" ]; then
    log "错误:没有有效的可备份数据库"
    exit 1
  fi
else
  # 获取所有非系统库
  log "未指定数据库,备份所有非系统库"
  DATABASES=$(mysql --defaults-file="$CONFIG_FILE" -N -e "SHOW DATABASES;" | \
    grep -Ev "^(${EXCLUDE_DBS//,/|})$")
fi

# ---------------------------- 备份执行 ----------------------------
TOTAL_SIZE=0
for DB in $DATABASES; do
  BACKUP_FILE="${BACKUP_DIR}/${DB}.sql.gz"
  START_TIME=$(date +%s)
  
  log "备份启动: ${DB}"
  
  # 核心备份命令(使用配置文件认证)
  mysqldump --defaults-file="$CONFIG_FILE" \
    --routines --triggers --events \
    --single-transaction \
    --hex-blob \
    "$DB" | gzip > "$BACKUP_FILE"

  # 结果检查
  if [ $? -eq 0 ]; then
    FILE_SIZE=$(du -h "$BACKUP_FILE" | awk '{print $1}')
    TIME_TAKEN=$(( $(date +%s) - START_TIME ))
    TOTAL_SIZE=$(( TOTAL_SIZE + $(stat -c %s "$BACKUP_FILE") ))
    
    log "备份成功: ${DB} (大小: ${FILE_SIZE}, 耗时: ${TIME_TAKEN}秒)"
    
    # 验证压缩文件
    if ! gzip -t "$BACKUP_FILE" 2>/dev/null; then
      log "警告:压缩文件校验失败 ${BACKUP_FILE}"
    fi
  else
    log "错误:${DB} 备份失败"
    rm -f "$BACKUP_FILE"
  fi
done

# ---------------------------- 清理旧备份 ----------------------------
if [ -n "$(ls -A "$BACKUP_DIR")" ]; then
  log "正在清理超过 ${RETENTION_DAYS} 天的旧备份..."
  find "$BACKUP_ROOT" -mindepth 1 -maxdepth 1 -type d -mtime +"$RETENTION_DAYS" \
    -exec sh -c 'log "删除旧备份: {}"; rm -rf "{}"' \;
else
  log "警告:未生成有效备份,跳过清理"
  rm -rf "$BACKUP_DIR"
fi

# ---------------------------- 完成报告 ----------------------------
if [ -d "$BACKUP_DIR" ]; then
  HUMAN_SIZE=$(numfmt --to=iec $TOTAL_SIZE)
  log "备份完成: ${BACKUP_DIR} (总大小: ${HUMAN_SIZE})"
else
  log "错误:未生成任何有效备份"
fi

log "===== 备份结束 [${TIMESTAMP}] ====="
echo "" >> "$LOG_FILE"
exit 0

【定时】配置

修改 crontab 时间表达式
shell 复制代码
crontab -e  
添加以下行(晚上7点43分执行)
shell 复制代码
43 19 * * * /usr/local/docker/mysql/backup/docker_backup.sh >> /var/log/mysql_backup_cron.log 2>&1

查看当前用户的定时任务 : **crontab -l**

shell 复制代码
[root@lavm 20250905_135142]# crontab -l
43 19 * * * /usr/local/docker/mysql/backup/docker_backup.sh >> /var/log/mysql_backup_cron.log 2>&1

查看日志

cat /var/log/mysql_backup.log

查看备份数据

相关推荐
杨云龙UP8 分钟前
SQL Server 备份异地同步 + 清理脚本
运维·服务器·数据库·sql·mysql·sqlserver
0***h94220 分钟前
MySQL 启动失败 (code=exited, status=1FAILURE) 异常解决方案
数据库·mysql
IguoChan29 分钟前
D2L(1) — 线性回归
后端
8***293130 分钟前
Go基础之环境搭建
开发语言·后端·golang
梅花1431 分钟前
基于Django房屋租赁系统
后端·python·django·bootstrap·django项目·django网站
提笔了无痕32 分钟前
go web开发表单知识及表单处理详解
前端·后端·golang·web
qq_124987075334 分钟前
基于SpringBoot技术的企业请假审批管理系统的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·信息可视化·毕业设计
小哀21 小时前
🌸 入职写了一个月全栈next.js 感想
前端·后端·ai编程
ziwu1 小时前
【民族服饰识别系统】Python+TensorFlow+Vue3+Django+人工智能+深度学习+卷积网络+resnet50算法
人工智能·后端·图像识别
程序员Easy哥1 小时前
ID生成器第一讲:原理和常见几种生成器
后端