Flyway + MySQL + Docker でマイグレーション環境構築

## TL; DR
FlywayでMySQLのコンテナにマイグレーションします。

ソースはこちら
https://github.com/OskaMathis/flyway-sample


## [Flyway][flyway]
オープンソースのDBマイグレーションツールです。使い方がシンプルなので好印象。
今回は公式で用意されているDockerイメージを使ってマイグレーション環境を構築します。


## 環境構築
### 設定ファイル作成
Flywayとマイグレーションを実行するDBの設定をします。

```conf:flyway.conf

flyway.url=jdbc:mysql://db/sample
flyway.user=root
flyway.password=root
```

```yml:docker-compose.yml

version: '3.4'

x-template: &flyway-template
  image: flyway/flyway:6.0.1
  volumes:
    - ./sql:/flyway/sql
    - ./conf:/flyway/conf

services:
  flyway-clean:
    <<: *flyway-template
    command: clean

  flyway-migrate:
    <<: *flyway-template
    command: migrate

  flyway-info:
    <<: *flyway-template
    command: info

  flyway-repair:
    <<: *flyway-template
    command: repair

  db:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: sample
      MYSQL_ROOT_PASSWORD: root
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    ports:
      - 3306:3306
```

### SQL作成
Flywayで使用するSQLファイルには命名規則が存在するので要注意です。
(参考: https://flywaydb.org/documentation/migrations#naming)

```sql:V0.1.0__create_table.sql

CREATE TABLE users (id INT, name VARCHAR(45));
```

```sql:V0.1.1__insert_data.sql

INSERT INTO users VALUES (1, "anonymous user");
```

### ディレクトリ構成
```bash

$ tree
.
├── conf
│   └── flyway.conf
├── docker-compose.yml
└── sql
    ├── V0.1.0__create_table.sql
    └── V0.1.1__insert_data.sql
```


## 実行
### DBコンテナ起動
```bash

$ docker-compose up -d db
Creating network "sample_flyway_default" with the default driver
Creating sample_flyway_db_1 ... done
```

### [マイグレーション][migrate]
sqlディレクトリ内のSQLファイルがバージョンの順に実行されます。
コンテナ起動直後に実行するとエラーが出ることがありますので、コンテナがちゃんと立ち上がりきるまで待ちましょう。

```bash

$ docker-compose run --rm flyway-migrate
Flyway Community Edition 6.0.1 by Boxfuse
Database: jdbc:mysql://db/sample (MySQL 5.7)
Successfully validated 2 migrations (execution time 00:00.032s)
Creating Schema History table `sample`.`flyway_schema_history` ...
Current version of schema `sample`: << Empty Schema >>
Migrating schema `sample` to version 0.0.1 - create table
Migrating schema `sample` to version 0.0.2 - insert data
Successfully applied 2 migrations to schema `sample` (execution time 00:00.264s)
```

### [マイグレーション履歴][info]
どのバージョンのマイグレーションまで実行されているかを出力してくれます。

```bash

$ docker-compose run --rm flyway-info
Flyway Community Edition 6.0.1 by Boxfuse
Database: jdbc:mysql://db/sample (MySQL 5.7)
Schema version: 0.0.2

+-----------+---------+--------------+------+---------------------+---------+
| Category  | Version | Description  | Type | Installed On        | State   |
+-----------+---------+--------------+------+---------------------+---------+
| Versioned | 0.0.1   | create table | SQL  | 2019-09-11 03:15:25 | Success |
| Versioned | 0.0.2   | insert data  | SQL  | 2019-09-11 03:15:25 | Success |
+-----------+---------+--------------+------+---------------------+---------+
```

### [データベース上の全テーブル削除][clean]
やんごとなき理由でDBの中身を一度リセットしたい場合に実行すると良いでしょう。
Flywayで作成してないテーブルに関しても削除されます。

```bash

$ docker-compose run --rm flyway-clean
Flyway Community Edition 6.0.1 by Boxfuse
Database: jdbc:mysql://db/sample (MySQL 5.7)
Successfully cleaned schema `sample` (execution time 00:00.044s)
```

```bash
$ docker-compose run --rm flyway-info
Flyway Community Edition 6.0.1 by Boxfuse
Database: jdbc:mysql://db/sample (MySQL 5.7)
Schema version: << Empty Schema >>

+-----------+---------+--------------+------+--------------+---------+
| Category  | Version | Description  | Type | Installed On | State   |
+-----------+---------+--------------+------+--------------+---------+
| Versioned | 0.0.1   | create table | SQL  |              | Pending |
| Versioned | 0.0.2   | insert data  | SQL  |              | Pending |
+-----------+---------+--------------+------+--------------+---------+
```

### [マイグレーション失敗時の修復][repair]
マイグレーションに失敗すると、 `State` が `Failed` になるのですが、この状態でSQLを修正して再度マイグレーションしようとしてもエラーになります。

```bash
$ docker-compose run --rm flyway-info
Flyway Community Edition 6.0.1 by Boxfuse
Database: jdbc:mysql://db/sample (MySQL 5.7)
Schema version: 0.0.2

+-----------+---------+--------------+------+---------------------+---------+
| Category  | Version | Description  | Type | Installed On        | State   |
+-----------+---------+--------------+------+---------------------+---------+
| Versioned | 0.0.1   | create table | SQL  | 2019-09-11 03:28:11 | Success |
| Versioned | 0.0.2   | insert data  | SQL  | 2019-09-11 03:28:11 | Failed  |
+-----------+---------+--------------+------+---------------------+---------+
```

```bash
$ docker-compose run --rm flyway-migrate
Flyway Community Edition 6.0.1 by Boxfuse
Database: jdbc:mysql://db/sample (MySQL 5.7)
ERROR: Validate failed: Detected failed migration to version 0.0.2 (insert data)
```

`repair` コマンドを実行することで該当のマイグレーションが `Pending` になるので、マイグレーションが実行可能になります。

```bash
$ docker-compose run --rm flyway-repair
Flyway Community Edition 6.0.1 by Boxfuse
Database: jdbc:mysql://db/sample (MySQL 5.7)
Successfully repaired schema history table `sample`.`flyway_schema_history` (execution time 00:00.073s).
```

```bash
$ docker-compose run --rm flyway-info
Flyway Community Edition 6.0.1 by Boxfuse
Database: jdbc:mysql://db/sample (MySQL 5.7)
Schema version: 0.0.1

+-----------+---------+--------------+------+---------------------+---------+
| Category  | Version | Description  | Type | Installed On        | State   |
+-----------+---------+--------------+------+---------------------+---------+
| Versioned | 0.0.1   | create table | SQL  | 2019-09-11 04:34:13 | Success |
| Versioned | 0.0.2   | insert data  | SQL  |                     | Pending |
+-----------+---------+--------------+------+---------------------+---------+
```

```bash
$ docker-compose run --rm flyway-migrate
Flyway Community Edition 6.0.1 by Boxfuse
Database: jdbc:mysql://db/sample (MySQL 5.7)
Successfully validated 2 migrations (execution time 00:00.033s)
Current version of schema `sample`: 0.0.1
Migrating schema `sample` to version 0.0.2 - insert data
Successfully applied 1 migration to schema `sample` (execution time 00:00.159s)
```

## 参考
- [Official Flyway Docker images][flyway-docker]
- [Flyway + PostgreSQLのDBマイグレーション環境をDockerを使って構築する][postgre]


[flyway]:https://flywaydb.org
[migrate]:https://flywaydb.org/documentation/command/migrate
[info]:https://flywaydb.org/documentation/command/info
[clean]:https://flywaydb.org/documentation/command/clean
[repair]:https://flywaydb.org/documentation/command/repair



[flyway-docker]:https://github.com/flyway/flyway-docker
[postgre]:https://qiita.com/supimen89/items/1008e633f6ac2028e1e9