GoでDB(MySQL)マイグレーションツールを作ったので紹介です。
先月末に行われたDevFest Kansai 2016でも紹介させてもらいました。その時の資料がこちらです。
carpenterとは
DBマイグレーション、結構面倒臭くないですか?
- up.sql、down.sqlみたいなものを書くのが面倒だったり
- バージョンを跨いで適用する時に面倒だったり
- 小さな修正が面倒だったり
これらの面倒を解消するために作ったのがcarpenterです。
4つのサブコマンド
carpenterはコマンドラインツールで、以下の4つのサブコマンドを持っています。
- design
- build
- export
- import
design
% carpenter -s db_name -d "user:password@tcp(127.0.0.1:3306)" design -s -p -d /path/to/json/dir
designコマンドは、対象のDBのテーブル構造をJSONで抜き出します。
-s
オプションは、テーブルごとにファイルを分けて出力するオプション。
-p
オプションは、JSONを整形して出力するオプションです。(付けない場合はワンラインで出力します)
build
% carpenter -s db_name -d "user:password@tcp(127.0.0.1:3306)" build -d /path/to/json/dir
buildコマンドは、対象のDBへdesignコマンドで出力したJSONを元に、各テーブルへその構造を適用します。
適用とは、
- JSONにあってDBに無いテーブルは作成
- JSONになくてDBにあるテーブルは削除
- JSONにあってDBにあるテーブル
- JSONにあってテーブルに無いカラムは追加
- JSONになくてテーブルにあるカラムは削除
- JSONにあってテーブルにあるカラムは差分があれば更新
- JSONにあってテーブルに無いINDEXは追加
- JSONになくてテーブルにあるINDEXは削除
- JSONにあってテーブルにあるINDEXは差分があれば削除、追加
という動きをします。
グローバルオプションとして --dry-run
を用意していて、これを付けることで実行されるであろうSQLを標準出力へ出力します。
% carpenter --dry-run -s db_name -d "user:password@tcp(127.0.0.1:3306)" build -d /path/to/json/dir
export
% carpenter -s db_name -d "user:password@tcp(127.0.0.1:3306)" export -r "^master_.*$" -d /path/to/csv/dir
exportコマンドは、対処のDBのテーブルデータをテーブルごとにCSVファイルとして抜き出します。
-r
オプションで抜き出したいテーブルを正規表現で指定することが出来ます。
import
% carpenter -s db_name -d "user:password@tcp(127.0.0.1:3306)" import -d /path/to/csv/dir
importコマンドは、対象のDBへexportコマンドで出力したCSVを元に、各テーブルへそのデータを適用します。
適用とは、
- CSVにあってテーブルに無いデータは作成
- CSVになくてテーブルにあるデータは削除
- CSVにあってテーブルにあるデータは差分があれば更新
という動きをします。
importコマンドにはいくつか制限があって、詳しくはREADMEに書いてますが、idというカラムが必須だったりします。
使い方
仕事ではいわゆるソシャゲを作っていて、DB構造やテストデータなどはプログラマが作ったり、ゲームのマスターデータはプランナーが作ったりといった環境です。
そういった環境で、以下のような使い方を想定して作りました。
- ローカルの開発環境にて機能開発(DBへの変更はGUIツールなどで好きに変更)
- designコマンドでテーブル構造をエクスポートしてコードと一緒にGitにコミット
- JenkinsなどでQA環境へデプロイ(この時buildコマンドも実行)
- QA環境にてプランナーがデータ調整
- exportコマンドでテーブルデータをエクスポートしてGitにコミット
- Jenkinsなどでステージング環境へデプロイ(この時、build,importコマンドも実行)
Gitのブランチの状態とDBの状態の差分管理をするという思想が割りと気に入っていて、まだ荒削りな感じはありますが今後もアップデート予定です。
元々は少し違った
実はこのcarpenterは二代目で、初代はCSVを適用する機能のみのツールでした。
当時はGoでAPIサーバーを書いていて、マイグレーションには naoina/migu を使っていました。
miguはGoのstructをテーブルに適用するツールで、コードを書くだけでDBマイグレーションが完了するみたいな感じで最高でした。
ただデータseedの機能は無いため、データもCSVを同期するツールを作ろうと思って出来たのが初代です。
そんな最高なDBマイグレーション自動化による運営をしていたんですが、ちょっと前に別プロジェクトへ異動となり状況が変わりました。
そこにはそもそもDBマイグレーションという概念は無く、温かみのある手作業かつPHP。そうなるとmiguが使えない。そういった状況で生み出したのが二代目carpenterでした。
二代目はMySQLでさえあれば使えるし、migu+初代carpenterの実績もあって社内の新規プロジェクトは大体使い始めています。
こういったツールを作ったりするのにGoは最適で、簡単に並列処理が書けるし、Windowsでも動きます。
ソースコードは公開しているので、良かったら見てやって下さい。