使用Docker为UItesting创build“可恢复”的MySQL数据库

我们有一些seleniumtesting,运行在我们的Web应用程序的生产式设置上。 问题是一些testing在影响数据库的应用程序中做了些什么。

是否有可能拥有数据量或类似数据,以便在每次testing之前“克隆”并附加到容器上?

我们真的只需要一个MySQL数据库,可以在每次testing之前快速重新创build。 偶尔我们会运行模式迁移到该数据库。

还是有另外一种方法可以更适合这个吗?

这是一个很好的问题,对于Docker来说可能是一个很好的用例。 有很多方法可以做到这一点,因为有办法备份MySQL数据库。 我会在下面解释一些。

一般来说,你会碰到的一个问题是,大多数MySQL容器使用/var/lib/mysql (存储数据的地方)的卷。 因此,销毁容器不足以清除数据 – 您还需要清除容量。 所以,当你在做docker rm清除你的旧容器时,通过-v标志去除卷。

选项1:将数据构build到容器中

可以将数据构build到容器中。 这样做的好处是您的容器每次运行不会花时间设置数据 。 这个优势对于需要很长时间才能build立或拆除的大数据集变得更加重要。 换句话说,“重置”这个数据库几乎是瞬间的

在基本的层面上,我们想要这样的东西:

 ADD mysql_data.tar.gz /var/lib/mysql 

这里棘手的部分是创buildmysql_data.tar.gz文件(这只是/ var / lib / mysql的tar.gz备份)。 我们可以这样做:

  1. 用一个空的数据库运行你的容器(我只是使用mysql:latest在这里)。 请注意,我们正在使用一个命名卷,我们正在转发端口3306。

    $ docker run -d --name my-mysql -v my-mysql-data:/var/lib/mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=password mysql:latest

  2. 设置你的数据库。 构build模式并插入所有的testing数据。 假设你有一个数据库备份backup.sql

    $ cat backup.sql | mysql -u root -ppassword -h 127.0.0.1

  3. 停止容器。 我们不希望MySQL运行。 数据将保留在指定的卷中。

    $ docker stop my-mysql

  4. 创build/var/lib/mysql的备份。 请注意,我们正在使用相同的命名卷。

    $ docker run --rm -v my-mysql-data:/var/lib/mysql -v $(pwd):/backup mysql:latest tar czvf /backup/mysql_data.tar.gz /var/lib/mysql

  5. 现在你已经从/var/lib/mysql获得了压缩的数据,在你的Dockerfile中使用它。 请注意,我们需要将它复制到/因为我们压缩它的方式:

    ADD mysql_data.tar.gz /

    如果您还没有Dockerfile,请使用第一行创build一个

    FROM mysql:5.7

  6. (看到它的工作)build立你的Dockerfile到一个包含你的数据的容器图像。 然后运行容器。

    $ docker build -t my-data-image:latest .

    $ docker run -d -p 3306:3306 my-data-image:latest

Docker会自动提取文件作为构build的一部分。 你完成了。 Dockerfile中的容器将始终包含干净的数据。 要“重置”容器,只需停止它并删除它用于/var/lib/mysql

要编辑数据,请重复此过程,但在步骤1中replace现有容器。对于步骤2,请进行更改。 你会产生一个新的mysql_data.tar.gz,如果你喜欢,你可以控制版本。 在重buildDockerfile之后,如果你喜欢,你可以在新的标签下发布它。

选项2:使用docker-entrypoint-initdb.d

MySQL Docker镜像有一个function,当容器首次运行时,它将在/docker-entrypoint-initdb.d运行SQL文件。 这样做的好处是可以使用常规的MySQL转储来创build数据。 缺点是数据库启动比较 ,因为它每次都恢复所有的数据。

如果你在./backup.sql有一个mysqldump的数据,你可以这样做:

 $ docker run -e MYSQL_DATABASE=DB_NAME -e MYSQL_ROOT_PASSWORD=password -d --name my-mysql -v ./backup.sql:/docker-entrypoint-initdb.d/backup.sql -p 3306:3306 mysql:latest 

完成后,请移除容器的容器。

 $ docker rm -v my-mysql 

我将使用一个golang应用服务器和一个mysql数据库的例子,因为这是我的主要用例:

 version: '2' services: app_test: image: golang:1.7-alpine volumes: - ./:/go/path/to/src links: - database_test environment: GOBIN: /go/bin APP_ENVIRONMENT: test APP_DB_HOST: database_test APP_DB_USERNAME: root APP_DB_DATABASE: app entrypoint: - /bin/sh - -c - /go/path/to/src/build_and_test.sh database_test: image: mysql:5.7 volumes: - ./schema/test/auto_tests_structure.sql:/docker-entrypoint-initdb.d/a.sql - ./schema/test/auto_tests_data.sql:/docker-entrypoint-initdb.d/b.sql ports: - "3307:3306" environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_DATABASE: app 

重要的部分是将.sql文件挂载到mysql容器中,该容器自动填充选定的数据库(通过环境variablesMYSQL_DATABASE – 这是官方mysql映像的文档),以及links项目。

运行testing如下所示:

 #!/bin/bash PASSED_ARGS="${@}" docker-compose -f docker-compose.test.yml stop database_test docker-compose -f docker-compose.test.yml rm -vf database_test docker-compose -f docker-compose.test.yml run -e PASSED_ARGS="${PASSED_ARGS}" app_test 

最重要的是前两个docker-compose命令,它们用关联的卷来停止和销毁database-test容器。 然后你运行容器,重新创build它。

至于速度,我不满意,运行Docker for Mac。 但是我的团队中有一个人正在运行linux,对他来说这个速度要快很多。