Gebでインフラをテストする。

Geb Advent Calendar 2016 - Qiitaの12日目エントリーです。

qiita.com

先日の「JJUG CCC 2016 Fall」で「実録Blue-Green Deployment導入記」というテーマで発表しましたが、その中でインフラ観点でのシステムテストにGebを活用した事例の紹介をしました。

インフラのテストの観点の特徴としてあげられるのは、最終的な動作の確認をアプリケーション層に依存することがあげられます。

  • 設定ファイルの項目の確認
  • アプリケーションのプロセスが起動しているかの確認
  • ヘルスチェックのURLにアクセスして行う疎通の確認
  • サーバーおよびネットワーク機器間の疎通の確認

という観点まではServerspec等を用いたテストが可能ですが、それより上位レベルの観点はデプロイしたアプリケーション上の動作で確認することになります。

このような場合、インフラ側のテスト担当者が

  • アプリケーション側の機能ドキュメント、テストケース一覧
  • 過去のインフラ観点でのテストケース
  • インフラ側のテスト担当者の勘

などを参照して、テストケースを作成します。

ですが、

  • アプリケーションの規模
  • サーバーやネットワーク構成
  • 外部との連携先

などの構成が複雑になるにつれ、インフラのテスト担当者がアプリケーション観点でテストケースを作成することへのハードルはあがってきます。

また、この事例で取り上げたシステムの場合、システムが

  • 「エンドユーザーからのアクセスを受け付けるモードか」(主系)
  • 「動作確認のためのアクセスを受け付けるモードか」(副系)

の二つのモードをもっており、その結果として

  • Blueサーバーが主系の場合のBlueサーバーへのアクセス
  • Blueサーバーが主系の場合のGreenサーバーへのアクセス
  • Greenサーバーが主系の場合のGreenサーバーへのアクセス
  • Greenサーバーが主系の場合のBlueサーバーへのアクセス

で、一つのテストパターンについて、都合四通りのテストの組み合わせを実施することになりました。

そこで、この事例ではアプリケーションの観点から見たインフラのテストについて、全面的にアプリケーションの開発チームがGebによって作成したエンドツーエンドのテストを使用することになりました。エンドユーザー側から見た、アプリケーションの機能および外部サービスへの連携について、構築した環境上でGebによるエンドツーテストを実行し、その結果を確認することで、インフラ観点でのシステムテストを行うわけです。

このことによって、

  • テストケースの作成コストの削減
  • テストケースの網羅度、信頼性向上
  • 組み合わせでテストを実行する場合の、実行コスト削減

という効果を得ることができました。

エンドツーエンドのテストを実装する場合、その効果はアプリケーションを開発する側のアプリケーションの修正に関わるコストの範囲内で語られがちです。しかし、エンドツーエンドの自動テストである程度の網羅性を担保することによって、インフラ側のテストの効率や精度の向上にも寄与することができる、というのが今回の事例で得られた知見です。

テスト自動化あれこれ

ソフトウェアテスト Advent Calendar 2016 - Qiitaの9日目エントリーです。

qiita.com

エラーが「自動的に」増殖するのがDevOps

継続的デリバリーの核心は、フィードバックのサイクルを素早く回すことにありますが、それはユニットテストカバレッジが十分になければ不可能です。 A/Bテスト、オートスケール、カナリヤテスト、Blue-Green Deploymentなど、DevOpsを推進する上での各種プラクティスは、いずれも、プロダクトの品質が安定していることを前提としています。品質が安定していない状態でリリースサイクルを早く回してもバグが素早くデリバリーされるだけです。

サービス開発は、開発者だけで行うものでなく、プロダクトオーナー、QAエンジニア、インフラエンジニア、運用エンジニア、リモート開発チームなど、多数のステークホルダーが協調して行うものです。チーム相互の信頼をもたらすために必要なのは安定したプロダクトの品質であり、継続的インテグレーション(CI)を軸としたデリバリーのワークフローの確立のためには、自動化されたテストが足場として必要です。

迅速なサービス開発の手助けにならない自動化テスト

翻って現場に目を向けたときに、最近複数の現場で見聞きするのは、

  • 必要とするミドルウェアや連携先サービスとの関係でテストがモックだらけになり、ユニットテストの可読性や保守性があがらない
  • それを補完すべくエンドツーエンドのテストに取り組んでいるが、テストケースが増えてきてメンテナンスコストや実行コスト(時間)が増大している

というものです。各種パブリッククラウド上でのサービス構築に代表されるように、システムを構築し、テストを実装するときに依存するサービスやミドルウェアが増えたこと、そしてマイクロサービスアーキテクチャーがその流れを加速しています。

それに対して、テストをはじめとして開発の方法論はいわゆる三層アーキテクチャーにいまだに最適化されており、そのことが自動テストの普及の妨げになっています。

テスト自動化ピラミッドとサービステスト

Mike Cohnは書籍「Succeeding with Agile」の中で、テスト自動化の戦略をレイヤーを「UI」「Service」「Unit」の3つに分類し、「テスト自動化ピラミッド」と命名しています。「Unit」の層はいわゆるユニットテストに相当し、「UI」の層はエンドツーエンドのテストに相当します。このピラミッドの特徴は「Service」の層にあって、アプリケーションのインターフェースに対するテストを、UIを迂回して実行することです。

Succeeding with Agile: Software Development Using Scrum (Addison-Wesley Signature Series (Cohn))

Succeeding with Agile: Software Development Using Scrum (Addison-Wesley Signature Series (Cohn))

f:id:setoazusa:20161208200716p:plain

*1

このピラミッド自体は一種の概念モデルですが、Sam Newmanは書籍「マイクロサービスアーキテクチャ」の中でこのモデルに着目しています。

マイクロサービスアーキテクチャ

マイクロサービスアーキテクチャ

マイクロサービスアーキテクチャーにおけるサービステストとは、外部のサービス呼び出しをモック化した上で、個々のサービスの機能に対して、UIを迂回してテストを実行します。このことにより、ユニットテストよりも広い範囲をカバーするテストを、エンドツーエンドのテストよりも安定かつ高速に実行できることを目指しています。

f:id:setoazusa:20161208200648p:plain

*2

まとめ

方向性としては、システムのコンポーネント間の関係、規模など、複雑度が増大するに伴い、自動化されたテスト、手動で行うテスト双方とも、レイヤーの分割を細かくして、テストのどこのレイヤーでどの品質を担保していくかを事前に設計した上で開発に望んでいくということになります。我が国では業界の生い立ちや歴史的背景から、ソフトウェア開発の職種とソフトウェアテストの職種の相互交流はまだはじまったばかりですが、開発エンジニアとテストエンジニアが共通の言語で会話しながら、システムの品質に対する責任を相互で分担できる未来が来ることを望みます。

*1:Mike Cohn(2010)「Successiding with Agile」312ページより

*2:Sam Newman著(2015)・佐藤直生監訳「マイクロサービスアーキテクチャ」160ページより

JJUG CCC 2016 FallでBlue-Green Deploymentの導入について発表しました #jjug_ccc

2016/12/3に開催されたJJUG CCC 2016 Fallで「実録Blue-Green Deployment導入記」というテーマで発表しました。

講演中でもちょっと触れたとおり、案件での事例に特化したセッションですので、皆様の現場で一般的に使えるノウハウではないかもしれません。

ですが、セッションで挙げた三つのテーマである

  • サイトの切替にDNSを使う場合の接続元クライアントの挙動の制御
  • データベースの取扱い
  • Blue Greenの稼働系を切り替える場合の切り替え手順の考慮

については、サービス無停止でリリースを行う上で、どこでも考慮が必要になるポイントだと考えています。

質疑応答で、「Blue-Greenの切替時に処理途中で処理する稼働系が切り替わるようなケースがないのか?」という質問がありましたが、この事についてうまく回答ができなかったので、この場で補足をいたします。

例えばGreenサーバーに新しいバージョンをデプロイしてBlueサーバーからGreenサーバーに稼働するシステムを切り替える場合、Greenサーバーではセッション中で説明した通り、テスト用のグローバルIPアドレスを使って動作確認済み(スライド内で「副系」と読んでいるもの)ですので、Blueサーバーへのリクエストが途中でGreenサーバーに乗りかわるのは問題ありません。問題となるのは、Greenサーバーへのリクエストが途中でBlueサーバーに移行するようなシーケンスが発生すると、機能的に一個前のバージョンとなりますので、例えば呼び出し先のAPIがないなどの問題が発生します。

このことに対応するために、切替元となるBlueサーバーの随時バッチが起動するサーバー(スライド中の「データ連携サーバー」と呼んでいるもの)のプロセスを切替時にいったん停止する手順を入れています。(発表スライド中の以下のページなります。)このことによって、切替時にGreenサーバー(切替先)へのリクエストが途中でBlueサーバー(切替元)に乗り変わることを防いでいます。

スライドの最後で「日本のDevOpsはSIがリードする」なんていう大風呂敷を広げましたが、これについて。各種ソーシャルメディアで現場に対するネガティブな面を振りまくのは言論の自由の範疇ですが、最近、何か事をなし得たというエントリーに対して、揚げ足を取ったり話の腰を折ったりするコメントが多すぎます。ストレスの捌け口というのも必要でしょうし、キャリアの浅さやスキルの至らなさで自分のやりたいことが実現できない現場にいる方もいらっしゃるでしょうが、もうすぐ40代の自分たちの世代は、現場と業界をどうやればよりよくできているかが求められる役割なので、それが後の世代への責任ではないのかと。自分が2年前のJJUG CCCで言った「ミッションを共有するする仲間が集うコミュニティーで、プログラマーが一人一人知恵を持ち寄り、議論し、勇気づけるときに、世界はかわる、そう思う。」を、自分はまだ取り下げるつもりはないです。

JJUG CCCが終わって感想ですが、ここ2年ばかりかかり切りだった案件の成果を世に発表できたので、今は安堵しているところです。

最後になりますが、

  • 発表の機会をいただいたJJUGのみなさま
  • スライドのレビューをいただいたプロジェクト関係者
  • 発表リハサールに立ち会っていただいた弊社同僚

以上のみなさま、ありがとうございました!

JJUG CCC 2016 FallでBlue-Green Deploymentの導入事例について登壇します。

2016/12/3にベルサール新宿グランド コンファレンスセンターで開催されるJJUG CCC 2016 fallで、10:00からG+H会場で「実録Blue-Green Deployment 導入記」で登壇します。

www.java-users.jp

JJUG CCC 2014 Fallのセッション「私がTDDできないのはどう考えてもお前らが悪い!~エンタープライズJava開発でのTDD適用の勘所~」で事例として取り上げたサービスのその後についてです。ユーザーの拡大に伴いサービス無停止でのリリースに取り組む事になり、TDDの推進をミッションとしてプロジェクトに参画した発表者はデプロイの自動化、そしてインフラ運用を担当するようになりました。

疎結合アーキテクチャーのシステムを、サービス無停止でリリースできるように作り替える上でサブシステム相互の連携をどう作り込むのか、DNSロードバランサーの挙動にあわせて稼働系システムの連携をどう作り込むか、そしてその中でテストの自動化がどう役割を果たすか。最終的にBlue-Green Deploymentになるまで1年以上に及び、今なお改善をつづけているインフラ運用の実態について発表します。

構成は「GSLB(Global Site Load Balancing)によるサイト切替」「Blue-Green Deploymentにおけるデータベースの扱い」「Blue-Green Deploymentにおける実装及び運用上の留意点」になる予定です。朝早い時間帯ですが、Blue-Green Deploymentの導入について興味がある方は是非お越しください。

同時上映のid:syobochim さんと @_Dr_ASAさんによる「SIerもはじめる、わたしたちのDevOps」もお楽しみに!

Bambooとdocker-composeの連携について

このエントリーは、Atlassian Advent Calendar 2015 - Qiitaの7日目のエントリーです。

docker-composeによるCI環境上でのコンテナー間の連携

昨日のAtlassian Community Day 2015 | Peatixで、弊社グロースエクスパートナーズより、「Atlassian Summit 2015でのDevOps関連の取り組みについて」というテーマで講演致しましたが、その中で取り上げたdocker-composeの連携のデモについてこのエントリーでは紹介します。

CI界隈では「ポータブルなビルド」という言い方がされます、これはビルドをするために必要な環境の情報をDocker等を使用して構成管理の下に置くことで、ビルドの環境をBambooやJenkinsなどのCIサーバー上の環境とは疎結合にして、ビルドの独立性、安定性、スケーラービリティーを得ることを目的にしています。

コンテナー上でビルドを行う際に、ビルドのプロセスが単独で完結していればいいのですが、データベースなどの外部のサーバープロセスとの連携が必要になる場合もあります。そのための方法はいくつかありますが、ここではdokcer-composeを用いてコンテナ間の連携を行います。

このデモはAtlassian SummitのSummit 2015 - Docker, Continuous Integration, and You | Atlassianというセッションで紹介されたものの改良版で、外部コンテナーとしてPostgreSQLとElasticsearchを起動して連携しています。

デモレポジトリについて

デモに使ったレポジトリFork元に比べて

  • DockerのPostgreSQLイメージスキーマ初期化の仕様がかわったのでそれの対応
  • デモが作成された当時はdocker-composeがDockerに統合されておらずfigだったため、fig.ymldocker-compose.ymlにリネーム
  • 依存ライブラリを毎回ダウンロードしていてビルドに時間がかかるので、ローカル環境でキャッシュするようにした

という点に手を加えています。

Bambooの設定について

Bambooは以下のような構成になっています。

f:id:setoazusa:20151207124052p:plain:w200

docker-compposeのセットアップ

まずGitからコードを取得した後の、最初のステップはdocker-composeのセットアップになります。予めBambooサーバー上にdocker-composeがセットアップされている場合は不要です。

f:id:setoazusa:20151207133538p:plain

curl -L https://github.com/docker/compose/releases/download/1.2.0/docker-compose-Linux-x86_64 > docker-compose

chmod +x docker-compose

ディレクトリの初期化

次のステップは依存性をキャッシュするディレクトリの初期化になります。 f:id:setoazusa:20151207124221p:plain:w300

mkdir -p target/.m2
mkdir -p target/.lein

docker-composeによるビルド

f:id:setoazusa:20151207124324p:plain:w300

set -x

sudo ./docker-compose kill 
sudo ./docker-compose rm --force
sudo ./docker-compose build
sudo ./docker-compose up

この中では、docker-compose.ymlの設定にしたがってelasticsearchPostgreSQLのイメージを起動し、次にDockerfileに従ってアプリケーションのビルドを行っています。この際に、EXPOSEしているポートがオープンになるのとサーバーのプロセスがreadyになるのにタイムタグがあってたまにビルドがこけるので、ポートをポーリングするスクリプトを使ってコンテナの中のポートが立ち上がるのを待つようにしています。

ビルド結果の取得

f:id:setoazusa:20151207125734p:plain:w300

CID=`sudo ./docker-compose ps -q transfer`

sudo docker cp ${CID}:/code/testreports.xml .

sudo chown bamboo:bamboo testreports.xml

sudo docker cp  ${CID}:/home/transfer/.m2 target/

sudo docker cp  ${CID}:/home/transfer/.lein target/


sudo chown -R bamboo:bamboo target/

後処理としてDockerからテスト結果のxml(JUnit形式)ならびに依存性キャッシュをコンテナーからコピーする段取りになります。ここでコンテナーから取得した依存性のキャッシュを次回のビルドの時に戻すことによって、ビルド時間を節約しています。

テスト結果のパース

f:id:setoazusa:20151207130108p:plain:w300

前のプロセスで取得したテスト結果(testreports.xml)をここでパースしています。

CleanUp

f:id:setoazusa:20151207130302p:plain:w300

sudo ./docker-compose kill
sudo ./docker-compose rm -f

ここはコンテナの後始末になります。

ビルド結果

f:id:setoazusa:20151207130606p:plain:w400

はまりどころ

  • PostgreSQLのDockerイメージの仕様変更でビルドが走らなくなっていたため、発表の前日にデバッグしていたこと
  • Macbook ProVagrant上でBamboo+Dockerを動かしていたのですが、最初CPU×2、メモリ2Gにしたらelasticsearchにリアルタイム連携しているところが間に合わなくてテストがfailしたこと。CPU×3、メモリ4Gにしたら動いた。

最後に

Bamboo+docker-composeによるCIビルドの例でした。Atlassian Summitの事例報告と言うことでBambooを使った発表になりましたが、Bambooの特定機能には依存していないので、CIサーバーでのDockerの使用例の一つとしてみていただければと思います。

しょぼちむにテストファーストについて説明してみる

このエントリーは、ソフトウェアテストあどべんとかれんだーの11日目*1ならびに、しょぼちむ Advent Calendar 2014 - Adventarの19日目エントリーです。

最初は、JJUG CCC 2014 Fallの懇親会の時に、「しょぼちむでTDD」というオーダーを受けていたので、

describe "しょぼちむ財布もってる?" do
   let (:she) { FactoryGirl.build(:syobochim) }
   it { expect(she.answers).to eq "はい" }
end 

...というのを題材に、TDDを説明してみようとおもったのですが、specがどうやっても緑にならないため*2思いのほか話が深まらないため、TDDの中の重要な要素、テストファーストについてお話ししたいと思います。

JJUG CCCのセッションの中で、「テストファーストにこだわらない」とことに言及させてもらいましたが、

実際にTDDを進めていく中で私がテストファーストを軽視しているかというとそうではなくて、むしろ重視しています。それについては直後にこう呟いた通り。

というわけで、このエントリーでは、TDD、ひいてはソフトウェアテストの中で、「テストファースト」がなぜ重要かということについて、書きたいと思います。しょぼちむはどうしたということに関しては、このアドベントカレンダーでは、↓のような話もあるし、まあいいんじゃね?

実務的な話

私がプログラマーとして、なぜテストファーストに拘るかですが、率直なことを申せば「テストファーストしてないテストは怖い」です。

テストそのものをソフトウェアコンポーネントとして捉えた時に、テストに求められている機能は、テスト対象(SUT)が意図している時に成功(Green)となり、そうでない時に(Red)となること、即ちテスト自身がテストの結果を判断できることです。

この観点から見た時に、テストファーストしてないテストの弱点は、テストを失敗させていないため、テストの信頼性がその分下がるということです。これはTDDの「まず失敗させるテストを書く」プラクティスに乗っ取ることができないためです。このことを差して、JJUG CCCのセッションでは「失敗していないテストのカバレッジは50%しかない」と表現しました。

「どのようにテストを成功させるか」と同じくらい、「どのようにテストを失敗させるか」ということは重要です。どのような条件を満たすとテストが緑になり、どのような条件で赤になるかということを明確にすることで、テストは品質を支える基盤として必要な堅牢さを得ることができます。

Testing と Checking

ソフトウェアテストには、対象のシステムを探索し、学び取る(Learing)Testingとしての側面と、アサーションが通るか、失敗するかを判断するCheckingとしての側面があります。ユニットテストに代表される、開発者のテストは、Checkingに軸足を置いています。

ソフトウェアを開発していく上で、Checkingとしてのテストの果たす役割は、どのようにステップを踏んでいけばゴールに到達できるかということを差す、道しるべとしての役割です。そして、テストが道しるべとしての役割を果たすためには、プロダクションコードを書く前に、Checkingとしてのテストをチェックポイントとして置いておく必要があります。

システム開発の工程の中では、ユニットテストだけでなく、結合テストシステムテスト、非機能要件のテストなど、様々な粒度のテストを行います。その中でのシステムテストは「指定された要件を満たすことを実証するため」に行いますが、システムテストの段階でシステムが「要件を満たしていない」ことが明らかになっても手遅れです。システムが要件を満たすことを確認するためには、上位レベルのテストのCheckする内容と、ユニットテストなどの下位テストのレベルがCheckする内容がお互いに関係を持ち、内容を補完し合っていて、テストの工程を回す中でフィードバックループを適切に回す必要があります。そして上位レベルのテストと下位テストのレベルが連携するためには、V字のモデルを描く必要があるので、やはりテストは先に作成されるべき、ということになります。

ではどうすればいいか

要は、システムを完成させるために、どうステップを踏んで、ゴールに近づいていくかです。その中でテストファーストを導入できるレベルにあれば、導入すればよいし、テストファーストを導入できる段階でなかったとしても、End to Endレベルの試験項目は先に作成するなど、システム開発工程全体の中で、Checkingする工程を適切にまわせていけばいい、ということになります。

ただ、IT技術者として、持っている手札の数は多い方がいいと思いますので、写経等で、テストファーストの考えに触れてみることは、非常に有益だと思いますので、お勧めします。

しょぼちむアドベントカレンダー、明日のエントリーはfukai_yasさんです。

*1:今日は何日だって話ですが...ごめんなさいごめんなさいm(__)m

*2:仮実装でこっちから財布わたせばいいんですかね...?

MyBatis MigrationsとBambooとSchemaSpyでデータベースの構成を管理する

このエントリーは、ゆかむアドベントカレンダー - ゆかむ | Doorkeeperの7日目エントリーです。

はじめまして。@setoazusa です。こんなハンドルですが、男性です。 都内のSIerで、TDDの導入や、DevOpsの推進、プロジェクトメンバーのフォローなどを仕事にしています。 IT技術者のコミュニティでは、TDDBCなどのコミュニティなどを中心に活動しています。よろしくお願いします。

ゆかむさんとは、第2回 ゆかむ勉強会 - connpassで、「CIサーバーとSchemaSpyでデータベースのドキュメント作成を自動化」というお題で話をさせていただきました。

今日は、その話の続きで、データベースのスキーマ管理のために、ツール同士をどう連携させているかという話をします。

データベース管理のあるある

このエントリーをご覧になっているみなさんは、リレーショナルデータベース(RDB))を使ったシステムの開発に従事されている方が多いと思います。その中で、このようなことに遭遇した方はいらっしゃらないでしょうか?

  • テーブル設計書と実際のテーブルの内容がずれている
  • ステージング環境と本番環境でテーブルのカラム構成が違う
  • 「テーブル設計書最新20141201.xls」
  • テーブル設計を変更するのにやたら手間がかかる

バージョン管理、コードの共同所有、ドキュメンテーションなどの開発のベストプラクティスがデータベース設計については適用されないことを、書籍「SQLアンチパターン」では「ディプロマティック・イミュニティ(外交特権)」と命名しています。

SQLアンチパターン

SQLアンチパターン

上記の問題に対応し、ローカル環境と開発環境とステージング環境と本番環境それぞれの構成管理をスムーズにするために、このエントリーでは、MyBatis MigrationBamboo、そしてSchemaSpyを使って、データベースの構成管理を行う時の流れを取り上げます。

説明に使っているデータベースの構成

RDBMSPostgreSQLで、データベースは、ローカル環境用*1、CI用、ステージング、商用環境の4つがあります。

テーブルはOracleのサンプル等でお馴染みのHRのスキーマーで、empテーブルが先に出来ている想定です。

f:id:setoazusa:20141207233251p:plain

1. MyBatis Migrationsでテーブル定義を変更する

まず、MyBatis Migrationsでマイグレーションを作成します。(MyBatis Migrationsそのものや環境の構築方法についてはMyBatis Schema Migrationを使ってみる - @katzchang.contextsDB Migration 入門 vol.1 #CDStudy を開催しました。 — うさぎ組を参照ください。このエントリが好評だったら環境構築やディレクトリ構成について追加エントリを書く。かも。)

C:\Users\azusa\git\migration\migration>..\bin\migrate new "create dept table"
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
------------------------------------------------------------------------
-- MyBatis Migrations - new
------------------------------------------------------------------------
Creating: 20141207150330_create_dept_table.sql
Done!

------------------------------------------------------------------------
-- MyBatis Migrations SUCCESS
-- Total time: 1s
-- Finished at: Mon Dec 08 00:03:30 JST 2014
-- Final Memory: 7M/479M
------------------------------------------------------------------------

C:\Users\azusa\git\migration\migration>

なお、migrate newコマンドの引数として渡す文字列には日本語も使えますが、渡した引数は上の出力を見て分かるとおり、マイグレーションのファイル名にそのまま使われます。バージョン管理がGitで、MacOSの開発環境がある場合、ファイル名に濁音や半濁音が混じった場合に、LinuxWindowsの環境上で、見た目が同じファイル名のファイルが2つできるという問題があるため*2、コマンドの引数として渡す文字列はAsciiの範囲に留めるほうが無難です。

migrate newコマンドで作成したファイルを、以下の通り編集します。

C:\Users\azusa\git\migration\migration>vim scripts\20141207150330_create_dept_table.sql
--// create dept table
-- Migration SQL that makes the change goes here.

CREATE TABLE dept
(
  deptno numeric(2,0) NOT NULL,
  dname character varying(14),
  loc character varying(13),
  versionno numeric(8,0),
  active numeric(1,0),
  CONSTRAINT dept_pkey PRIMARY KEY (deptno)
)
WITH (
  OIDS=FALSE
);

COMMENT ON TABLE dept IS '部署';
COMMENT ON COLUMN dept.deptno IS '部署番号';
COMMENT ON COLUMN dept.loc IS '地域';
COMMENT ON COLUMN dept.versionno IS 'バージョン番号';
COMMENT ON COLUMN dept.active IS '有効';



--//@UNDO
-- SQL to undo the change goes here.

DROP TABLE dept;

MyBatis Migrationsではマイグレーションの定義をSQLで行うため、マイグレーションのファイル中にはcreate文やalter文等のDDLを直接書きます。

マイグレーションを作成したらmigrate upコマンドでローカル環境に適用します。

C:\Users\azusa\git\migration\migration>..\bin\migrate up
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
------------------------------------------------------------------------
-- MyBatis Migrations - up
------------------------------------------------------------------------
========== Applying: 20141207150330_create_dept_table.sql ======================

------------------------------------------------------------------------
-- MyBatis Migrations SUCCESS
-- Total time: 0s
-- Finished at: Mon Dec 08 00:22:02 JST 2014
-- Final Memory: 12M/479M
------------------------------------------------------------------------

ローカル環境にデータベースが作成されます。

f:id:setoazusa:20141208002314p:plain

2. Bambooによるデータベースのマイグレーション

ローカル環境での確認が完了したら*3、Gitレポジトリにpushします。

f:id:setoazusa:20141208002448p:plain

Gitレポジトリマイグレーションがpushされると、連携しているBambooでビルドが実行され、CI用の環境にデータベースの変更が適用されます。

f:id:setoazusa:20141208003612p:plain

f:id:setoazusa:20141208015253p:plain

この時に、Bamboo上でSchemaSpyスクリプトを呼び出して作成したドキュメントをArtifacts*4として保持していますので、Bambooのビルドに対応するドキュメントを下記のリンクからたどれるようになっています。

f:id:setoazusa:20141208004037p:plain

リンクをたどると、以下の様なドキュメントを参照できることができます。出力したドキュメントのイメージはSchemaSpy - d66vta52qi8mtp.publicから参照することができます。

f:id:setoazusa:20141208004816p:plain

なお、SchemaSpyでドキュメントを作成すると、SchemaSpyの作者のアカウントでgoogleadsが挿入されるのですが、それを出さないようにするにはSchemaSpyの実行時に-noadsオプションをつけます。

Bembooによるデータベース構成のデリバリー

さて、ここまでだと「それJenkinsでもできるよ」という感じなのですが、Bambooの色が出るのはここからです。ビルドのサマリー画面に「Create release」というボタンがあるので、それをクリックします。

f:id:setoazusa:20141208010702p:plain

Bambooには「リリース」という概念があり、任意のビルド結果に名前をつけて、任意の環境にデプロイできるようになっています。

f:id:setoazusa:20141208011046p:plain

リリースを作成すると*5、Bambooのリリースを管理する画面に遷移し、そこから任意の環境にデプロイができるようになっています。ここではステージング環境にデプロイします。

f:id:setoazusa:20141208011204p:plain

f:id:setoazusa:20141208011435p:plain

f:id:setoazusa:20141208014543p:plain

f:id:setoazusa:20141208012001p:plain

そして、ステージング環境での動作確認がOKだったら、ステージング環境で動作確認済みのマイグレーションスクリプトをそのまま本番環境にデプロイすることができます。*6

f:id:setoazusa:20141208011829p:plain

f:id:setoazusa:20141208012110p:plain

f:id:setoazusa:20141208014652p:plain

f:id:setoazusa:20141208012218p:plain

Bambooによるトレーサビリティーの確保

そしてBemboo上で、今データベースに適用されているスキマーがどのビルドで作成されて、バージョン管理のどのコミットが含まれているのかをトレースできるようにあっています。

すなわち、現在の本番環境やステージング環境のスキーマーの状態と、SchemaSpyによって作成されたドキュメントの間で、常にトレース出来る状態になっているということです。

f:id:setoazusa:20141208012724p:plain

f:id:setoazusa:20141208012840p:plain

まとめ

MyBatis MigrationsとBambooとSchemaSpyでデータベースの構成を管理する際の方式についてまとめました。Jenkinsに比べると地味な存在なBambooですが、デリバリーのためのワークフローをプラグインなしで構築できるということに関しては一日の長があるんです、やれば出来る子なんです><

今回の手順ではバージョン管理には、Stashを使用していますが、その部分はGitHubやgitbucket等、他のバージョン管理システムとも組み合わせることができます。MyBatis MigrationsやSchemaSpyについては独立したツールですので、その環境構築の実際や、Bambooの設定で行っていることについては、機会があればまとめたいと思いますので、このエントリーについてのフィードバックお待ちしています!

*1:実際にはVagrantを使用して開発者個人の環境にそれぞれデータベースがある想定です

*2:クライアントの設定で回避できるのですが、1台でも設定をしてないクライアントがあると全クライアントに影響がおよびため、筆者のプロジェクトではGit管理下で日本語をファイル名として扱うのは諦めました...

*3:実際には、データベースに関連付いているアプリケーションのコードベースが、pushできる状態になったら

*4:Jenkinsと同一の概念

*5:ここではリリースを作成→デプロイという流れを分かりやすくするために手動でリリースを作成していますが、Bambooのビルドが成功した段階で自動でビルドを作成し、デプロイを即実行することもできます。

*6:それにしても、データベースマイグレーションのデモをするときの「ほら、ここにテーブルが出来てます!」「...で?」という流れはどうにかならいんですかね、裏で色々頑張ってるんですけど...