ridgepole で MySQL5.7 に接続してDB定義を一括管理しよう

# はじめに
## 大まかな流れ
1. MySQLの準備
1. Rubyのインストール
1. ridgepoleのインストール
1. ridgepoleでのテーブル操作
1. ちょっと応用編

## 注意点
- `git`,`docker`,`docker-compose`は導入済みとして進めていきます
    - 既存のMySQLや、非コンテナのMySQLを使用する場合は`docker`,`docker-compose`を使用する必要ありません
- 環境的にUbuntu18.04を使用しているので`apt`が出てきますが、適宜読みかえてください
- Rubyインストールに使用する`rbenv`のインストールには公式のrbenv-installerを使用するのが速いのですが、`brew`導入済みのマシンでは作業が必要となります（後述）
    - 面倒な作業がしたくない場合は`brew`でいけます

# 環境

| ソフトウェア等 | バージョン | 備考                                                         |
| -------------- | ---------- | ------------------------------------------------------------ |
| Ubuntu         | 18.04      |                                                              |
| git            | 2.31.1     | 脆弱性対応で2.30.2以降を入れるべきです                       |
| docker         | 20.10.5    | MySQLをコンテナで動かす場合                                  |
| docker-compose | 1.28.5     | 同上                                                         |
| MySQL          | mysql:5.7  | dockerコンテナのmysql:5.7をdocker-composeで実行              |
| rbenv          | 1.1.2      |                                                              |
| ruby-build     | 20210309   |                                                              |
| Ruby           | 2.4.0      | 特に理由なし                                                 |
| ridgepole      | 0.8.13     | 0.9系だと変更がなくてもテーブルオプションの差分がでてしまったので |

# 最終的なDir構成

```bash:ディレクトリ構成
<作業ディレクトリ>
|-- mysql
|   |-- .bundle         # bundleの設定ファイルが格納される
|   |-- bundle          # bundleのインストール先(--path指定した場合)
|   |-- database.yml    # mysql接続設定
|   |-- Gemfile         # インストールしたいGemを記述するファイル
|   |                   #   nodeで言うpackage.jsonみたいなもの？
|   |-- Gemfile.lock    # 依存性含め実際にインストールしたGemが記載されたファイル
|   |                   #   nodeで言うpackage-lock.jsonとかyarn.lockみたいなもの？
|   |-- Schemafile      # mysqlスキーマ定義ファイル
|   `-- .env            # ちょっと応用編で使う環境設定ファイル
|
`-- docker-compose.yml  # mysqlのコンテナ起動用
```

# 手順

## MySQLの準備
### MySQLコンテナの作成
既存のMySQLを使用する場合は不要です

```yaml:docker-compose.yml
version: '3.8' # docker-composeのバージョンとかで変わります

services:
  mysql:
    image: mysql:5.7
    environment:
      - MYSQL_USER=root
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
    ports:
      - "3306:3306"
    volumes: # 必要に応じてマウントしてください
      - ./mysql/sql:/docker-entrypoint-initdb.d/ # 初回起動時に動作するSQLを入れる場合はこのマウントが必要
      - ./mysql/conf/:/etc/mysql/conf.d/         # MySQLの設定
      - ./mysql/data/:/var/lib/mysql/            # データの格納場所
```

```bash:ubuntu
# docker-compose.ymlのあるDirで実行
docker-compose up -d

# コンテナ起動状態を確認
docker-compose ps
```

### 接続先DBの設定
既存のMySQLを使用する場合は既存のMySQLに設定を合わせて修正してください

```yaml:database.yml
adapter: mysql2
encoding: utf8mb4
charset: utf8mb4
collation: utf8mb4_general_ci
database: sample
username: root
password: ''
host:     127.0.0.1
```

### databaseを作成
mysqlにログインしてdatabaseを作成しておく

```bash:ubuntu
docker ps # mysql5.7のコンテナIDを確認
docker exec -it `mysql5.7のコンテナID` bash # VSCodeでdockerの拡張機能使ってログインとかでも良いです
```

```bash:mysql5.7
mysql # mysqlに入ってdatabaseを作成しておく
> create database sample;
```

## Rubyのインストール
`rbenv`,`ruby-build`を利用してRubyをインストールします。インストールの方法は下記のどちらかです
(`apt`では、古いバージョンの`rbenv`,`ruby-build`しか入りませんでした。)

- [rbenv-installer](https://github.com/rbenv/rbenv-installer)のスクリプトでインストール
- `brew install rbenv ruby-build`

※`brew`導入済みマシンでrbenv-installerスクリプトを使用するにはちょっと作業が必要です（後述）

### rbenv-installerを使う場合

`brew`でインストールしたい場合は[brewを使う場合](https://qiita.com/kabu0404/items/bc18ff42150b893d8589#brew%E3%82%92%E4%BD%BF%E3%81%86%E5%A0%B4%E5%90%88)まで読み飛ばしてください

|            | インストール先                                | バージョン        |
| ---------- | --------------------------------------------- | ----------------- |
| rbenv      | `~/.rbenv/bin/rbenv`                          | 1.1.2-44-gd604acb |
| ruby-build | `~/.rbenv/plugins/ruby-build/bin/rbenv-build` | 20210309          |
※brew導入済みの場合はインストール先はbrewを使う場合と同じになります

#### brew導入済みマシンの場合
- `brew`を導入済みマシンでrbenv-installerを使用する場合はこの手順が必要となります。（`brew`を導入していない場合は[rbenv-installerの実行](https://qiita.com/kabu0404/items/bc18ff42150b893d8589#rbenv-installer%E3%81%AE%E5%AE%9F%E8%A1%8C)まで読み飛ばしてください）

rbenv-installerの[README.md](https://github.com/rbenv/rbenv-installer/blob/master/README.md)には
> If Homebrew is detected, installation will proceed using brew install/upgrade. 

と書かれていています（ざっくり言うと「`brew`があるなら`brew`使ってインストールするよ」）が、実際に動かすとエラーになってしまいます。
これは、スクリプトに書かれている`--without-ruby-build`が原因となっていて[Issue](https://github.com/rbenv/rbenv-installer/issues/15)や[PullRequest](https://github.com/rbenv/rbenv-installer/pull/21)を見ると2019年から発覚しているのものの、解決される気配はありません。
スクリプト内の`--without-ruby-build`を消せば良いだけなので、`rbenv-installer`のリポジトリをPullして、該当箇所を消したスクリプトを使えば`brew`と`rbenv-installer`を共存させることが出来ます。（一応インストールだけは動作確認しました）

```bash:ubuntu
# rbenv-installerのリポジトリをcloneする
cd ~ # clone先はどこでも良いです
git clone https://github.com/rbenv/rbenv-installer.git

# rbenv-installerを修正する
vi ~/rbenv-installer/bin/rbenv-installer # もちろんviでなくてもOKです

```
下記の箇所を修正した上で、次の手順に進んでください。（`--without-ruby-build`を消すだけです）

```diff:rbenv-installerの修正箇所
diff --git a/bin/rbenv-installer b/bin/rbenv-installer
index f426db6..dba12f5 100755
--- a/bin/rbenv-installer
+++ b/bin/rbenv-installer
@@ -42,7 +42,7 @@ if [ -n "$rbenv" ]; then
     brew update >/dev/null
     if [ "$(./rbenv --version)" < "1.0.0" ] && brew list rbenv | grep -q rbenv/HEAD; then
       brew uninstall rbenv
-      brew install rbenv --without-ruby-build
+      brew install rbenv
     else
       brew upgrade rbenv
     fi
@@ -56,7 +56,7 @@ else
   if [ -n "$homebrew" ]; then
     echo "Installing rbenv with Homebrew..."
     brew updat
-    brew install rbenv --without-ruby-build
+    brew install rbenv
     rbenv="$(brew --prefix)/bin/rbenv"
   else
     echo "Installing rbenv with git..."
```


#### rbenv-installerの実行
```bash:ubuntu
# rbenv/ruby-buildのインストール
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash  # curlを使う場合
wget -q https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer -O- | bash # wgetを使う場合
~/rbenv-installer/bin/rbenv-installer # cloneしたrbenv-installerを使う場合

# PATHを通して、rbenv initする
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
eval "$(rbenv init -)"

# インストール状態の確認
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash  # curlを使う場合
wget -q https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor -O- | bash # wgetを使う場合
~/rbenv-installer/bin/rbenv-doctor # cloneしたrbenv-doctorを使う場合
```

### brewを使う場合
|            | インストール先                              | バージョン |
| ---------- | ------------------------------------------- | ---------- |
| rbenv      | `/home/linuxbrew/.linuxbrew/bin/rbenv`      | 1.1.2      |
| ruby-build | `/home/linuxbrew/.linuxbrew/bin/ruby-build` | 20210309   |

#### brewをインストール
導入済みの人は[rbenv,ruby-buildをインストール](https://qiita.com/kabu0404/items/bc18ff42150b893d8589#rbenvruby-build%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)まで読み飛ばしてください

```bash:ubuntu
# brewのインストール
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# PATHを通す
echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> ~/.profile
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"

# メッセージにでたコマンドで推奨されたものを入れる
sudo apt install -y build-essential
brew install gcc
```
#### rbenv,ruby-buildをインストール

```bash:ubuntu
# rbenv,ruby-buildのインストール
brew install rbenv ruby-build

# rbenv initする
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
eval "$(rbenv init -)"

# インストール状態の確認
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash  # curlを使う場合
wget -q https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor -O- | bash # wgetを使う場合
```

### Rubyをインストール
`rbenv install`で任意のバージョンのRubyをインストールします

```bash:ubuntu
# 今のバージョンを確認
ruby --version

# インストール可能なバージョンを確認
rbenv install --list     # 最新の安定バージョンに限定した一覧
rbenv install --list-all # 全バージョン一覧

# とりあえず2.4.0を入れてみる(結構時間かかる)
rbenv install 2.4.0

# rbenv installが失敗したので下記を実行してから再度rbenv install
sudo apt install zlib1g-dev

# バージョンを確認（2.4.0は入ったが、設定していないのでまだ使えない）
rbenv versions
ruby --version

# ruby --versionでrubyが見つからなかったらrbenv initをし直すために下記を実行してみる
. ~/.bashrc

# バージョンを切り替える
rbenv global 2.4.0 # マシン全体のrubyバージョンを指定する場合
rbenv local 2.4.0  # カレントディレクトリ以下のrubyバージョンを指定する場合
ruby --version
```

## ridgepoleのインストール

### bundleのインストール・初期化
```bash:ubuntu
gem install bundle # sudo必要かも
. ~/.bashrc
cd ~ # プロジェクトを作るディレクトリに移動する
bundle init # カレントディレクトリにGemfileが生成される
```

### Gemfileに追記
```ruby:Gemfile
gem 'ridgepole', '< 0.9.0' # 0.9系を避けてます
gem 'mysql2'
```

### Gemfileに従ってインストール

```bash:ubuntu
# libmysqlclient-devを先に入れておかないとエラーが出てしまいます(環境依存？ ubuntu限定かも？ )
sudo apt install -y libmysqlclient-dev
bundle install
```
#### bundle installのパス指定について
調べていると`bundle install --path vender/bundle`としている記載されているサイト等が多かったのですが
`--path`オプションは現在非推奨になっているようで、下記のようなメッセージが出てきます。

>[DEPRECATED] The `--path` flag is deprecated because it relies on being remembered across bundler invocations, which bundler will no longer do in future versions. Instead please use `bundle config set --local path 'vender/bundle'`, and stop using this flag

インストール先を指定したい場合は`bundle config set --local path 'vender/bundle'`を使った方が良いようです。

## ridgepoleでのテーブル操作

### ざっくり主要操作まとめ

```bash:ridgepole主要操作まとめ
# スキーマ構造の出力
bundle exec ridgepole -c database.yml --export -o Schemafile

# スキーマ作成・更新（差分確認）
bundle exec ridgepole -c database.yml -f Schemafile --apply --dry-run

# スキーマ作成・更新
bundle exec ridgepole -c database.yml -f Schemafile --apply
```

### テーブル定義の出力

既存のMySQLを使っている場合などには下記コマンドでテーブル定義をSchemafileに出力可能です

#### ridgepoleの実行

```bash:ubuntu
bundle exec ridgepole -c database.yml --export -o Schemafile

# 実行時の表示
Export Schema to `Schemafile`
```

DBに何もないとこんな感じで出力されます

```ruby:Schemafile
# -*- mode: ruby -*-
# vi: set ft=ruby :
```

何かしらテーブル構造が入っている場合はこんな感じで出力されます

```ruby:Schemafile
# -*- mode: ruby -*-
# vi: set ft=ruby :
create_table "shops", id: :bigint, unsigned: true, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", comment: "店舗", force: :cascade do |t|
  t.string "shop_name", null: false, comment: "店舗名"
  t.datetime "created_at", null: false, comment: "作成日時"
  t.datetime "updated_at", null: false, comment: "更新日"
end

create_table "users", id: :bigint, unsigned: true, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", comment: "ユーザー", force: :cascade do |t|
  t.string "user_name", null: false, comment: "ユーザ名"
  t.string "email", comment: "メールアドレス"
  t.string "address", comment: "住所"
  t.datetime "created_at", null: false, comment: "作成日時"
  t.datetime "updated_at", null: false, comment: "更新日"
end
```

### テーブル定義の作成

#### スキーマ定義を作成
Schemafileにテーブル定義を記載します

```ruby:Schemafile
# encoding: utf-8

create_table "users", id: :bigint, unsigned: true, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", comment: "ユーザー", force: :cascade do |t|
  t.string   "name",       null: false, comment:"ユーザ名"
  t.string   "email",      null: false, comment:"メールアドレス"
  t.datetime "created_at", null: false, comment:"作成日"
  t.datetime "updated_at", null: false, comment:"更新日"
end
```

#### ridgepoleの実行
`--dry-run`オプションを使うと（実際には実行せず）実行した場合の変更内容が確認できます

```bash:ubuntu
bundle exec ridgepole -c database.yml -f Schemafile --apply --dry-run

# 事前の差分表示
Apply `Schemafile` (dry-run)
create_table("users", **{:id=>:bigint, :unsigned=>true, :options=>"ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", :comment=>"ユーザー"}) do |t|
  t.column("name", :"string", **{:null=>false, :comment=>"ユーザ名", :limit=>255})
  t.column("email", :"string", **{:null=>false, :comment=>"メールアドレス", :limit=>255})
  t.column("created_at", :"datetime", **{:null=>false, :comment=>"作成日"})
  t.column("updated_at", :"datetime", **{:null=>false, :comment=>"更新日"})
end

# CREATE TABLE `users` (
# `id` bigint unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
# `name` varchar(255) NOT NULL COMMENT 'ユーザ名',
# `email` varchar(255) NOT NULL COMMENT 'メールアドレス',
# `created_at` datetime NOT NULL COMMENT '作成日',
# `updated_at` datetime NOT NULL COMMENT '更新日')
# ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT 'ユーザー'
```
問題なければ`--dry-run`を外して変更を適用します

```bash:ubuntu
bundle exec ridgepole -c database.yml -f Schemafile --apply

# 実行時の表示
Apply `Schemafile`
-- create_table("users", {:id=>:bigint, :unsigned=>true, :options=>"ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", :comment=>"ユーザー"})
   -> 0.0071s
```
### テーブル定義の変更

コマンドはテーブル定義の作成と同じです。ridgepoleがSchemafileとDBの定義間の差分を反映してくれます。

#### スキーマ定義を変更　
Schemafileのスキーマ定義を変更します

```ruby:Schemafile
# encoding: utf-8

create_table "users", id: :bigint, unsigned: true, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", comment: "ユーザー", force: :cascade do |t|
  t.string   "user_name",  null: false, comment:"ユーザ名",      renamed_from: "name"# カラム名変更
  t.string   "email",      null: true,  comment:"メールアドレス"                     # 定義変更
  t.string   "address",    null: true,  comment:"住所"                               # カラム追加
  t.datetime "created_at", null: false, comment:"作成日時"                           # コメント変更
  t.datetime "updated_at", null: false, comment:"更新日"                             # そのまま
end

# テーブル追加
create_table "shops", id: :bigint, unsigned: true, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", comment: "店舗", force: :cascade do |t|
  t.string   "shop_name",  null: false, comment:"店舗名"
  t.datetime "created_at", null: false, comment:"作成日時"
  t.datetime "updated_at", null: false, comment:"更新日"
end

```
#### ridgepoleの実行
`--dry-run`オプションで一度差分を確認します

```bash:ubuntu
bundle exec ridgepole -c database.yml -f Schemafile --apply --dry-run

# 事前の差分表示
Apply `Schemafile` (dry-run)
create_table("shops", **{:id=>:bigint, :unsigned=>true, :options=>"ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", :comment=>"店舗"}) do |t|
  t.column("shop_name", :"string", **{:null=>false, :comment=>"店舗名", :limit=>255})
  t.column("created_at", :"datetime", **{:null=>false, :comment=>"作成日時"})
  t.column("updated_at", :"datetime", **{:null=>false, :comment=>"更新日"})
end

add_column("users", "address", :string, **{:null=>true, :comment=>"住所", :after=>"email", :limit=>255})
rename_column("users", "name", "user_name")
change_column("users", "email", :string, **{:null=>true, :comment=>"メールアドレス", :default=>nil, :unsigned=>false})
change_column("users", "created_at", :datetime, **{:null=>false, :comment=>"作成日時", :default=>nil, :unsigned=>false})

# CREATE TABLE `shops` (
# `id` bigint unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
# `shop_name` varchar(255) NOT NULL COMMENT '店舗名',
# `created_at` datetime NOT NULL COMMENT '作成日時',
# `updated_at` datetime NOT NULL COMMENT '更新日')
# ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '店舗'
# ALTER TABLE `users` ADD `address` varchar(255) COMMENT '住所' AFTER `email`
# ALTER TABLE `users` CHANGE `name` `user_name` varchar(255) NOT NULL
# ALTER TABLE `users` CHANGE `email` `email` varchar(255) DEFAULT NULL COMMENT 'メールアドレス'
# ALTER TABLE `users` CHANGE `created_at` `created_at` datetime NOT NULL COMMENT '作成日時'
```
問題なければ`--dry-run`を外して変更を適用します

```bash:ubuntu
bundle exec ridgepole -c database.yml -f Schemafile --apply

# 実行時の表示
Apply `Schemafile`
-- create_table("shops", {:id=>:bigint, :unsigned=>true, :options=>"ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", :comment=>"店舗"})
   -> 0.0089s
-- add_column("users", "address", :string, {:null=>true, :comment=>"住所", :after=>"email", :limit=>255})
   -> 0.0103s
-- rename_column("users", "name", "user_name")
   -> 0.0046s
-- change_column("users", "email", :string, {:null=>true, :comment=>"メールアドレス", :default=>nil, :unsigned=>false})
   -> 0.0148s
-- change_column("users", "created_at", :datetime, {:null=>false, :comment=>"作成日時", :default=>nil, :unsigned=>false})
   -> 0.0048s
```

## ちょっと応用編

### 複数の接続設定
`ridgepole`で`-E`オプションを利用すると`database.yml`に定義された複数の接続先設定を読み分けて実行することが出来るようになり、複数環境のデータベース定義ファイルが統一出来ます。

```yaml:database.yml
# 基本的な情報だけはこっちに定義しておく
base: &base
  adapter: mysql2
  encoding: utf8mb4
  charset: utf8mb4
  collation: utf8mb4_general_ci

# 環境別の情報は個別に定義や上書きする
development:
  <<: *base
  database: sample
  username: root
  password: ''
  host:     127.0.0.1

# 検証ということで一旦databaseを分けるだけでやっています
test:
  <<: *base
  database: sample2
  username: root
  password: ''
  host:     127.0.0.1 
```

```bash:ubuntu
# development用(実行結果は省略します)
bundle exec ridgepole -c database.yml -E development -f Schemafile --apply

# test用(実行結果は省略します)
bundle exec ridgepole -c database.yml -E test -f Schemafile --apply
```

### dotenvを使って環境依存設定を分離

`dotenv`を導入すると、`database.yml`から環境依存情報やパスワードをなくすことが出来ます。

#### Gemfileに追記
```ruby:Gemfile
gem 'dotenv-rails'
```
#### bundleインストール
```bash:ubuntu
bundle install
```

#### 環境情報の分離
`database.yml`を修正

```yaml:database.yml
# 変えた所のみを抜粋
development:
  <<: *base
  database: <%= ENV.fetch('DB_NAME') %>
  username: <%= ENV.fetch('USER_NAME') %>
  password: <%= ENV.fetch('PASSWORD') %>
  host:     <%= ENV.fetch('HOST')%>
# 変数が存在しない時のデフォルト値はENV.fetch('HOGEHOGE','defaultValue')で設定できるようです
```
`.env`を作成

```bash:.env
export DB_NAME='sample'
export USER_NAME='root'
export PASSWORD=''
export HOST='127.0.0.1'
```

ridgepoleの実行

```bash:ubuntu
bundle exec dotenv -f '.env' bundle exec ridgepole -c database.yml -E development -f Schemafile --apply
```

`dotenv`を導入した上で、例えば下記のような工夫をしておくとリリースミスなどの発生は抑えられるかもしれませんね。

- リポジトリ管理する`.env`にはローカル環境や開発環境用の設定しか記載しない
- 試験環境や本番環境の設定については`.env`ファイルのファイル名を変えておく
    - `.env-staging`とか`.env-prod`とか？

※実運用する際には`database.yml`と`.env`についてどう記載して複数環境を分離するかはちゃんと検討したほうが良さそうです。

# さいごに

以上の手順によって、Schemafileを原本としてテーブル定義を行うことが出来るようになったため、Schemafileでテーブル構造を設計すれば「実際のテーブル構造とデータベース設計書に差分が発生してしまう」なんて事はなくなりました。

## テーブル定義としてのSchemafile
今回実施した「カラム名の変更」では`renamed_from:`を指定しないと削除→追加となってしまうようです。
つまり「テーブル定義のスナップショット」として存在させたいSchemafileに、「○○から●●への変更」という「スナップショット的でない要素」が入ってしまいます。

```bash:ubuntu
# Schemafileにrename_fromの指定が無い場合は下記のようにカラム削除→追加となってしまいます
add_column("users", "user_name", :string, **{:null=>false, :comment=>"ユーザ名", :after=>"id", :limit=>255})
remove_column("users", "name")

# ALTER TABLE `users` ADD `user_name` varchar(255) NOT NULL COMMENT 'ユーザ名' AFTER `id`
# ALTER TABLE `users` DROP COLUMN `name`
```

例えば初期リリース前の開発中などではテーブル構造に変更が入ることも多いですが、こういった場合にはリリース手順やSchemafileの管理に工夫をすることになります。
（リリース用のSchemafileと、リリース後のスナップショットとしてのSchemafileをそれぞれ用意するとかでしょうか？）

※カラム追加などではないテーブル構造の変更については、バグの発生原因になりますので特にリリース後は実施を避けるべきかと思います