Java跨Docker容器备份数据库数据

我的个人博客:Lichg,欢迎大家访问。

前置背景

  • 在我们的开发部署场景中,通常多数使用Docker进行部署。当你的数据库和项目都使用Docker进行部署,此时我想要通过Java程序进行数据备份,那么就无法实现,因为是两个相互独立的容器。
  • 在本篇文章中,我提供我的解决方法仅供参考。

思路整理

  1. 因为你的两个Docker容器是相互独立的,你的Java容器要操作MySQL,所以你的Java容器要具备可以执行MySQL命令的能力
  2. 但是,MySQL和Java是隔离的,无法直接使用MySQL命令备份,所以就想到使用docker的exec命令去操作MySQL容器让他备份。
  3. 备份完事以后,备份的文件还在MySQL容器中,宿主机也看不到想要的备份的SQL脚本,所以MySQL容器要挂载数据卷,把备份的SQL脚本备份出来。

编写备份脚本

本脚本我是从别人那里拿的,根据自己的需求修改即可

#!/bin/bash
#备份路径
BACKUP=/backups/mysql
#当前时间
DATETIME=$(date +%Y-%m-%d)
echo "===== 备份开始 ====="
 
#数据库名称
DATABASE=你的数据库名
#数据库地址
HOST=数据库地址
#数据库用户名
DB_USER=用户名
#数据库密码
DB_PW=密码
#创建备份目录
[ ! -d "${BACKUP}/$DATABASE" ] && mkdir -p "${BACKUP}/$DATABASE"
echo "备份文件存放于${BACKUP}/$DATABASE/$DATABASE-$DATETIME.sql"
#开始备份
mysqldump -h ${HOST} -u${DB_USER} -p${DB_PW}  ${DATABASE} > ${BACKUP}/$DATABASE/$DATABASE-$DATETIME.sql
 
echo "===== 导出成功,开始传输 ====="
#压缩成tar.gz包
cd $BACKUP
tar -zcvf $DATABASE.tar.gz $DATABASE
#备份到服务器B
#scp $DATABASE-$DATETIME.sql root@ip:/home/mysqlBackup
#删除备份目录  如果取消注释此命令 会删除sql脚本文件 只保留打包完成后的压缩包
# rm -rf ${BACKUP}/$DATABASE/$DATETIME
 
#删除10天(不含)前备份的数据,这边可以自行更改
find $BACKUP -mtime +10 -name "*.tar.gz" -exec rm -rf {} \;
echo "===== 数据库备份到服务器成功 ====="

容器启动

这里如果你的容器已经启动了也没关系,直接跑一遍docker命令即可。

Java:

这里最主要的是数据卷的绑定,因为你的Java容器需要可以使用docker命令,所以你得把docker挂载进去。其他的根据自己的需求修改就行。

docker run -d \
-v $JOB_NAME-data:/tmp \
--net=host \
-e PARAMS="--spring.profiles.active=prod" \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
--name $JOB_NAME $JOB_NAME

MySQL:

version: '3'

services:
  mysql:
    image: mysql:5.7
    container_name: mysql
    volumes:
      - mysql-conf:/etc/mysql/conf.d
      - mysql-data:/var/lib/mysql
      # 数据库备份脚本存储路径,映射进去:这里是把你准备的备份脚本从宿主机映射到MySQL容器中,让他可以执行
      - /export/shell/mysql:/home/shell/mysql
      # 数据库的备份文件挂在地址:这里是MySQL备份完成后,将备份文件从容器中映射到宿主机中
      - /export/backups/mysql/57:/backups/mysql
      # 将宿主机的时区挂载到容器:不挂载可能导致容器内和宿主机的时间不一致,导致备份脚本文件名称的日期出错
      - /etc/localtime:/etc/localtime:ro
    environment:
      - MYSQL_ROOT_PASSWORD=自行设置你的数据库密码
    ports:
      - "3306:3306"
    mem_limit: 512m

volumes:
  mysql-conf:
  mysql-data:

检验效果

Java容器

  1. 先进入到你的Java容器中:
docker exec -it Java容器名 bash
  1. 进来以后可以直接使用下面的命令,查看是否挂载Docker成功:
docker -v
  1. 出现版本号即为成功

image-20240527104710429

  1. 如果你出现了权限不足的问题,你需要退回到你的宿主机内,给docker.sock进行权限修改,没有的话直接省略此步骤即可:
chmod -R 777 /var/run/docker.sock
  1. Java容器中查看你的MySQL版本,如果正常出现版本号基本就没什么问题了:
# 注意这里没有 -it 参数
docker exec mysql mysql -V

image-20240527111754983

MySQL容器

  1. 进入MySQL容器:
docker exec -it mysql bash
  1. 找到你自己设置的挂载备份脚本的路径,查看脚本是否挂载成功:

image-20240527112516583

  1. 你可以直接执行下你的脚本,看下效果
sh 你的脚本名称

image-20240527113328530

  1. 可以到你的备份目录查看下备份的效果,这里有其他的是因为我的程序设置的每七天自动备份一次:

image-20240527113507659

  1. 到你的宿主机挂载的脚本备份路径查看:

image-20240527113846237

image-20240527113918053

  1. 这里还是有一个可能存在的坑:

如果你发现你备份的数据SQL脚本,分明是18号备份的但是SQL的脚本文件的名称上却是17号,这是因为:你的数据库备份脚本中,有一个参数是获取当前系统的时间,那么就说明你的MySQL容器中的时间跟宿主机的时间不一致,运行容器时没有对时区进行挂载数据卷。

image-20240527114446397

Java代码执行备份

代码执行这里我是使用了xxl-job定时任务去做,每七天备份一次,其他的实现方式可以根据你们自己的需求去进行更改。

    @XxlJob("mysqlBackup")
    public void mysqlBackup(){
        //获取Runtime实例
        Runtime runtime = Runtime.getRuntime();
        // 数据库备份命令
        String command = "docker exec mysql sh /home/shell/mysql/course_compete.sh";
        //获取命令所得的缓冲流结果
        BufferedReader bufferedReader = null;
        // 执行命令
        try {
            Process exec = runtime.exec(command);
            //初始化缓冲阅读器
            bufferedReader = new BufferedReader(new InputStreamReader(exec.getInputStream()));
            // 逐行读取输出
            String line;
            //此时就可以对获取的结果in进行操作了,可以使用in.readline()逐步获取每一行的结果内容
            while ((line = bufferedReader.readLine()) != null){
                log.info("获取到的行数据:{}", line);
            }
        } catch (IOException e) {
            log.error("竞赛模块数据库备份异常");
            throw new RuntimeException(e);
        }finally {
            if(bufferedReader != null){
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奔跑的菜鸟Run

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值