使い捨てDockerでビルドテスト Mysqlスキーマが入ったdockerを立上げる テスト衝突を回避する 

今までは、ビルドする度にテストサーバーに繋いでテストをしていたが、開発人数が増えた為衝突が起きる様になりました。
その衝突を避ける為にdockerを使ったテスト環境を作った話です。

私のプロジェクトはgradleで動いています。なのでテスト環境の時のみ、command lineからdocker起動のコマンドを流してもらいます。

build.gradle:

tasks.withType(Test) {
    def dockerName = UUID.randomUUID().toString().replaceAll("-", "")
    exec {
        commandLine './before.sh', dockerName
    }
    System.properties.setProperty("dockerName", dockerName)
    gradle.buildFinished {
        exec {
            commandLine './after.sh', System.properties.getProperty("dockerName")
        }
    }
}

dockerコンテナの名前の重複を避ける為、UUIDを使ってランダムな文字列を生成してもらいます。
ちなみにUUIDの衝突確率は10^-18以下なので殆ど不可能です(’-’を消しているので私の使用上そんなに低くないが)
名前を作ったらbefore.shに引数として渡してコンテナを起動します。

before.sh:

#!/bin/bash -x
docker pull mysql:5.6
docker run -v $PWD/tmp/:/docker-entrypoint-initdb.d --name=$1 -d -e "TZ=Asia/Tokyo" -e MYSQL_DATABASE=test -p 0:3306 -u root -e MYSQL_ALLOW_EMPTY_PASSWORD=yes mysql:5.6

色々引数をつけていますが、起動するローカルポートはランダム、docker内部の3306に紐付けてくれます。
MYSQL_ALLOW_EMPTY_PASSWORDをつけないとrootにランダムなパスワードをつけられます。

    • nameで先程生成した名前を渡し、起動したコンテナの特定に使います。

tmpの中にはあらかじめ用意したMYSQLスキーマが入っています。
docker-entrypoint-initdb.dと言うフォルダにマウントしておくと、中身のファイル(ファイル形式には制限があるが)を起動時に実行してくれます。
ちなみにマウント出来るディレクトリ名にも制限があるので公式ドキュメントをよく見ましょう。
dockerの名前はsystem propertyに渡して、プログラム内部からまたコネクションを立てています。
最後に使い終わったコンテナの削除も忘れないように

after.sh:

#!/bin/bash -x

docker stop $1
docker rm -v $1


以上でdockerコンテナを使い、ローカルでビルドテストが完結します。
やったね