定期从Docker上部署的MySQL备份数据
前段时间公司停电,正巧赶上周一领导要开会要过一遍项目,然而项目所依赖的MySQL数据库是直接部署在宿主机,且因为各人部署方式不同的原因,花了很久才在开会前启动起来。于是开完会后,我第一件事就是把原先依赖的MySQL数据库迁移到Docker上,又另外写了一个脚本定时将Docker上部署的MySQL数据库备份出来,而且我们的脚本不单单可以指定要备份的数据库,还要将备份出来的SQL文件打包成压缩文件,并以一定的规范来命名,比如:test_2019-10-11-17.zip,test是前缀,2019-10-11-17代表是2019年10月11日17点的时候备份的。再来就是定期删除5个小时或10个小时之前的备份文件,当然这些都是锦上添花的事了,文末会附上备份文件脚本。
现在,我们先在Docker上部署一个MySQL实例,再创建几个用于测试的数据库,将其导出。
首先,我们创建一个MySQL实例:
➜ ~ docker run --name mysql-test -v /usr/local/mysql-test:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -p 8706:3306 -d mysql
1a70e86992bddb493db69da55cf8bf08863ce0b59d2f5931e782125adb900d71
➜ ~ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1a70e86992bd mysql "docker-entrypoint..." 4 seconds ago Up 2 seconds 33060/tcp, 0.0.0.0:8706->3306/tcp mysql-test
然后我们进入到容器后,再进入到MySQL修改一下加密方式,以便部分版本较旧的Navicat可以连接我们的MySQL实例(此操作可以不做):
➜ ~ docker exec -it mysql-test /bin/bash
root@1a70e86992bd:/# mysql -uroot -p
Enter password:
…… mysql> ALTER user 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
Query OK, 0 rows affected (0.03 sec) mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
我们创建一个test1数据库,再创建一张表admin,并插入两条数据:
mysql> CREATE DATABASE `test1`CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
Query OK, 1 row affected (0.02 sec) mysql> CREATE TABLE `test1`.`admin` ( `id` INT NOT NULL AUTO_INCREMENT, `account` CHAR ( 32 ) NOT NULL, PRIMARY KEY ( `id` ) );
Query OK, 0 rows affected (0.27 sec) mysql> INSERT INTO `test1`.`admin`(`account`) VALUES ('admin1');
Query OK, 1 row affected (0.02 sec) mysql> INSERT INTO `test1`.`admin`(`account`) VALUES ('admin2');
Query OK, 1 row affected (0.01 sec) mysql> SELECT * FROM `test1`.`admin`;
+----+---------+
| id | account |
+----+---------+
| 1 | admin1 |
| 2 | admin2 |
+----+---------+
2 rows in set (0.00 sec)
我们再来创建第二个数据库test2,并创建一张表user,再插入两条测试数据:
mysql> CREATE DATABASE `test2`CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
Query OK, 1 row affected (0.01 sec) mysql> CREATE TABLE `test2`.`user` ( `id` INT NOT NULL AUTO_INCREMENT, `name` CHAR ( 32 ) NOT NULL, `age` TINYINT NOT NULL, PRIMARY KEY ( `id` ) );
Query OK, 0 rows affected (0.04 sec) mysql> INSERT INTO `test2`.`user`(`name`,`age`) VALUES ('Amy','16');
Query OK, 1 row affected (0.03 sec) mysql> INSERT INTO `test2`.`user`(`name`,`age`) VALUES ('Tom','20');
Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM `test2`.`user`;
+----+------+-----+
| id | name | age |
+----+------+-----+
| 1 | Amy | 16 |
| 2 | Tom | 20 |
+----+------+-----+
2 rows in set (0.00 sec)
至此,我们的测试库和测试数据已经创建好了。现在,我们先尝试着用命令行备份数据库test1。
➜ ~ docker exec -it mysql-test mysqldump -uroot -p123456 test1 > test1.sql
➜ ~ cat test1.sql
……
CREATE TABLE `admin` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`account` char(32) COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
……
INSERT INTO `admin` VALUES (1,'admin1'),(2,'admin2');
这里简单介绍一下导出命令:
docker exec -it {container_name} mysqldump -u{db_user} -p{db_password} {database} > {file_path}
- container_name:容器名称,此处也可填容器ID。
- db_user:数据库账号。
- db_password:数据库密码。
- database:要备份的数据库。
- file_path:备份出来的文件名。
因此,如果我们要备份多个数据库,比如test1和test2,则循环执行上面的命令,替换database即可。
让我们用Python3来执行下面这个脚本:
#!/usr/bin/env python
# encoding: utf-8
import datetime
import os
import shutil
import subprocess
import time
import zipfile # 数据库用户名
db_user = "root"
# 数据库密码
db_password = "123456"
# 备份目录
backup_dir = "/var/test_backup"
# backup_prefix和backup_suffix分别为备份文件的前缀和后缀,如test_backup_2019-09-19-11则代表该文件是在2019年9月19日的11点时备份的
backup_prefix = "test_backup"
backup_suffix = "%Y-%m-%d-%H"
# 备份数据库列表
backup_databases = [
"test1",
"test2",
]
# 容器名
container_name = "mysql-test"
# 过期小时,定期删除5个小时前的备份文件
expire_hour = 5 # 获取备份文件名
def get_backup_filename():
t = time.strftime(backup_suffix, time.localtime())
return "%s_%s" % (backup_prefix, t) def get_backup_path():
return "%s%s%s" % (backup_dir, os.sep, get_backup_filename()) # 获取过期时间戳
def get_expire_time():
t = datetime.datetime.now() - datetime.timedelta(hours=expire_hour)
return int(time.mktime(t.timetuple())) def create_dir(dir_path):
# 如果目录存在则退出
if os.path.exists(dir_path):
return
os.mkdir(dir_path) cmd_template = "docker exec -it {container_name} mysqldump -u{db_user} -p{db_password} {database} > {file_path}" # 备份指定数据库
def backup_database(backup_path, database):
file_path = os.sep.join([backup_path, "%s.sql" % database])
d = {
"container_name": container_name,
"db_user": db_user,
"db_password": db_password,
"database": database,
"file_path": file_path,
}
cmd = cmd_template.format(**d)
subprocess.call(cmd, shell=True) def zip_dir(dir_path):
file_path = '.'.join([dir_path, "zip"])
if os.path.exists(file_path):
os.remove(file_path)
z = zipfile.ZipFile(file_path, 'w', zipfile.ZIP_DEFLATED)
for root, directories, files in os.walk(dir_path):
fpath = root.replace(dir_path, '')
fpath = fpath and fpath + os.sep or ''
for filename in files:
z.write(os.path.join(root, filename), fpath + filename)
z.close() # 备份数据库
def backup():
backup_path = get_backup_path()
try:
create_dir(backup_path)
for database in backup_databases:
backup_database(backup_path, database)
zip_dir(backup_path)
finally:
shutil.rmtree(backup_path) # 清理过期备份文件
def clean():
expire_time = get_expire_time()
for root, directories, files in os.walk(backup_dir):
for file in files:
if not file.startswith(backup_prefix):
continue
if not file.endswith(".zip"):
continue
file_path = os.sep.join([root, file])
t = os.path.getctime(file_path)
if t < expire_time:
os.remove(file_path) if __name__ == "__main__":
try:
backup()
finally:
clean()
执行完毕后,我们会发现备份目录下多了一个zip文件,我们可以用unzip命令来查看下zip文件的内容:
➜ ~ python36 backup.py
➜ ~ ll /var/test_backup
total 4.0K
-rw-r--r-- 1 root root 1.8K Oct 12 09:55 test_backup_2019-10-12-09.zip
➜ ~ unzip -v /var/test_backup/test_backup_2019-10-12-09.zip
Archive: /var/test_backup/test_backup_2019-10-12-09.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
2085 Defl:N 784 62% 10-12-2019 09:55 e42329a0 test1.sql
2104 Defl:N 801 62% 10-12-2019 09:55 046297a6 test2.sql
-------- ------- --- -------
4189 1585 62% 2 files
测试脚本可以正常备份Docker上的MySQL实例的多个数据库,我们就可以用Linux自带的crontab命令来自动执行脚本。
定期从Docker上部署的MySQL备份数据的更多相关文章
- 【docker】centOS7上部署的mysql和spring boot服务,要求,mysql的时间、java程序服务的时间和宿主机的时间完全保持一致【修改mysql时区,临时和永久】【修改spring boot配置文件时区】【修改docker启动spring boot实例程序时区】
要求:centOS7上部署的mysql和spring boot服务,要求,mysql的时间.java程序服务的时间和宿主机的时间完全保持一致: ============================ ...
- 容器化 | 在 K8s 上部署 RadonDB MySQL Operator 和集群
作者:程润科 数据库研发工程师 编辑:张莉梅 高级文档工程师 视频:钱芬 高级测试工程师 本文将演示在 Kubernetes 上部署 RadonDB MySQL Kubernetes 2.X(Oper ...
- 禅道在docker上部署与迁移
一.禅道部署 1.下载地址 禅道开源版: http://dl.cnezsoft.com/zentao/docker/docker_zentao.zip 数据库用户名: root,默认密码: 123 ...
- MySQL 备份数据那点事
mysqldump 什么是 mysqldump ? mysqldump 是 MySQL 用于执行逻辑备份的一款工具,可以根据原始数据库对象以及表的定义和数据来生成一系列可以被执行的 SQL 语句. 通 ...
- 【集群监控】Docker上部署Prometheus+Alertmanager+Grafana实现集群监控
Docker部署 下载 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.re ...
- 在docker上部署mysql
1.拉取官方镜像5.6的版本.(查看有哪些版本,可以在阿里云的镜像仓库查看,我配置的镜像是阿里云的) docker pull mysql:5.6 2.查看拉取的镜像,获取镜像id docker ima ...
- 在腾讯CentOS7.4云服务器上安装Docker,在Docker上安装配置MySQL、Tomcat和Nginx
提示:以下是在腾讯CentOS7.4云服务器上操作. Docker的基本操作:https://www.cnblogs.com/opsprobe/p/10963098.html 一.安装Docker # ...
- ubuntu16.04环境下在docker上部署javaweb项目简单案例
因为一些原因,接触到了docker,经过一番研究,总算是有了一些自己的看法,有什么不对的地方,希望多多指教. 废话不多说,首先我这里使用的虚拟机安装的是ubuntu16.04版本,其他版本应该也可以. ...
- 【Linux】在docker上部署grafana+zabbix监控实录
------------------------------------------------------------------------------------------------- ...
随机推荐
- Codefroces 920F SUM and REPLACE(线段树)
SUM and REPLACE 题意:给你n个数,进行m次操作,分别是将区间[l,r]内的所有数替换成自己的因子数 和 对区间[l,r]进行求和. 题解:可以发现2的因子个数还是2,1的因子个数还是1 ...
- Codeforces 919D Substring (拓扑排序+树形dp)
题目:Substring 题意:给你一个有向图, 一共有n个节点 , m条变, 一条路上的价值为这个路上出现过的某个字符最多出现次数, 现求这个最大价值, 如果价值可以无限大就输出-1. 题解:当这个 ...
- zoj - 4059 Kawa Exam scc + dsu
Kawa Exam 题解:先scc把图变成树, 然后对于这若干棵树在进行dsu的操作. dsu就是先找到最大的子树放在一边,然后先处理小的子树,最后处理大的子树.无限递归. 重要的一点就是 是否重新添 ...
- hdu 4734 F(x)(数位dp+优化)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734 题意:我们定义十进制数x的权值为f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2 ...
- yzoj P2045 不老的传说 题解
题意 类似于涂色问题,环形问题不多说,断环加倍即可,限制条件if判断就行. 解析 代码 #include<bits/stdc++.h> using namespace std; int n ...
- shell 菜单选择命令
devices=`adb devices | sed '1d;$d' | sed 's/device//g'` */sed '1d;$d' : 删除第一行和最后一行*/ device_ ...
- Spring.Net是怎么在MVC中实现注入的(原理)
本文将介绍Spring.Net(不仅仅是Spring.Net,其实所有的IoC容器要向控制器中进行注入,原理都是差不多的)在MVC控制器中依赖注入的实现原理,本文并没有关于在MVC使用Spring怎么 ...
- 【Redis】发布订阅
一.概述 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. Redis 客户端可以订阅任意数量的频道. 下图展示了频道 channel1 ...
- Python中使用pip安装库时提示:远程主机强迫关闭了一个现有的连接
场景 在cmd中使用pip install moviepy时,需要安装一些依赖库,很长时间后提示: 远程主机中断了一个现有的连接. 原因是默认镜像源下载过慢,将其修改为国内或者设置安装时的源. 这里以 ...
- 使用DevExpress的PdfViewer实现PDF打开、预览、另存为、打印(附源码下载)
场景 Winform控件-DevExpress18下载安装注册以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1 ...