Shell 脚本 + cron 定时备份 Docker MySQL
✅ 为了直观且简单的达到读者期望要求,除了「环境准备-配置国内加速器」篇章有一条命令需要根据阿里云提供给你的加速地址进行配置外,本文的所有命令都可以直接 CV 执行且配有注释方便理解 。因此,在这种情况下,你可以参照本文进行 CV 在三分钟内就实现使用 Shell 脚本进行 MySQL 容器定时备份 。当然,你想自定义的配置信息如数据库用户名、数据库密码、备份路径等 ,可参考和修改「定时备份-配置文件」篇章的 db_backup_conf.json 文件。
文章目录
- [Shell 脚本 + cron 定时备份 Docker MySQL](#Shell 脚本 + cron 定时备份 Docker MySQL)
要求说明
- 每天凌晨 2:30 备份。
- 脚本需要完成任务:
- 备份多个数据库
stu_manage
、blog_manage
到/data/mysql/backup
文件夹。 - 备份开始和备份结束给出相应的提示信息,写入到
/data/mysql/log/backup.log
日志文件。 - 备份后的文件以备份时间命名,并打包成
.tar.gz
格式,比如 2024-12-29_023004.tar.gz。 - 备份完成后,检查是否有 10 天以前备份的数据库文件,如果有就将其删除。
- 备份多个数据库
环境准备
环境:
- 阿里云轻量应用服务器
- Ubuntu 20.04.6 LTS
安装 docker
-
安装需要的包
bashsudo apt update && sudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
-
添加阿里 GPG 密钥
bashcurl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
-
设置阿里云 Docker 仓库地址
bashsudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
-
安装 Docker Enginesudo docker --version
bashsudo apt update && sudo apt install docker-ce docker-ce-cli containerd.io
-
验证是否成功
bashsudo docker --version
配置国内加速器
若要配置阿里云加速器,必须首先要有阿里云的账号。登录阿里云后,打开阿里云的容器镜像服务页面,然后找到如下页面,可以查看到你的 registry-mirrors
。
我们按照上图代码步骤进行操作配置即可:
-
创建 docker 目录
bashsudo mkdir -p /etc/docker
-
创建 daemon.json 文件:该 json 数据中的 URL 地址是与用户登录账号绑定的,不同的用户所生成的地址是不同的。
bashsudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["替换为阿里云提供给你的 registry-mirrors 信息"] } EOF
-
重新加载服务配置文件
bashsudo systemctl daemon-reload
-
重启 docker 引擎
bashsudo 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
此外,在执行脚本后,可以进一步查看日志文件和备份目录:
-
查看日志文件
bashsudo cat /data/mysql/log/backup.log
-
查看备份目录
bashcd /data/mysql/backup && sudo ls -lh
-
解压其中一个 .tar.gz 格式文件,并查看解压后的文件内容
bash# 解压 sudo tar -zxvf 2024-12-29_170043.tar.gz --overwrite # 进入目录并查看 cd 2024-12-29_170043 && sudo ls -lh
定时任务
在 ubuntu 系统下,默认是不生成 cron 日志文件的,因此我们通过如下步骤进行开启:
-
打开配置文件
bashsudo vim /etc/rsyslog.d/50-default.conf
-
从配置文件中找到
cron.*
,将前面的注释#
删除。 -
重启系统日志
bashsudo 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