DockerコンテナでSpring Boot + MySQLのテストを動かす
Dockerコンテナ内でテストを動かすことに成功したのでやり方をまとめます。
MySQL + jdk8のイメージを作る
まずはこれがなければ話になりません。MySQL公式イメージのDockerFileにOracle-JDKをインストールする記述を足しました。 MySQL公式イメージはこちら。DockerFileだけじゃなく、docker-entrypoint.shもクローンします。
Debian(jessie)にOracle-JDKをインストールするには以下の通りにやればできます。
あと、こちらも参考にできます。
上記を参考にして作ったjdk8のインストールコマンドをDockerFileに追加するわけですが、ここでハマりポイントがあって、gosuのインストールの後に記述しないと、なぜかjdkのインストールディレクトリが消えます(理由は不明)
DockerFileは下記のようになりました(一部)
FROM debian:jessie MAINTAINER doilux ... ENV GOSU_VERSION 1.7 RUN set -x \ && apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \ ... # ------------------ add jdk ------------------------- # add essentials RUN apt-get update && \ apt-get install -y software-properties-common && \ rm -rf /var/lib/apt/lists/* # add jdk8 RUN echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \ add-apt-repository "deb http://ppa.launchpad.net/webupd8team/java/ubuntu xenial main" && \ apt-get update && \ apt-get install -y oracle-java8-installer && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /var/cache/oracle-jdk8-installer # Define commonly used JAVA_HOME variable ENV JAVA_HOME /usr/lib/jvm/java-8-oracle # ---------------------------------------------------- RUN mkdir /docker-entrypoint-initdb.d ... && apt-get update && apt-get install -y mysql-server="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/* \ ... COPY docker-entrypoint.sh /usr/local/bin/ RUN chmod 777 /usr/local/bin/docker-entrypoint.sh && \ ln -s /usr/local/bin/docker-entrypoint.sh docker-entrypoint.sh ENTRYPOINT ["docker-entrypoint.sh"] EXPOSE 3306 CMD ["mysqld"]
DockerFileができたら、ファイルがある場所で以下のコマンドを実行するとイメージができます。
$ docker build -t jdk8-mysql56:v1 . $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE jdk8-mysql56 v1 a488e97a0d5a About an hour ago 878MB mysql 5.6 cba30fe3cdd4 31 hours ago 299MB mysql latest f0f3956a9dd8 31 hours ago 409MB debian jessie ce40fb3adcc6 3 days ago 123MB ubuntu 16.04 0458a4468cbc 3 weeks ago 112MB
コンテナで実行するシェルを作る
PROJECT_ROOTに以下のようなシェルを作りました。
#!/bin/bash SCRIPT_DIR=$(cd $(dirname $0); pwd) cd $SCRIPT_DIR service mysql start mysql -u root << EOF create database hr; create user 'hr'@'127.0.0.1' identified by 'hr'; GRANT ALL PRIVILEGES ON hr.* to 'hr'@'127.0.0.1'; FLUSH PRIVILEGES; EOF ./gradlew clean test
コンテナを起動するときにこのシェルを指定して動かします。 やってることはMySQLを起動して、rootユーザーでDBとhrユーザーを作り、テスト実行するという感じです。
ここでもハマりポイントがあって、DockerFileにはCMD ["mysqld"]と書いてますが、ここではservice mysql startと記述しています。 コンテナ作成後にコンテナに接続してmysqldコマンドを実行してもなぜか動きません(run_test.shでも同様、これも理由は不明)
コンテナを実行する
以下のコマンドでテストを実行できます。
docker run \ --rm \ -v $HOME/.gradle:/root/.gradle \ -v $PROJECT_ROOT:/lib/modules \ -e MYSQL_ROOT_PASSWORD=password \ -it jdk8-mysql56:v1 /lib/modules/run_test.sh
-vはホストOSのディレクトリをマウントしていて、$HOME/.gradleはホストにキャッシュしたライブラリが置かれています(これをマウントしないとテストするたびにjarファイルをダウンロードしてくるので通信がやばい)$PROJECT_ROOTはrun_test.shを実行するためにマウントしています。--rmをつけているのでテストが終わったらコンテナは削除されます。ちなみに、イメージ名の後にコマンドを記述した場合は、DockerFileのCMDは上書きされるようです(参考: [docker] CMD とENTRYPOINT の違いを試してみた - Qiita)
IDEでテストする
IDEでテストする度にコンテナを起動するのは非効率的な気がします。なので、その場合はコンテナをバックグラウンドで起動しっぱなしにして、テストするのがいいと思います。
docker run \ -p 3306:3306 \ -e MYSQL_DATABASE=hr \ -e MYSQL_USER=hr \ -e MYSQL_PASSWORD=hr \ -e MYSQL_ROOT_PASSWORD=password \ -d jdk8-mysql56:v1 # 終わったら以下のコマンドでコンテナを停止&削除 docker stop <<CONTAINER ID>> docker rm <<CONTAINER ID>>