これはFujitsu Advent Calendar 2016の21日目の記事です。
※タイトルについて、申し訳ないですがハウツーではないです。
はじめに
先日、Cloud Foundry Days in Tokyoというコミュニティイベントに参加してきました。
資料はconnpassに公開されていますが、ConcourseというCI/CDツールが度々登場しました。
プロペラマークが目印です。
concourseはよいものですよ #cfdtokyo
— Ken Ojiri (@kenojiri) 2016年11月11日
Cloud FoundryとConcourse CI使っています #cfdtokyo pic.twitter.com/IVR5xjcKcu
— Toshiaki Maki (@making) 2016年11月11日
Circle of code #cfdtokyo pic.twitter.com/GfSnJHROWI
— Toshiaki Maki (@making) 2016年11月11日
今回のイベントで頻出したのはConcourseがCloudFoundryのために作られたCI/CDツールだからという理由もあるでしょう。
ただCI/CDツールと言えばJenkinsというイメージだった私は焦りを覚えてConcourseを触って見ることにしました。
Concourseをとりあえず動かす
Concourseは、ビルド等のタスクの集まりをパイプラインで記述することでビルドパイプラインを実行、可視化してくれるCI/CDツールです。
また、各タスクはDockerコンテナ上で実行されるので再現性の高いビルドが可能となっています。
日本語の資料は少ないですが、以下のサイトがよくまとまっているので、とりあえず動かすのは難しくなかったです(今回はdocker-compose版を使用)。
これで今どきのマイクロサービスを継続的インテグレーションできる気がしてきました。
サービスのテスト
Cinema 3というgithubで見つけた超シンプルなマイクロサービスっぽいものを使わせていただきます。
これは映画予約を想定した4つのマイクロサービスから構成されます。(bookings, movies, showtimes, user)
今回は元のコードから以下の点を変更することにしました。
- 言語:Python2→Python3
- DB:JSONファイル→MongoDB (herokuのMongoDBアドオンを想定)
- リポジトリ管理:
- 1つのリポジトリのサブディレクトリにサービス→1リポジトリ1サービスに分ける。(『マイクロサービスアーキテクチャ』の6章.デプロイ→まとめ記事)
- 新規→リポジトリにciディレクトリを作り、Dockerfile, pipeline.ymlなどのCI資材を管理する。(8 Pro Tips for Using Concourse CI with Cloud FoundryのPro tipsその1)
ということで作ったmoviesサービスがこちら(https://github.com/matsulib/cinema3-movies)です。
以下のコマンドを実行してみると…
$ fly -t lite set-pipeline -p movies -c cinema3-movies/ci/pipelines/pipeline-movies.yml
成功しました。
標準出力、標準エラー出力からテスト結果を確認することができます。
Jenkinsには、xUnit形式で出力したXMLファイルのテスト結果をレポートとして表示できる機能がありますが、Concourseにはないようです。
@DougStephenJr Nope, just stdout/stderr for now. Not sure yet whether we want to integrate with test frameworks vs. delegating to resources.
— Concourse CI (@concourseci) 2016年3月30日
どうしてもレポートを見たい人はタスクの成果物としてレポートをコンテナの外にファイル出力する必要があります。
社内で使う場合
タスクはDockerコンテナ上で実行されますが、タスクが終了するとコンテナは消えてしまいます。
毎回タスクが走るたびに何も入っていないベースイメージからビルド環境を構築するのは無駄なので、必要なものが入ったイメージを予め作っておき、そのイメージキャッシュを利用した方が良いです。(これだけはやっておきたい〜マイクロサービスのデプロイメント - クラウドワークス エンジニアブログ)
例えば上記のmovies-unittestというタスクを実行するコンテナは、今回私が作ったlibmatsu/mongo-python3というDockerイメージから作られています。
---
platform: linux
image_resource:
type: docker-image
source:
repository: libmatsu/mongo-python3
inputs:
- name: cinema3-movies
run:
path: cinema3-movies/ci/scripts/test_runner.sh
このDockerイメージはDockerHubに公開されていますが、そんなとこに公開できないよという環境の人は多いと思います。
そのような場合はPrivate Docker Registryが使えます。その他、社内環境でのConcourseの利用例は以下のリンク先に紹介されています。
- Running Concourse CI on enterprise private cloud【日本語版】
- Nexus RepositoryのDocker Registryを使ってオフラインでConcourse CIを使う - BLOG.IK.AM
リポジトリ管理再考
あとはmoviesサービス以外のサービスも作ってインテグレーションテストしてPaaSにデプロイするだけ、と思ってこんな感じのパイプラインを作ったら問題が発生しました。
エラーが出ているのは無視してください。ところでこのpipeline.ymlはどのリポジトリに管理されているのでしょうか?
例えばmoviesリポジトリのciディレクトリにはmovies用のpipeline.ymlしか含まれていません。
全体用のpipeline.ymlを管理するリポジトリを新たに作るのか、もしくは元のCinema3のように1つのリポジトリにしてサブディレクトリごとにビルドするのか。。
後者の方がすっきりすると思うし、確かにサービスごとにリポジトリを分ける必要はないという意見もあります。
Aを更新したらBとの結合テストをしてからAを更新、Bを更新したらAとの結合テストをしてからBを更新、またはSlackからbotに依頼したらAかBを更新…やりたかったことはこれではないでしょうか。その観点からすると、複数GitレポジトリにそれぞれCIするとか、分散ロックなどはただの手段です。やりたいことをもっと直接的に表現できるツールはないでしょうか。
これだけはやっておきたい〜マイクロサービスのデプロイメント - クラウドワークス エンジニアブログ
ただリポジトリ1つの場合、githubの変更をトリガーにジョブが走る設定だと、あるサービスを変更すると全てのユニットテストが走ってしまってあんまり独立してないなあと若干感じます。
そもそも誰がインテグレーションテストを書くのかという問題もあります。
1つのチームが1つのサービスを作る分には問題ないが、複数のチームが関わると生じる問題と解決案は『マイクロサービスアーキテクチャ』でも繰り返し述べられています。
でも結局は組織論ってお話になりそうです。
おわりに
Concourseを使ってみました。導入は難しくないのでCI/CDツールの選択肢としてはありだと思います。
CI/CDの知識も含めて運用上のベストプラクティスがまとまっていれば良いなと思いました。