• 定期从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命令来自动执行脚本。

  • 相关阅读:
    快速幂模板
    部分有关素数的题
    POJ 3624 Charm Bracelet (01背包)
    51Nod 1085 背包问题 (01背包)
    POJ 1789 Truck History (Kruskal 最小生成树)
    HDU 1996 汉诺塔VI
    HDU 2511 汉诺塔X
    HDU 2175 汉诺塔IX (递推)
    HDU 2077 汉诺塔IV (递推)
    HDU 2064 汉诺塔III (递推)
  • 原文地址:https://www.cnblogs.com/beiluowuzheng/p/11655242.html
Copyright © 2020-2023  润新知