Java应用备份Mysql数据库,跨docker容器执行脚本
Docker跨容器执行脚本,Java调用脚本,Mysql备份,Docker.sock
近来有一个需求,需要备份数据库以供审计。思路很简单,直接写个sh脚本并用Java程序调用即可,说干就干
1、backup.sh脚本
#!/bin/bash
host="127.0.0.1"
port="3306"
user="user"
password="password"
# 备份数据库名
db="dbName"
# 仅仅备份结构的表,多表使用|隔开
noDataTable="table"
# 备份文件名
backupFile=/var/lib/mysql-backup/${db}-$(date +%Y%m%d%H%M%S).sql
echo "开始备份数据库:${db}"
# 备份表结构与数据,-N是去掉标题头
tables=$(mysql -N -h${host} -P${port} -u${user} -p${password} -e "show tables from ${db}" | grep -Ev ${noDataTable})
mysqldump -h${host} -P${port} -u${user} -p${password} ${db} ${tables} >> ${backupFile}
# 仅备份表结构
mysqldump -d -h${host} -P${port} -u${user} -p${password} ${db} ${noDataTable} >> ${backupFile}
echo "数据库备份完成"
接着问题就来了,使用mysql是使用docker部署的,那么如何在宿主机执行mysql容器的脚本呢?很简单,思路是将脚本目录挂载到mysql容器中,然后使用docker exec命令执行内部的备份脚本。思路有了,继续往下执行
2、挂载
上边是我的docker-compose配置,框起来就是重点。贴出文字版
services:
mysql:
image: mysql:5.7.34
restart: always
container_name: mysql
#容器内赋予root权限
privileged: true
ports:
- 13306:3306
environment:
MYSQL_ROOT_PASSWORD: password
TZ: Asia/Shanghai
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--lower_case_table_names=1
--max_allowed_packet=128M
--innodb_strict_mode=0
--sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
volumes:
- ./mysql/conf:/etc/mysql
- ./mysql/data:/var/lib/mysql
- ./mysql/logs:/var/log/mysql
- ./mysql/backup:/var/lib/mysql-backup
./mysql/backup
是我宿主机上备份脚本backup.sh的目录,将其挂载到mysql容器内部的/var/lib/mysql-backup
中,然后就能通过命令去运行了
docker exec mysql /var/lib/mysql-backup/backup.sh
然后发现还有问题,Java应用也是通过Docker部署的,那么如何跨容器去调用脚本呢?我先把备份脚本目录挂载进Java容器中,这样,Java容器与mysql容器共同挂载了./mysql/backup
目录,为了方便,我们将容器内部目录统一设置为/var/lib/mysql-backup
。这样,我们在Java容器中也能访问到备份脚本backup.sh了,下面我们进入java容器检验一下,docker exec -it youth sh
,进入脚本目录cd /var/lib/mysql-backup
发现已经脚本存在了,那么我们执行一下sh /var/lib/mysql-backup/backup.sh
找不到mysql及mysqldump命令?原来这个是Java容器,里边根本没有安装Mysql,那么这条路就行不通了,我们可以换一种新的思路,也就是在Java容器中跨容器调用Mysql的脚本。思路有了,接着开干。
1、进入Java容器
docker exec -it youth sh
2、通过Docker执行Mysql备份脚本
docker exec mysql /var/lib/mysql-backup/backup.sh
3、没有docker指令
所以我们需要在Java容器内部挂载宿主机的docker,贴出构建镜像的dockerfile
FROM openjdk:8-jdk-alpine
MAINTAINER SYH
ENV PARAMS="-Xms64m -Xmx128m"
ENV TIME_ZONE=PRC
#时区定义
RUN ln -snf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime && echo $TIME_ZONE > /etc/timezone
RUN mkdir -p /data/logs
ARG JAR_FILE
COPY target/${JAR_FILE} /app.jar
ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /app.jar $PARAMS"]
4、挂载docker.sock文件
具体解析查看大佬的文章docker.sock详解,贴出docker-compose文件
youth:
image: 127.0.0.1:5000/youth_dev:latest
restart: always
container_name: youth
ports:
- 8080:8080
volumes:
- /etc/localtime:/etc/localtime:ro
#在容器内部可以使用docker
- /var/run/docker.sock:/var/run/docker.sock:ro
- /usr/bin/docker:/usr/bin/docker:ro
- /etc/docker/daemon.json:/etc/docker/daemon.json:ro
logging:
options:
max-file: "2"
max-size: "1024m"
5、重启Java容器
这里需要注意第3步重新构建完镜像后,记得删除本地的镜像,我是使用私人docker仓库的,踩了一个坑,若是镜像标签一致,且本地已有镜像的时候,不会再去从私人仓库拉取镜像,而是继续采用本地的镜像,这就造成镜像还是老的版本,或者改下镜像标签的话也可以,这样他就每次都从私人仓库拉取新镜像了。启动Java容器后,进入容器内部,使用docker -v指令,确保容器内部已有docker
6、看看能否查询到宿主机的容器
docker ps
7、不忘初心,执行我们的数据库备份脚本
docker exec mysql /var/lib/mysql-backup/backup.sh
8、大功告成
此时只需要Java代码中实现执行docker exec mysql /var/lib/mysql-backup/backup.sh
指令即可,下面贴出初步实现代码,该方法很不安全,只是在测试环境验证而已,注意生产环境上不能直接以参数的形式写入bash命令。
package com.syh.youth.controller;
import cn.hutool.core.util.RuntimeUtil;
import com.syh.youth.domain.Res;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author Lenovo
*/
@RestController
@RequestMapping("/shell")
public class ShellController {
@GetMapping("/exec")
public Res<String> exec(String command) {
List<String> strings = RuntimeUtil.execForLines(command);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < strings.size(); i++) {
sb.append(strings.get(i)).append(" ");
}
return Res.ok(sb.toString());
}
}
更多推荐
所有评论(0)