KINTO Tech Blog
Development

Flyway導入

李 琳
李 琳
Cover Image for Flyway導入

背景紹介

自己紹介

こんにちは。KINTOテクノロジーズ Globalグループ、DevOpsチームの李琳です。2017年までは中国でエンジニア、プロジェクトマネージャー、大学の先生を経験し、 2018年から日本で働き始めました。 子供を二人持っている母ですが、リスキルしながら仕事をしています。

DevOpsチームの紹介

GlobalグループのDevOpsチームは今年から実働開始しました。Globalグループは多国籍のグループで、DevOpsチームメンバーたちの母国語はそれぞれ日本語、中国語、英語ですので、仕事中は参画者の言語能力を考慮しながらコミュニケーションを取っています。 新しいチームとして、チームメンバーそれぞれの経験は違いますが、普段トラブルあった時には積極的に協力しながら進めています。チームワークがうまくできていると思っています。

DevOpsチームの責任範囲

現在Globalグループ内では複数のチームがあります。DevOpsチームは共通チームの位置付けで、Global全体を見ています。 具体的に言うと担当範囲は下記です。

タスク 作業内容
CI/CD、開発環境(Git/AWS/Grafana/SonarQubeなど)のGlobalチーム展開基準策定 共通部品のGlobalチーム展開基準の策定
Globalチーム共通のDevOps改善 上記内容のFB収集、PDCAの実施
個別カスタマイズサポート 上記内容以外の、全グループ通用可能な改善ではない要望については緊急度と必要性を判断した上で、実施策(基本DevOpsチームはサポートで、アプリチーム独自実装)の検討とサポート
エラー解決サポート CI/CDと環境利用中のエラーについて、DevOpsが解決サポート
グループ内DevOpsとAWS知見の向上 勉強会実施、個別問い合わせ受け取ること
プラットフォームグループとの窓口 Globalグループとプラットフォームグループ間の問い合わせについて、DevOpsがフォローと収集を行い、グループノウハウを蓄積すること
運用の基準策定 運用業務の標準策定、一部外部業者さんに依頼すること
コストの監視と方針策定 環境コストの最適化
問い合わせ対応 上記範囲の問い合わせ受付

本記事のターゲット

本記事の対象読者は、開発経験者としてFlywayの導入を検討中または導入済の方です。以前、自分でFlywayの導入を始めたとき、ネットでも色々調べたことがありますが、全体図を書かれている資料が少ないと痛感しました。本記事は、一つのFlyway導入案として執筆しています。ご参考になると光栄です。

Flywayの紹介

Flywayとは

FlywayはOpen-Sourceのデータベースマイグレーションツールです。
Flywayを使うことで、複数環境のデータベースのバージョン管理が簡単にできます。
各コマンドの適用シナリオは下記の様です。

Baseline

Baselineのコマンドを実行すると、Flywayの初期バージョンを作ります。Baselineのデフォルトバージョンが「1」です。 Community Editionだと、Baselineは一回しか作れません。更新できません。 対象データベースの中に既に一部のテーブルが存在している場合、Baselineを実行しないとエラーになって、Migrateコマンドが実行できません。
【シナリオ】
Step1)Flyway導入前に既に適用済のSQL文のバージョンを「1」より小さい数字にする
Step2)Baseline実行
Step3)Migrate実行
結果はバージョン「1」以上のSQL文が適用されます。
【参照】Baselines an existing database

Clean

対象スキーマが丸ごとクリアされます。スキーマが空っぽになるので、本番環境には使わない様な仕組みを入れないといけないです。
【シナリオ】
最初のバージョンに戻したい時は下記のステップでできます。
Step1)Cleanのコマンド実行
Step2)Migrateのコマンド実行
【参照】Wiping your configured schemas completely clean

Info

Flywayの情報が出力されます。このコマンドでFlywayからデータベースに繋がるかどうかの確認ができます。
【シナリオ】
実行後下記の様な情報出力(一例)

| Category  | Version | Description | Type | Installed On | State   | 
+-----------+---------+-------------+------+--------------+---------+
| Versioned | 00.01   | initial     | SQL  |              | Pending |
| Versioned | 00.02   | initial     | SQL  |              | Pending |
+-----------+---------+-------------+------+--------------+---------+

【参照】Prints the details and status information about all the migrations

Migrate

新バージョン(まだ適用していない)のSQLファイルが適用されます。一番使われるコマンドです。データベースバージョンアップの時毎回使うコマンドです。
【参照】Migrates the schema to the latest version

Repair

エラーになったSQL文の実行履歴を消します。 実行結果は消せません。
Repairコマンドはデータベース中のflyway_shema_historyテーブル(Flywayのバージョン管理テーブル)からエラーになったSQL文の実行履歴を消しただけです。
下記の状況がよくあることです。その場合はきちんとどこまで適用されたかを確認して、全てのSQL文を適用するまで対応してください。

1つのSQLファイルの中に複数のSQL文があって、エラーになった前のSQL文が適用済み、エラーになったSQL文の後のSQL文が適用されていない場合。 

【シナリオ】
【例】
V01_07、V01_08、V01_09、適用する時、V01_07、V01_08が成功、V01_09がFailした場合、下記のステップで対応可能です。
Step1)V01_09修正
Step2)Repairコマンド実行
Step3)再度Migrateコマンド実行
【参照】Repairs the schema history table

Validate

プロジェクト中のSQL文がデータベースに適用されたかどうか、バージョンがあっているかどうかのチェックができます。
今のDBバージョンがクラウド上のバージョンと同じかどうかをチェックしたい場合も利用できます。
【参照】 Validates the applied migrations against the available ones

Flyway導入の背景

Flywayのようなツールを利用しなければ、デプロイする度にデータベースに対する踏み台サーバにログインして、アップデートのシェルなどを実行する必要があります。Globalグループのサービスはほとんどがマイクロサービスで構成されているため、環境が多くなると従来の様な踏み台サーバを利用してデータベースをアップデートするオペレーションでは工数もリスクも大きくなるということが課題になりました。

こういった経緯でFlywayの導入を視野に入れました。最初はAWS上のLambda経由で、GitHubのジョブでコマンドを実行できるジョブを導入してみました。実際に使ってみたところ、下記の課題がありました。

  • ローカル環境等でのSQLそのものの検証が不十分な状態でAWSにマイグレートしてしまうと、マイグレートが失敗し復旧に手間がかかってしまった。
  • ローカル環境でFlywayの環境を構築しないままで、手動でデータベースをアップデートすると、AWS上のデータベースと違う構造になるリスクが高いです。
    上記の課題をもちまして、一回目のPDCAで、Flywayの仕組みを下記のように作ってみました。

KINTOテクノロジーズ Global チームのFlyway導入方法

SpringBootアプリケーションでFlyway利用するために、下記のところに機能を入れました。

  1. アプリケーションの中にFlywayを導入
  • 利用タイミング:ローカルでアプリを立ち上げる時と、AWSにデプロイする時に自動的にマイグレートされる
  • 意図:ローカルでマイグレーション用のSQL文テスト、自動的にマイグレーションされるので手間がかからないため
  1. Flywayのプラグイン導入
  • 利用タイミング:ローカル開発の時
  • 意図:ローカルで自動マイグレートができなかった場合は、プラグインでFlywayのコマンドを実行するため
  1. Flywayコマンドを実行可能なGitHubジョブ導入
  • 利用タイミング:AWSにデプロイする時に自動的にマイグレーションできない場合は、GitHub上のジョブでFlywayコマンドを実行します。
  • 意図:AWSに入らなくてもFlywayのコマンドを実行できるようにするため

つぎに、それぞれの完成図を紹介いたします。

アプリケーションの中にFlywayの導入

Flywayをプロジェクトの中に導入したら、下記のことができます。

  • アプリケーション起動後各環境上のデータベースが自動的にマイグレート
  • AWSのデータベースにマイグレート前、ローカル環境でマイグレーション用SQL文検証

詳細は下記の通りです。
下記のコマンドでローカルでMySQLのDockerイメージを起動→アプリケーション起動したら、 自動的に最新のSQL文がマイグレートされます。

docker-compose up -d
./gradlew bootRun

Flywayのプラグイン導入

手動でもFlywayのコマンドでローカルデータベースを維持できます。下記のようにプラグインを使えばコマンド実行できます。
flywayプラグイン

Flywayコマンド実行可能のGitHubジョブ導入

AWSにデプロイされると、Auroraまで自動的にマイグレートできますが、できない場合はFlywayコマンドを実行する必要があります。 AWS上にはLambdaを経由でFlywayコマンド実行します。 構成図は下記の通りです。

flyway構成図

GitHubジョブ実行からFlyway実行終了までのフローは下記の通りです。

  • GitHubジョブから実行用のファイルをS3にアップロード
  • Payload(JSON)から必要なパラメータを抽出
  • AWS CLIを利用し、Flyway実行に必要な情報を抽出
  • S3バケットからSQLを含むzipファイルを取得
  • Flyway実行(Lambda上のDocker imageで)
  • 結果をS3バケットに配置

GitHub上コマンド実行時のイメージは下記の通りです。AWSに入らなくても実行できるように構築しました。
GitHub実行用ジョブ

これで各環境に下記のことができるようになりました。

  • アプリケーション起動後各環境上のデータベースが自動的にマイグレートされた
  • AWSのデータベースにマイグレート前、ローカル環境でマイグレーション用SQL文検証できた
  • 各環境にFlywayコマンド実行用のツールが用意された

Flywayを使うことによって、下記のメリットがありました。

  • デプロイ時間が大幅に(半分以上)削減できた
  • 各環境のデータベース差分が無くなったことで開発時の不要なバグ混入や認識齟齬を減らせた
  • 各環境データベースバージョン管理の工数を極小化(SQL文の名前でバージョンを明確すればOK)できた
  • テストやReviewによって不完全なクエリを流すことを防ぐことができた
  • AWS上に構築した踏み台サーバにログインしてオペレーションをしなくて良くなった

もちろんFlywayを利用することによって、下記注意しないといけないこともあります。

  • 開発者が多い場合は使い方を決めた上で徹底すること
  • エラーになるときのトラブルシュッティングと復旧は手数をかかること

上記の仕組みで理論上はGitHub ActionsのCI/CDジョブ実行中にもデータベースを立ち上げることもできますが、まだ検証していないです。CI/CDの自動テスト用のデータベースもFlywayで構築した方がいいかなと思っているところです。

Flywayを使うことによって、便利なところもありますが、Flywayが起因となったトラブルが発生したこともあります。この点は利用基準のPDCAで改善の余地があります。環境と利用するシーンによって段階的に導入することで、より安全に効率的に利用できると思います。興味ある方は是非お試しください。

Facebook
【KURAND社 協賛】仕事とお酒を愛でる「ソースコード」レビューまつり!

関連記事 | Related Posts

We are hiring!

【データエンジニア】分析G/東京・名古屋・大阪

分析グループについてKINTOにおいて開発系部門発足時から設置されているチームであり、それほど経営としても注力しているポジションです。決まっていること、分かっていることの方が少ないぐらいですので、常に「なぜ」を考えながら、未知を楽しめるメンバーが集まっております。

【部長・部長候補】/プラットフォーム開発部/東京

プラットフォーム開発部 について共通サービス開発GWebサービスやモバイルアプリの開発において、必要となる共通機能=会員プラットフォームや決済プラットフォームの開発を手がけるグループです。KINTOの名前が付くサービスやTFS関連のサービスをひとつのアカウントで利用できるよう、様々な共通機能を構築することを目的としています。