Shell 脚本 + cron 定时备份 Docker MySQL

Shell 脚本 + cron 定时备份 Docker MySQL

✅ 为了直观且简单的达到读者期望要求,除了「环境准备-配置国内加速器」篇章有一条命令需要根据阿里云提供给你的加速地址进行配置外,本文的所有命令都可以直接 CV 执行且配有注释方便理解 。因此,在这种情况下,你可以参照本文进行 CV 在三分钟内就实现使用 Shell 脚本进行 MySQL 容器定时备份 。当然,你想自定义的配置信息如数据库用户名、数据库密码、备份路径等 ,可参考和修改「定时备份-配置文件」篇章的 db_backup_conf.json 文件

文章目录

要求说明

  • 每天凌晨 2:30 备份。
  • 脚本需要完成任务:
    1. 备份多个数据库 stu_manageblog_manage/data/mysql/backup 文件夹。
    2. 备份开始和备份结束给出相应的提示信息,写入到 /data/mysql/log/backup.log 日志文件。
    3. 备份后的文件以备份时间命名,并打包成 .tar.gz 格式,比如 2024-12-29_023004.tar.gz。
    4. 备份完成后,检查是否有 10 天以前备份的数据库文件,如果有就将其删除。

环境准备

环境:

  • 阿里云轻量应用服务器
  • Ubuntu 20.04.6 LTS

安装 docker

  1. 安装需要的包

    bash 复制代码
    sudo apt update && sudo apt install	apt-transport-https ca-certificates curl gnupg-agent software-properties-common
  2. 添加阿里 GPG 密钥

    bash 复制代码
    curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
  3. 设置阿里云 Docker 仓库地址

    bash 复制代码
    sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
  4. 安装 Docker Enginesudo docker --version

    bash 复制代码
    sudo apt update && sudo apt install docker-ce docker-ce-cli containerd.io
  5. 验证是否成功

    bash 复制代码
    sudo docker --version

配置国内加速器

若要配置阿里云加速器,必须首先要有阿里云的账号。登录阿里云后,打开阿里云的容器镜像服务页面,然后找到如下页面,可以查看到你的 registry-mirrors

我们按照上图代码步骤进行操作配置即可:

  1. 创建 docker 目录

    bash 复制代码
    sudo mkdir -p /etc/docker
  2. 创建 daemon.json 文件:该 json 数据中的 URL 地址是与用户登录账号绑定的,不同的用户所生成的地址是不同的。

    bash 复制代码
    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
      "registry-mirrors": ["替换为阿里云提供给你的 registry-mirrors 信息"]
    }
    EOF
  3. 重新加载服务配置文件

    bash 复制代码
    sudo systemctl daemon-reload
  4. 重启 docker 引擎

    bash 复制代码
    sudo systemctl restart docker

安装 MySQL 容器与测试

安装并启动 MySQL 容器:

bash 复制代码
sudo docker run -d \
  --name fox-mysql \
  -p 3306:3306 \
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -v /etc/mysql/data:/var/lib/mysql \
  -v /etc/mysql/conf:/etc/mysql/conf.d \
  mysql:5.7.27

使用 ufw 开启防火墙与创建防火墙规则,允许 3306 和 tcp。

bash 复制代码
sudo ufw enable; sudo ufw allow 3306/tcp; sudo ufw allow 22/tcp; sudo ufw allow 80/tcp; sudo ufw allow 443/tcp

由于我使用的是阿里云轻量应用服务器,阿里云平台本身也有一层安全组规则,这些规则会覆盖或限制通过 ufw 设置的本地防火墙规则。也就是说,即使配置了规则仍然拦截了 3306 端口。因此我们需要在阿里云平台上添加规则。

添加规则后,在自己电脑上远程连接服务器的 MySQL,使用 SQLyog 或 Navicat 等工具。执行如下 SQL:

mysql 复制代码
DROP DATABASE IF EXISTS `stu_manage`;
DROP DATABASE IF EXISTS `blog_manage`;

CREATE DATABASE `stu_manage`;

USE `stu_manage`;

CREATE TABLE `student`(
	`id` INT UNSIGNED AUTO_INCREMENT COMMENT '学号',
	`name` VARCHAR(64) NOT NULL COMMENT '姓名',
	`update_time` DATETIME NOT NULL COMMENT '修改时间',
	`create_time` DATETIME NOT NULL COMMENT '创建时间',
	PRIMARY KEY(`id`)
) ENGINE=INNODB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8mb4;

INSERT INTO `student`(`name`, `update_time`, `create_time`) VALUES
('狐狸半面添', NOW(), NOW()),
('foxtian', NOW(), NOW());

#--------------------------------------------------------

CREATE DATABASE `blog_manage`;

USE `blog_manage`;

CREATE TABLE `article_tag`(
	`id` INT UNSIGNED AUTO_INCREMENT COMMENT 'id',
	`name` CHAR(6) NOT NULL DEFAULT '' COMMENT '标签名称',
	`update_time` DATETIME NOT NULL COMMENT '修改时间',
	`create_time` DATETIME NOT NULL COMMENT '创建时间',
	PRIMARY KEY(`id`)
) ENGINE=INNODB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8mb4;

INSERT INTO `article_tag`(`name`, `update_time`, `create_time`) VALUES
('java', NOW(), NOW()),
('shell', NOW(), NOW()),
('linux', NOW(), NOW()),
('c', NOW(), NOW());

定时备份

配置文件

/task/mysql 目录下编写 db_backup_conf.json 配置文件:

bash 复制代码
# 1.为了能解析 json,安装 jq 工具
sudo apt update && sudo apt install jq

# 2.创建目录
sudo mkdir -p /task/mysql

# 3.进入 /task/mysql 目录下
cd /task/mysql

# 4.创建 db_backup.sh 脚本文件
sudo touch db_backup_conf.json; sudo chmod u+rw db_backup_conf.json; sudo vim db_backup_conf.json

db_backup_conf.json 配置文件内容:

json 复制代码
{
    "mysql_container_name": "fox-mysql",
    "backup_dir": "/data/mysql/backup",
    "mysql_user": "root",
    "mysql_password": "123456",
    "databases": ["stu_manage", "blog_manage"],
    "log_dir": "/data/mysql/log",
    "log_file": "backup.log"
}

配置文件的内容根据自己的实际情况进行修改,字段说明:

  • mysql_container_name:MySQL 容器名称。
  • backup_dir:备份目录。
  • mysql_user:数据库用户名。
  • mysql_password:数据库密码。
  • databases:需要备份的数据库。
  • log_dir:日志目录。
  • log_file:日志文件。

脚本编写

/task/mysql 目录下编写 db_backup.sh 脚本文件:

bash 复制代码
cd /task/mysql && sudo touch db_backup.sh; sudo chmod u+x db_backup.sh; sudo vim db_backup.sh

db_backup.sh 脚本文件内容:

bash 复制代码
#!/bin/bash

# 定义配置文件路径
conf_file="db_backup_conf.json"

# MySQL 容器名称
MYSQL_CONTAINER_NAME=$(jq -r '.mysql_container_name' "${conf_file}")
# 备份目录
BACKUP_DIR=$(jq -r '.backup_dir' "${conf_file}")
# 数据库用户名
MYSQL_USER=$(jq -r '.mysql_user' "${conf_file}")
# 数据库密码
MYSQL_PASSWORD=$(jq -r '.mysql_password' "${conf_file}")
# 需要备份的数据库
readarray -t DATABASES < <(jq -r '.databases[]' "$conf_file")
# 日志
LOG_DIR=$(jq -r '.log_dir' "${conf_file}")
LOG_FILE=$(jq -r '.log_file' "${conf_file}")

DATETIME=$(date +%Y-%m-%d_%H%M%S)

# 记录备份成功的数据库
SUCCESS_BACKUP_DB=()
# 记录备份失败的数据库
FAIL_BACKUP_DB=()

# 获取当前时间的日志格式
get_log_time() {
    echo "$(date '+%Y-%m-%d %H:%M:%S')"
}

# 初始化日志文件和备份目录
prepare() {
    # 如果不存在日志目录,则创建
    [ ! -d "${LOG_DIR}" ] && sudo mkdir -p "${LOG_DIR}"
    # 如果不存在日志文件,则创建并设置权限
    [ ! -f "${LOG_DIR}/${LOG_FILE}" ] && sudo touch "${LOG_DIR}/${LOG_FILE}" && sudo chmod u+rw "${LOG_DIR}/${LOG_FILE}"
    
    # 如果不存在备份目录,则创建
    [ ! -d "${BACKUP_DIR}" ] && sudo mkdir -p "${BACKUP_DIR}"
}

# 记录日志信息
log_message() {
    local message="$@"
    
    sudo echo -e "$(get_log_time) ${message}"
}

# 执行 mysqldump 备份
perform_backup() {
    sudo mkdir -p ${BACKUP_DIR}/${DATETIME}
    
    for database in "${DATABASES[@]}"; do
    
        local sql_file="${BACKUP_DIR}/${DATETIME}/${database}.sql"

        if sudo docker exec "${MYSQL_CONTAINER_NAME}" \
            sh -c "exec mysqldump -u${MYSQL_USER} -p'${MYSQL_PASSWORD}' -q -R --databases ${database}" \
            > "${sql_file}" 2>&1; then
            SUCCESS_BACKUP_DB+=("${database}")
            log_message "成功备份 MySQL 数据库 ${database} 到 ${sql_file}"
        else
            local err_code=$?
            FAIL_BACKUP_DB+=("${database}")
            log_message "失败备份 MySQL 数据库 ${database} 到 ${sql_file},错误代码:${err_code}(忽略错误,继续执行脚本)"
        fi
    
    done
}

# 压缩备份文件
compress_backup() {
    # 记录压缩开始的信息
    log_message "开始压缩 ${BACKUP_DIR}/${DATETIME} 文件夹"

    cd "${BACKUP_DIR}" || exit
    sudo tar -zcvf "${DATETIME}.tar.gz" "${DATETIME}" 2>&1
    
    # 记录压缩完成的信息
    log_message "完成压缩 ${BACKUP_DIR}/${DATETIME}.tar.gz"
}

# 删除原始 .sql 文件
remove_sql_file() {
    sudo rm -rf "${BACKUP_DIR}/${DATETIME}" 2>&1
    
    # 记录删除原始文件的信息
    log_message "完成删除 ${BACKUP_DIR}/${DATETIME} 文件夹"
}

# 清理旧备份文件
cleanup_old_backups() {
    sudo find "${BACKUP_DIR}" -atime +10 -name "*.tar.gz" -exec rm -rf {} \; 2>&1
}

# 主程序逻辑
main() {
	log_message "----------------------------------------------------------------"

    # 记录开始备份的信息
    log_message "开始备份 MySQL 数据库 ${DATABASES[*]}"

    # 执行 mysqldump 并将输出重定向到主机上的文件
    perform_backup

    # 将 .sql 文件压缩为 .tar.gz 格式
    compress_backup

    # 删除 .sql 文件
    remove_sql_file

    # 删除 10 天前的备份文件
    cleanup_old_backups

    # 记录结束备份的信息
    log_message "结束备份 MySQL 数据库,共需要备份 ${#DATABASES[@]} 个数据库,其中 \
${#SUCCESS_BACKUP_DB[@]} 个数据库(${SUCCESS_BACKUP_DB[@]})备份成功,\
${#FAIL_BACKUP_DB[@]} 个数据库(${FAIL_BACKUP_DB[@]})备份失败"

	log_message "----------------------------------------------------------------\n"
}


prepare
# 运行主程序
main >> "${LOG_DIR}/${LOG_FILE}" 2>&1

我们可以先运行这个脚本测试一下是否生效:

bash 复制代码
./db_backup.sh

此外,在执行脚本后,可以进一步查看日志文件和备份目录:

  1. 查看日志文件

    bash 复制代码
    sudo cat /data/mysql/log/backup.log
  2. 查看备份目录

    bash 复制代码
    cd /data/mysql/backup && sudo ls -lh
  3. 解压其中一个 .tar.gz 格式文件,并查看解压后的文件内容

    bash 复制代码
    # 解压
    sudo tar -zxvf 2024-12-29_170043.tar.gz --overwrite
    
    # 进入目录并查看
    cd 2024-12-29_170043 && sudo ls -lh

定时任务

在 ubuntu 系统下,默认是不生成 cron 日志文件的,因此我们通过如下步骤进行开启:

  1. 打开配置文件

    bash 复制代码
    sudo vim /etc/rsyslog.d/50-default.conf
  2. 从配置文件中找到 cron.*,将前面的注释 # 删除。

  3. 重启系统日志

    bash 复制代码
    sudo service rsyslog restart

编辑 crontab 任务:

bash 复制代码
sudo crontab -e

在第一次调用 crontab -e 命令时,可能会让你选择使用的编译器,建议选择 vim.basic。如果不小心选择了其它的,可使用 select-editor 命令重新选择。

输入任务:

shell 复制代码
30 2 * * * /task/mysql/db_backup.sh

查看一下 crontab 任务列表:

bash 复制代码
sudo crontab -l

为了以防万一,还可以检查一下 cron 服务是否已开启,即处于 active(running) 状态:

bash 复制代码
sudo systemctl status cron.service

当定时任务被调度时,我们可以通过查看日志文件 /data/mysql/log/backup.log 检查脚本执行情况。

当然,还可以通过查看文件 /var/log/cron.log 检查任务是否被调度。

bash 复制代码
sudo cat /var/log/cron.log | sudo grep db_backup.sh
相关推荐
飞火流星020271 小时前
docker安装Redis:docker离线安装Redis、docker在线安装Redis、Redis镜像下载、Redis配置、Redis命令
redis·docker·docker安装redis·redis镜像下载·redis基本操作·redis配置
lwprain1 小时前
springboot 2.7.6 security mysql redis jwt配置例子
spring boot·redis·mysql
vortex51 小时前
Shell基础:中括号的使用
linux·运维·bash·shell
基哥的奋斗历程2 小时前
Docker 常用命令
运维·docker·容器
HEX9CF3 小时前
【Docker】快速部署 Nacos 注册中心
运维·docker·容器
小Tomkk3 小时前
Docker 部署 ClickHouse 教程
clickhouse·docker·rpc
字节全栈_BjO5 小时前
mysql死锁排查_mysql 死锁问题排查
android·数据库·mysql
明 庭6 小时前
通过 Docker 部署 pSQL 服务器的教程
服务器·docker·容器
字节全栈_kYu6 小时前
FastDFS实用笔记 (Docker 搭建环境 + 整合 SpringBoot)
spring boot·笔记·docker
是小崔啊12 小时前
事务03之MVCC机制
数据库·mysql·事务·