読者です 読者をやめる 読者になる 読者になる

GitHubを使った複数人でのスキーマ管理 on Rails

要約

Chefみたいなスキーマ管理ツールRidgepole)を使うと、GitHubを使ったワークフローでスキーマを管理できる(と思います、たぶん)

RailsMigrationsについての問題提起

Migrationsは便利な仕組みですがベストではないと常々思っていました。 具体的には、特定のマイグレーションを保留にしにくいとか、複数人で作業するとコンフリクトすることがあるとか。

大きめのRailsプロジェクトだと特別なワークフローを用意して解決しているんですかね…声出して行こうぜ!とか。

Chef的スキーマ管理ツール: Ridgepole

https://github.com/winebarrel/ridgepoleデモ

以前からそのようなそのような問題意識があって、たぶん Chef的な冪等性保証する(操作ではなく定義を書くたぐいの)ツールがあれば解決できそう、でも実際作るの大変そうだなぁ…と思ってたんですが、現実逃避の負のパワーによって案外あっさり実装できました

RailsDSLスキーマを定義してそれを食わせると、その通りにスキーマを変更してくれるツールです(カラムが追加されたらadd_columnを実行とか)。冪等性を保証してるので、定義とスキーマに差異がなければなにも変更は行いません。

まだ実戦投入には至ってなくて、テスト追加したり投入の準備をしたりしているという段階なのですが、たぶおおむね問題なく動くと思います。

GitHub+Ridgepoleのワークフロー

さて、Ridgepoleを使って何が一番うれしいかと言えばスキーマ管理のワークフローにGitHubのPull Requestを使えるところだと思います。 具体的には、

  1. 開発者がスキーマリポジトリをフォーク
  2. カラムを追加するなりインデックスを追加するなりスキーマ定義を変更し、ローカルのDBに適用
  3. 変更をPull Requestとして投げる
  4. Pull RequestはCIでテスト(テスト用のDBを立ち上げてそこに適用とか…)
    • サービスを止めかねない重い変更はこれで弾けるはず…
  5. 運用担当者がテスト結果をみてマージ→本番に適用

なんとなく僕らの未来感があってかっこいい気がしてます。

もし、開発用のDBが共用されている場合はRidgepoleの--mergeというコマンドを使えば『カラム・インデックスの削除を行わないでファイルの変更を適用する』ということができるので、作業がバッティングしても他の人が追加したカラムを削除したりすることがないです。

Example

とりあえずGitHubTravis CIを使ったExample Projectを用意してみました。 https://github.com/winebarrel/ridgepole-example

masterからフォークしてPull Requestを投げると、以下の通り。

差分がDBに適用されて実行の成否・実行時間が分かります。未来っぽい!

Exampleだとbefore_scriptでmasterのスキーマを適用してからPull Requestを適用とかやってます。

実際の運用ではスナップショットから本番と同じデータのDBを立ち上げて適用してみるとか、masterにマージされたら自動的に本番DBに適用とかするとよいかもです。夢が広がります。

課題

ActiveRecordに依存しているので、ActiveRecordの制限があります

  • 複数PKが管理しにくい(カラム自体は認識されるのですがPKと認識されません)
  • 外部参照制約が…

リネーム

一応、rename_from: "src_name" とかするとテーブル・カラムは追加・削除ではなくリネームされます。 でも、なにか問題でそうな気が…

本番投入できていない

すいません。

Pull RequestなりIssueなりは随時対応します。 が、わりと最近死んでるので、すぐ対応できるか分かりません。

メンテしてやるぜ、ってかたがいればいくらでもコミット権お渡しします。

→2014/07/29 某所で運用を開始しました

補足

ブックマークコメントで『これだと、どうやって rollback するのか... 「前だけ見て進もう!」って感じか」とありましたが、元に戻す場合はgitのリビジョンを前に戻して、そのスキーマ定義をDBに適用する感じになると思います。

追記 2014/07/02

--diffとか--reverse-diffとかさらにその差分をそのまま適用とかできると便利そうなので、近々追加してみます

→ v0.2.2で追加しました。たぶんrenameを伴う変更の巻き戻しとが多少楽になる…と思います