Java(Maven) + Docker + CircleCI + CodecovなCI環境にしたメモ

1年位前に個人で開発していたReluminというRedis Cluster Admin Toolがあるんですが、
久しぶりに新しい機能いれるかってなって、ついでにtest + local env周りのちょっと残念な部分というか手抜きしていた部分を刷新してみた。

github.com (気が向いたら、Relumin自体のエントリもそのうち書こう)

以前の環境

個人で作っていたものだったので雑にVagrantでRedis cluster構築して、開発時とかunit testのときはそのVagrantのRedisに接続してごにょごにょとやっていた。

特にCI toolとかも回さず、手元でmvn testしてそれでいいや、みたいな感じ。

今の環境

Docker

Vagrantを捨てて、Dockerにした。 やっぱり起動早いし、使い捨てとかしやすいし、そのままCircleCIでも動かせたりするっていうのが理由。

Dockerfileはこんな感じ。
relumin/Dockerfile at develop · be-hase/relumin · GitHub

ちなみにやたらとEXPOSEしているけど、

  • 9000
    • meta data保存する用のRedis
  • 10000 ~ 10005
    • Redis Clusterのnode 6台
  • 20000 ~ 20005
    • Redis Clusterのnode間通信用 (gossip通信)
    • これもちゃんとやらないとcluster作れないので注意。ついつい忘れがち。
  • 10010 ~ 10015
    • 普通のRedis。いまのところ使っていない。

という用途です。

慣れでそのままsupervisord使ってしまったが、centos7にしてsystemdとかで良いと思う。

CircleCI

最初は慣れているtravisを使用していたのだけどDocker imageのcacheがうまく出来なくて、途中からCircleCIにした。
毎回docker buildするのは時間かかって辛い。
最近会社でCircleCI Enterpriseが導入されそうっていうのも理由のひとつであったりするし、なによりもsshできるのは良い。

circle.ymlはこんな感じ。
relumin/circle.yml at develop · be-hase/relumin · GitHub

Docker imageのcacheはこのあたりでやっている。

dependencies:
  cache_directories:
     - "~/docker"
  override:
    - if [[ -e ~/docker/image.tar ]]; then docker load -i ~/docker/image.tar; fi
    - docker build -t relumin/relumin-test .
    - mkdir -p ~/docker; docker save relumin/relumin-test > ~/docker/image.tar

参考 : Continuous Integration and Delivery with Docker - CircleCI

ちなみに、
dependencies:overrideでmvn install -DskipTestsしているのは、mavenをcacheさせるため。
もう少し適切なgoalがある気はする。

Codecov

Coverage toolは色々あるけど、Codecovを使ってみた。

Codecovにした理由は、
documentの量とか他のものより多かったし、こっちのほうがUIが好みだったのと、カバレッジサービスのための依存lib(uploadするためのlib)がなかったから。

mavenの場合は、pomにjacocoのpluginを入れるだけで良い。 (jacoco自体は、javaで一般的なカバレッジツール)

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.7.201606060606</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>report</id>
            <phase>test</phase>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>

circle.ymlにこんな風に書いている。

test:
  override:
    - docker run -d --net="host" -p 9000:9000 -p 10000:10000 -p 10001:10001 -p 10002:10002 -p 10003:10003 -p 10004:10004 -p 10005:10005 -p 20000:20000 -p 20001:20001 -p 20002:20002 -p 20003:20003 -p 20004:20004 -p 20005:20005 -p 10010:10010 -p 10011:10011 -p 10012:10012 -p 10013:10013 -p 10014:10014 -p 10015:10015 relumin/relumin-test
    - mvn test jacoco:report -DargLine="@{argLine} -Dspring.profiles.active=ci"
  post:
    - mkdir -p $CIRCLE_TEST_REPORTS/junit
    - find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
    - cp -r ./target/site/* $CIRCLE_TEST_REPORTS/
    - bash <(curl -s https://codecov.io/bash)

mvn test jacoco:report -DargLine="@{argLine} -Dspring.profiles.active=ci"でテストレポートが諸々作成される。
CircleCI上では、Spring bootの"ci" profileで実行したいので-DargLine="@{argLine} -Dspring.profiles.active=ci"を付与している。

jacoco自体もargLineを利用しているため、@{argLine}をつけないと上書きされてしまってjacocoが上手く動かないので注意。 ハマった。

test reportを
find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \
cp -r ./target/site/* $CIRCLE_TEST_REPORTS/
でCIRCLE_TEST_REPORTSに移動することで、CircleCI上のArtifactsで見れるようにしている。こんな感じ。
Continuous Integration and Deployment

最後にbash <(curl -s https://codecov.io/bash)を実行することで、Codecovにtest reportを送信している。

test code自体もがっつり書き直した。
Mockitoで済むところはMocktioだけでいい。全部springかましたtestでやると遅くて辛い。
( springかますのは、最終的なintegrateなtestと、DAOくらいでいいかなと。 )

所感

仕事だとJenkinsでこういったことやってるけど、やっぱりこの手のツールのほうが楽だし簡単。UIも綺麗で嬉しい。