使用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备份)。 我们可以这样做:
-
用一个空的数据库运行你的容器(我只是使用
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
-
设置你的数据库。 构build模式并插入所有的testing数据。 假设你有一个数据库备份
backup.sql
。$ cat backup.sql | mysql -u root -ppassword -h 127.0.0.1
-
停止容器。 我们不希望MySQL运行。 数据将保留在指定的卷中。
$ docker stop my-mysql
-
创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
-
现在你已经从
/var/lib/mysql
获得了压缩的数据,在你的Dockerfile中使用它。 请注意,我们需要将它复制到/
因为我们压缩它的方式:ADD mysql_data.tar.gz /
如果您还没有Dockerfile,请使用第一行创build一个
FROM mysql:5.7
-
(看到它的工作)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,对他来说这个速度要快很多。