zoukankan      html  css  js  c++  java
  • 定期从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命令来自动执行脚本。

  • 相关阅读:
    微信小程序 --- 获取当前坐标
    微信小程序 --- 缓存数据
    微信小程序 --- 音乐的播放和控制
    微信小程序 --- webSocket
    微信小程序 --- 文件的上传和下载
    微信小程序 --- 选择图片和拍照
    微信小程序 --- loading提示框
    微信小程序 --- toast消息提示框
    Atitit.attilax软件研发与项目管理之道
    Atitit.attilax软件研发与项目管理之道
  • 原文地址:https://www.cnblogs.com/beiluowuzheng/p/11655242.html
Copyright © 2011-2022 走看看