docker

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > 云和虚拟化 > docker > Docker Percona Xtrabackup全量压缩脚本

Docker版Percona Xtrabackup全量压缩脚本方式

作者:小时候的阳光

本文介绍了如何在Linux环境下使用Percona XtraBackup进行MySQL数据库的每天定时备份,并通过脚本实现备份数据的压缩、日志管理以及定时任务的设置

简单记录一下Percona Xtrabackup常用的每天定时备份的压缩脚本

场景说明

镜像信息:

[root@cn1920vm0064 backup]# docker image ls | grep -E '*backup|mysql*'
percona/percona-xtrabackup   8.0.35-34.1   11c6f241e3b3   6 weeks ago    1.78GB
mysql                        8.0.22        d4c3cafb11d5   4 years ago    545MB

运行容器:

[root@cn1920vm0064 backup]# docker ps | grep -E '*backup|mysql*'
99c8448c9387   mysql:8.0.22      "docker-entrypoint.s…"   19 hours ago   Up 18 hours                                                                                          mysql8

上面的 Docker容器 mysql8 为要备份的业务数据库,已经做了数据目录映射,之前创建该业务数据库的Docker容器命令如下:

 docker run -u root \
  --cap-add=SYS_NICE \
  --network=host \
  --restart=always \
  --name mysql8 \
  -v /data/apps/mysql/conf/my.cnf:/etc/mysql/my.cnf \
  -v /data/apps/mysql/files:/var/lib/mysql-files \
  -v /data/apps/mysql/data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=YourPassword \
  -d mysql:8.0.22

可以看到数据库的数据目录映射到物理宿主机的 /data/apps/mysql/data 目录下了,这里假设数据库端口为3309

一、创建备份脚本文件

sudo touch mysqlbackup.sh
sudo chmod +x mysqlbackup.sh

假设备份数据放在如下目录中:

sudo mkdir -p /data/apps/xtrabackup/backup

假设运行产生的日志放在文件/var/log/xtrabackup/backup.log 中:

sudo mkdir -p /var/log/xtrabackup
sudo touch /var/log/xtrabackup/backup.log
sudo chmod 644 /var/log/xtrabackup/backup.log

需要在目标业务数据库中创建专门的用于备份的账号密码:

 CREATE USER 'xtrabackup'@'%' IDENTIFIED WITH mysql_native_password BY 'yourbackpassword';
 
 GRANT SELECT, RELOAD, PROCESS, LOCK TABLES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO `xtrabackup`@`%`;

 GRANT BACKUP_ADMIN ON *.* TO `xtrabackup`@`%`;
 
 FLUSH PRIVILEGES;

脚本内容如下:

#!/usr/bin/env bash
#
# MySQL XtraBackup Daily Backup Script (Docker)
# 每天备份一次,保留最近3天(可调)

set -euo pipefail
# 建议:限制新建文件/目录权限,提升安全性
umask 077

########## 可配置变量 BEGIN ##########

# 备份保留天数(只保留最近多少个备份目录)
RETENTION_DAYS=3

# Docker 镜像
XTRABACKUP_IMAGE="percona/percona-xtrabackup:8.0.35-34.1"

# 宿主机 MySQL 数据卷所在的容器名称
MYSQL_DATA_CONTAINER="mysql8"

# 备份容器运行时名称(临时)
BACKUP_CONTAINER_NAME="pxb"

# 备份根目录(宿主机路径)
BACKUP_ROOT="/data/apps/xtrabackup/backup"

# MySQL 连接信息(从备份容器访问 MySQL)
MYSQL_HOST="172.17.0.1"
MYSQL_PORT="3309"
MYSQL_USER="xtrabackup"
MYSQL_PASSWORD="yourbackpassword"

# MySQL 数据目录(在 mysql8 容器里的路径)
MYSQL_DATADIR="/var/lib/mysql"

# 备份选项(可按需修改压缩等参数)
XTRABACKUP_OPTIONS="--backup --compress --compress-threads=4"

# 备份目录命名前缀
BACKUP_PREFIX="full_backup_"

# 日志文件
LOG_FILE="/var/log/xtrabackup/backup.log"

########## 可配置变量 END ##########

# 确保日志目录存在
mkdir -p "$(dirname "$LOG_FILE")"

# 从这里开始,所有输出(包括 docker run 的 stdout/stderr)都写入日志
exec >> "$LOG_FILE" 2>&1

echo "==== $(date '+%F %T') 开始 MySQL XtraBackup 备份 ===="

# 安全检查:防止 BACKUP_ROOT 为空或指向根目录
if [[ -z "${BACKUP_ROOT:-}" || "${BACKUP_ROOT}" == "/" ]]; then
  echo "ERROR: BACKUP_ROOT 未定义或为 '/',为防止误删数据,中止执行!"
  exit 1
fi

# 创建备份根目录(如不存在)
mkdir -p "${BACKUP_ROOT}"

# 生成当日备份目录名,例如 full_backup_2025-12-01
TODAY_DATE="$(date +%F)"
TARGET_DIR_NAME="${BACKUP_PREFIX}${TODAY_DATE}"
TARGET_DIR="${BACKUP_ROOT}/${TARGET_DIR_NAME}"

echo "== 当日备份目录: ${TARGET_DIR}"

# 如果当天目录已存在,可以选择退出或覆盖,这里选择退出防止覆盖
if [[ -d "${TARGET_DIR}" ]]; then
  echo "WARN: 备份目录已存在:${TARGET_DIR},本次备份中止以避免覆盖。"
  exit 1
fi

echo "== 启动 Docker 容器执行备份 =="
echo "   镜像: ${XTRABACKUP_IMAGE}"
echo "   MySQL: ${MYSQL_HOST}:${MYSQL_PORT}"
echo "   数据目录: ${MYSQL_DATADIR}"
echo "   目标目录: ${TARGET_DIR}"

docker run --name "${BACKUP_CONTAINER_NAME}" \
  --rm \
  -u root \
  --volumes-from "${MYSQL_DATA_CONTAINER}" \
  -v "${BACKUP_ROOT}":/backup \
  "${XTRABACKUP_IMAGE}" \
  /bin/bash -c "
    xtrabackup ${XTRABACKUP_OPTIONS} \
      --datadir=${MYSQL_DATADIR} \
      --target-dir=/backup/${TARGET_DIR_NAME} \
      --host=${MYSQL_HOST} \
      --port=${MYSQL_PORT} \
      --user=${MYSQL_USER} \
      --password=${MYSQL_PASSWORD}
  "

echo "== 备份完成: ${TARGET_DIR} =="

########## 清理旧备份(安全版) ##########

echo "== 清理旧备份,保留最近 ${RETENTION_DAYS} 个 =="

cd "${BACKUP_ROOT}" || {
  echo "ERROR: 无法进入备份目录 ${BACKUP_ROOT}"
  exit 1
}

# 收集所有符合前缀的备份目录,按时间倒序排列(最新在前)
BACKUP_DIRS=( $(ls -dt ${BACKUP_PREFIX}* 2>/dev/null || true) )

TOTAL=${#BACKUP_DIRS[@]}

if (( TOTAL == 0 )); then
  echo "当前没有任何备份目录,无需清理。"
elif (( TOTAL <= RETENTION_DAYS )); then
  echo "当前备份数量 ${TOTAL} 个,不超过保留上限 ${RETENTION_DAYS},无需删除。"
else
  TO_DELETE_COUNT=$(( TOTAL - RETENTION_DAYS ))
  echo "当前共有 ${TOTAL} 个备份,将删除最旧的 ${TO_DELETE_COUNT} 个:"

  for (( i=RETENTION_DAYS; i<TOTAL; i++ )); do
    OLD_BACKUP="${BACKUP_DIRS[$i]}"
    # 双重保险:只删除以 BACKUP_PREFIX 开头的目录
    if [[ -d "${OLD_BACKUP}" && "${OLD_BACKUP}" == ${BACKUP_PREFIX}* ]]; then
      echo "  删除旧备份目录: ${OLD_BACKUP}"
      rm -rf "${OLD_BACKUP}"
    else
      echo "  跳过(非备份目录或不存在): ${OLD_BACKUP}"
    fi
  done
fi

echo "==== $(date '+%F %T') 备份及清理完成 ===="

要点说明:

二、创建对应的日志管理配置

上面脚本中设置了输出的日志归档到 /var/log/xtrabackup/backup.log ,为了防止日志太大太多我们需要创建一个用于日志文件自动轮换、压缩、删除的工具。

Linux系统自带了一个工具:Logrotate

Logrotate 是一个 Linux/Unix 系统工具,主要用来管理系统生成的日志文件,这里我们直接创建对应我们脚本的日志管理配置内容:

sudo sh -c 'echo "/var/log/xtrabackup/backup.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
    create 644 root root
    dateext
    dateformat -%Y%m%d
}" | tee /etc/logrotate.d/xtrabackup'

配置参数含义说明
文件路径管理 /var/log/xtrabackup/backup.log 日志。
daily每天轮换一次。
rotate 7保留最近 7 份旧日志。
compress压缩旧日志。
delaycompress延迟压缩旧日志。
copytruncate复制旧日志后,清空原文件,让程序继续写入。
create创建新日志文件的权限和所有者。
dateext旧日志以日期命名。
missingok日志不存在不报错。
notifempty空日志不轮换。

测试一下

sudo logrotate -f /etc/logrotate.d/xtrabackup

正常情况日志目录下会生成:

backup.log-yyyymmdd
backup.log

三、创建定时任务

创建定时任务可以先手动执行一下脚本看下

sudo ./mysqlbackup.sh

上面的脚本放在 /data/apps/xtrabackup/backup/mysqlbackup.sh

sudo crontab -e

输入:

0 6 * * * /data/apps/xtrabackup/backup/mysqlbackup.sh

这里是每天早上6点执行,可以根据实际情况修改时间。

查看定时任务

sudo crontab -l

总结

本次脚本也是借助AI工具生产,经过了多次修改调试,适用于中小型业务场景的数据库备份操作。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文