基于 Kubernetes 环境中 MySQL 数据库备份与恢复

背景介绍

本数据库备份脚本基于 ToB 生产项目,单机服务架构,仅用于防止误删数据库而生

软件版本

  • 系统版本:CentOS Linux release 7.9.2009 (Core)
  • Kubernetes 版本:v1.19.16
  • Mysql 版本:v8.0.34

运行脚本前置工作

# 环境变量赋值或编辑 profile 永久加入环境变量
export MYSQL_ROOT_PASSWORD=xxxxx

数据库备份脚本详情

#!/bin/bash
#*************************************************************************************************************
#Author:        kubecc
#Date:          2024-11-08
#FileName:      mysqlbackpu.sh
#blog:          www.kubecc.com
#Description:   product databases backup
#Copyright (C): 2024 All rights reserved
#*************************************************************************************************************
# 定义变量
NAMESPACE="devops-tools"
POD_NAME=$(kubectl get pods -n ${NAMESPACE} | grep mysql | awk '{print $1}')
DB_USER="root"
DB_PASSWORD="${MYSQL_ROOT_PASSWORD}" # 环境变量获取
BACKUP_DIR="/data/backup/mysql"      # 备份文件存放路径
BACKUP_SUCCESS=true                  # 标志变量,用于跟踪备份是否成功
LOG_FILE="${BACKUP_DIR}/backup.log"  # 日志文件路径

# 创建备份目录(如果不存在)
mkdir -p ${BACKUP_DIR}

# 将标准输出和标准错误重定向到日志文件
exec > >(tee -a ${LOG_FILE}) 2>&1

echo "===== 备份开始时间: $(date) ====="

# 获取所有数据库名称(排除系统数据库)
DATABASES=$(kubectl exec "${POD_NAME}" -n "${NAMESPACE}" -- mysql -u"${DB_USER}" -p"${DB_PASSWORD}" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")

# 检查是否获取到数据库
if [ -z "$DATABASES" ]; then
  echo "未找到可备份的数据库。"
  exit 1
fi

# 遍历每个数据库并备份
for DB_NAME in ${DATABASES}; do
  BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_$(date +%Y%m%d%H%M%S).sql"
  BACKUP_FILE_GZ="${BACKUP_FILE}.gz" # 压缩后的文件名

  echo "正在备份数据库: ${DB_NAME}..."

  # 使用kubectl exec在MySQL Pod中执行备份命令,并加上--single-transaction
  if kubectl exec "${POD_NAME}" -n "${NAMESPACE}" -- mysqldump -u"${DB_USER}" -p"${DB_PASSWORD}" --single-transaction "${DB_NAME}" >"${BACKUP_FILE}"; then
    echo "数据库 ${DB_NAME} 备份成功,备份文件保存在: ${BACKUP_FILE}"

    # 压缩备份文件
    echo "正在压缩备份文件: ${BACKUP_FILE}..."
    if gzip "${BACKUP_FILE}"; then
      echo "备份文件压缩成功,压缩文件保存在: ${BACKUP_FILE_GZ}"
      # 删除原始 SQL 文件
      rm -f "${BACKUP_FILE}"
      echo "已删除原始 SQL 文件: ${BACKUP_FILE}"
    else
      echo "备份文件压缩失败,请检查错误信息。"
      BACKUP_SUCCESS=false # 标记备份失败
    fi
  else
    echo "数据库 ${DB_NAME} 备份失败,请检查错误信息。"
    rm -f "${BACKUP_FILE}" # 删除可能不完整的备份文件
    BACKUP_SUCCESS=false   # 标记备份失败
  fi
done

# 如果备份全部成功,则执行清理策略
if $BACKUP_SUCCESS; then
  echo "所有数据库备份成功,正在检查是否需要清理超过 7 天的备份文件..."

  # 查找匹配的文件
  FILES_TO_DELETE=$(find "${BACKUP_DIR}" -name "*.gz" -mtime +7)

  # 检查是否有需要删除的文件
  if [ -z "$FILES_TO_DELETE" ]; then
    echo "数据库备份完成,没有需要清理的数据。"
  else
    echo "找到的备份文件:"
    echo "$FILES_TO_DELETE"

    # 删除超过 7 天的备份文件,并列出删除的文件名称
    echo "正在删除以下文件:"

    # 检查清理是否完成
    if find "${BACKUP_DIR}" -name "*.gz" -mtime +7 -exec echo "删除文件: {}" \; -exec rm -f {} \;; then
      echo "备份文件清理完成,已删除超过 7 天的备份文件。"
    else
      echo "备份文件清理失败,请检查错误信息。"
    fi
  fi
else
  echo "备份过程中出现失败,跳过清理策略。"
fi
echo "===== 备份结束时间: $(date) ====="

创建定时任务

运行脚本
每天凌晨 3:00 分开始备份,并清理7天之前的备份数据,
因为数据量不大,为了省事,所以每次都是全备,并将日志打印到指定文件中,

[root@master01 ~]# crontab -e
00 03 * * * bash /usr/local/sbin/mysqlbackup.sh

运行结果输出样例

[root@master01 ~]# bash mysqlbackup.sh
===== 备份开始时间: Fri Jan 10 15:32:07 CST 2025 =====
mysql: [Warning] Using a password on the command line interface can be insecure.
正在备份数据库: nacos_db...
mysqldump: [Warning] Using a password on the command line interface can be insecure.
数据库 nacos_db 备份成功,备份文件保存在: /data/backup/mysql/nacos_db_20250110153207.sql
正在压缩备份文件: /data/backup/mysql/nacos_db_20250110153207.sql...
备份文件压缩成功,压缩文件保存在: /data/backup/mysql/nacos_db_20250110153207.sql.gz
已删除原始 SQL 文件: /data/backup/mysql/nacos_db_20250110153207.sql
所有数据库备份成功,正在检查是否需要清理超过 7 天的备份文件...
找到的备份文件:
/data/backup/mysql/nacos_db_20250110140229.sql.gz
/data/backup/mysql/nacos_db_20240110140229.sql.gz
/data/backup/mysql/nacos_db_20230110140229.sql.gz
正在删除以下文件:
删除文件: /data/backup/mysql/nacos_db_20250110140229.sql.gz
删除文件: /data/backup/mysql/nacos_db_20240110140229.sql.gz
删除文件: /data/backup/mysql/nacos_db_20230110140229.sql.gz
备份文件清理完成,已删除超过 7 天的备份文件。
===== 备份结束时间: Fri Jan 10 15:32:07 CST 2025 =====

数据库恢复脚本详情

#!/bin/bash
#*************************************************************************************************************
#Author:        kubecc
#Date:          2024-11-08
#FileName:      mysqlrestore.sh
#blog:
#Description:   product databases restore
#Copyright (C): 2024 All rights reserved
#*************************************************************************************************************
# 定义变量
NAMESPACE="devops-tools"
POD_NAME=$(kubectl get pods -n "${NAMESPACE}" | grep mysql | awk '{print $1}' )  # 获取 Pod 名称
DB_USER="root"
DB_PASSWORD="${MYSQL_ROOT_PASSWORD}"  # 从环境变量获取密码
BACKUP_DIR="/data/backup/mysql"       # 备份文件存储路径

# 函数:从备份文件名中解析数据库名称
get_databases_from_backups() {
  ls "${BACKUP_DIR}" | grep -v backup.log |grep -v  '*.sql.gz' | awk -F '_[0-9].' '{print $1}' | uniq | sort -r
}

# 函数:显示菜单并获取用户选择
show_menu() {
  # 获取可恢复的数据库列表
  DATABASES=$(get_databases_from_backups)

  # 检查是否有可用的数据库备份文件
  if [ -z "${DATABASES}" ]; then
    echo "错误:没有可用的备份数据库。"
    exit 1
  fi

  echo "请选择要恢复的数据库:"
  select DB_NAME in ${DATABASES}; do
    if [ -n "${DB_NAME}" ]; then
      echo "你选择的数据库是: ${DB_NAME}"
      break
    else
      echo "无效的选择,请重新选择。"
    fi
  done
}

# 函数:显示备份版本并获取用户选择
show_versions() {
  # 获取匹配的备份文件列表
  BACKUP_FILES=$(find "${BACKUP_DIR}" -name "${DB_NAME}_*.sql.gz" -printf '%f\n' | sort -r)
  echo "请选择要恢复的备份版本:"
  select BACKUP_FILE in ${BACKUP_FILES}; do
    if [ -n "${BACKUP_FILE}" ]; then
      echo "你选择的备份文件是: ${BACKUP_FILE}"
      break
    else
      echo "无效的选择,请重新选择。"
    fi
  done
}

# 函数:恢复数据库
restore_database() {
  local BACKUP_FILE=$1
  local TARGET_DB=$2

  # 解压备份文件
  echo "正在解压备份文件..."
  UNZIPPED_FILE="${BACKUP_FILE%.gz}"
  gzip -c -d "${BACKUP_DIR}/${BACKUP_FILE}" > "${BACKUP_DIR}/${UNZIPPED_FILE}" || { echo "解压失败"; exit 1; }

  # 将备份文件复制到 MySQL Pod
  echo "正在将备份文件复制到 MySQL Pod..."
  kubectl cp "${BACKUP_DIR}/${UNZIPPED_FILE}" "${POD_NAME}:/tmp/backup.sql" -n "${NAMESPACE}" || { echo "复制失败"; exit 1; }

  # 进入 MySQL Pod 并恢复数据库
  echo "正在恢复数据库..."
  kubectl exec "${POD_NAME}" -n "${NAMESPACE}" -- bash -c '
    mysql -u'"${DB_USER}"' -p'"${DB_PASSWORD}"' -e "DROP DATABASE IF EXISTS '"${TARGET_DB}"';"
    mysql -u'"${DB_USER}"' -p'"${DB_PASSWORD}"' -e "CREATE DATABASE '"${TARGET_DB}"';"
    mysql -u'"${DB_USER}"' -p'"${DB_PASSWORD}"' '"${TARGET_DB}"' < /tmp/backup.sql
    rm /tmp/backup.sql
  ' || { echo "恢复失败"; exit 1; }

  echo "数据库恢复完成!"
}

# 主函数
main() {
  # 第一阶段:选择数据库
  show_menu

  # 第二阶段:选择备份版本
  show_versions

  # 第三阶段:恢复数据库
  restore_database "${BACKUP_FILE}" "${DB_NAME}"
}

# 执行主函数
main

恢复演示

[root@master01 mysql]# bash /root/restore_mysql.sh
请选择要恢复的数据库:
1) sxxxx_asda122333_asd222  4) nacos
2) sads_sdasD               5) asd_asda_ax
3) nacos_db
#? 4
你选择的数据库是: nacos
请选择要恢复的备份版本:
1) nacos_20250110164213.sql.gz  3) nacos_20250110164203.sql.gz
2) nacos_20250110164205.sql.gz
#? 1
你选择的备份文件是: nacos_20250110164213.sql.gz
正在解压备份文件...
正在将备份文件复制到 MySQL Pod...
正在恢复数据库...
mysql: [Warning] Using a password on the command line interface can be insecure.
mysql: [Warning] Using a password on the command line interface can be insecure.
mysql: [Warning] Using a password on the command line interface can be insecure.
数据库恢复完成!

总结

这是一个初步实现的版本,功能已经完成,可以正常运行,但可能还需要进一步优化。

用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇