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