はじめに
こんにちは、ATOM 事業本部のエンジニアの岸田 (@mwudo) です。
最近は集計基盤の機能開発や保守、API サーバ、バッチ処理などの開発をしていて、 ATOM のバックエンド周りを見ております。
現在、DBのスキーマ情報を管理する仕組みを考えています。
この記事では導入を検討している仕組みについてご紹介しようと思います。
背景
ATOM では新機能の開発や、既存機能のブラッシュアップ等で DB のテーブル定義に変更が加えられています。
このような状況下で、テーブル定義の情報やER図を人力でのメンテナンスだと追従するのが大変なのは想像できると思います。
さらに、テーブル数が多くなってきて各テーブルの関係性が複雑になってきたこともあり、新機能を開発する上でテーブル同士の関係性を理解していないと全容を把握できない機会が出てきたと感じています。
現状、テーブル同士の関係性を理解するためには、メンバーに聞くか DB のテーブルを直接みるしか方法がなく、新しく入ってくる方の認知負荷が当然高い状態です。
現状のスキーマの情報を管理して、新しく入ってくる方の立ち上がりをスムーズに行うためにも仕組みを用意しようと思いました。
新しく入ってくる方の中には新卒もいるので、より必要性を感じていました。
ツールの検討
導入するに当たって、いくつか要件を考えていました。
- テーブル定義とテーブル同士の関係性がわかるドキュメントを出力される
- CI 上(
CircleCI
やGitHub Actions
など)で実行できるとよい - Git 管理をする(当然)
頭の中で要件を考えながら、日々の日課である Twitter を漁っていると、
というツールを見つけて、見た感じで考えていた要件を満たしていたのでこのツールを導入することを検討しました。
tbls
tbls
は DB の情報をドキュメントすることが可能な Go 製のツールになります。
README にいくつか特徴が書かれていまして、
- GitHub Flavored Markdown (通称:GFM)で出力が可能(他にも様々なフォーマットにも対応)
- シングルバイナリ
- 様々な DB に対応
- DB の Linter としても機能する
実際にこのツールを使用して出力されるサンプルを見ると、
テーブルの一覧情報とテーブルごとの関係性が画像で示されており、わかりやすいです。
更に、各テーブルの詳細だとカラムごとの情報やインデックスなどが記載されています。
このあたりの情報は 1. テーブル定義とテーブル同士の関係性がわかる
を満たしていました。
さらに、2. CI 上(CircleCI や GitHub Actions など)で実行できるとよい
と3. Git 管理をする(当然)
に関連したところで、
GitHub Actions用の tbls
が用意されていました。
tbls
でやりたいことができることは確認できたので次にどのような仕組みで導入するか紹介します。
導入検討
実行環境は定義が用意されている GitHub Actions
上で行うことにしました。*1
ワークフローのイメージは以下の通りです。
- テーブル定義に変更を行った Pull Request (PR) がマージされた時に
GitHub Actions
を起動 tbls
を使ってスキーマ情報のドキュメントを作成・更新- ドキュメントを作成・更新した PR を作成
次に各手順の GitHub Actions
のワークフローの定義を紹介します。
使用する DB は MySQL で、テーブル定義は schema.sql
というファイルに書かれている想定です。*2
1. テーブル定義に変更を行った PR がマージされた時に GitHub Actions
を起動
# develop にプッシュされたかつ schema.sql に変更があった場合に起動 on: push: branches: - 'develop' paths: - "schema.sql"
READEM やテーブル定義の変更に関係ない更新で起動させないためにテーブル定義を管理しているファイルを指定しています。
2. tbls
を使ってスキーマ情報のドキュメントを作成・更新
tbls
を使うためにはまず、更新されたテーブル定義を DB (今回だと MySQL ) に反映させる必要があります。
update-schema-document: runs-on: ubuntu-latest services: mysql: image: mysql:5.7 env: MYSQL_DATABASE: test_db MYSQL_ALLOW_EMPTY_PASSWORD: true ports: - 3306:3306 # 疎通が確認できるまで待つ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
次に 更新された schema.sql
を反映させます。
steps: - name: Checkout base branch uses: actions/checkout@v3 - name: Init Schema run: mysql -u root -h 127.0.0.1 test_db < ./schema.sql
DB へ読み込ませる処理(Init Schema
)はマイグレーションツール等を採用している場合はそちらをお使いください。
これで更新されたテーブル定義を用意できたので、tbls
を使ってドキュメントを作成・更新します
# 続きです - name: Setup tbls uses: k1low/setup-tbls@v1 - name: Run tbls env: DATABASE: test_db # --force をつけるとすでにあるファイルに対して上書きすることが可能 run: tbls doc --force
ここで、環境変数にDATABASE
を設定しているのは、tbls
には .tbls.yml or tbls.yml
に設定を可能で、
# ドキュメントの出力先 docPath: doc/${DATABASE} # 対象のDBのDSN dsn: mysql://root:@localhost:3306/${DATABASE}
のように設定を追加すると、
今回だとドキュメントの出力先は doc/test_db
配下に、
接続する DSN は mysql://root:@localhost:3306/test_db
になります。
他にも様々な設定が可能です。
3. ドキュメントを作成・更新した PR を作成
作成したドキュメントの PR を作成しますが、どの PR に関連したもの分かっているとより親切だと思うので、このワークフローの起動のきっかけとなった PR の情報を取得したいと思います。
PR 情報の取得には GitHub CLI を使用します。
今回取得する情報は以下の通りです。
- PR の URL
- PR のタイトル
- PR の作成者
- name: Load PR Infomation id: load_pr run: | pr_url=$(gh pr list --state merged --search "sha:${{ github.sha }}" --json "url" -q ".[0].url") pr_title=$(gh pr list --state merged --search "sha:${{ github.sha }}" --json "title" -q ".[0].title") pr_author=$(gh pr list --state merged --search "sha:${{ github.sha }}" --json "author" -q ".[0].author.login") echo "pr_url=${pr_url}" >> $GITHUB_OUTPUT echo "pr_title=${pr_title}" >> $GITHUB_OUTPUT echo "pr_author=${pr_author}" >> $GITHUB_OUTPUT env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
--state merged
を追加することで、マージされた PR の中から対象のものを検索することが可能です。*3
PR 作成には Create Pull Request を使用します。
これを使用するためには、Settings
→ Actions
→ General
で表示されるページの下部にあるAllow GitHub Actions to create and approve pull requests
にチェックをつける必要があります。
- name: Create Pull Request uses: peter-evans/create-pull-request@v5 with: token: ${{ secrets.GITHUB_TOKEN }} title: "Update generated documentation" body: | [${{ steps.load_pr.outputs.pr_title }}](${{ steps.load_pr.outputs.pr_url }}) でスキーマが更新されたのでスキーマのドキュメントも更新します commit-message: "update generated documentation" base: develop branch: feat/update-generated-docs reviewers: ${{ steps.load_pr.outputs.pr_author }} author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
PR のイメージはこちらです。
Reviewers にはテーブル定義を変更の PR を作成した人にして、その人が確認し、問題なければマージして反映させます。
この PR 作成の部分については、PR を新規作成ではなく、テーブル定義の変更のPRに対してコミットを追加するといった方法も考えられます。
最後に各手順をまとめたファイルを載せます。
展開する
name: Update Schema Document on: push: branches: - 'develop' paths: - "schema.sql" jobs: update-schema-document: runs-on: ubuntu-latest services: mysql: image: mysql:5.7 env: MYSQL_DATABASE: test_db ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - name: Checkout base branch uses: actions/checkout@v3 - name: Init Schema run: mysql -u root -h 127.0.0.1 test_db < ./schema.sql - name: Setup tbls uses: k1low/setup-tbls@v1 - name: Run tbls env: DATABASE: test_db run: tbls doc --force - name: Load PR Infomation id: load_pr run: | pr_url=$(gh pr list --state merged --search "sha:${{ github.sha }}" --json "url" -q ".[0].url") pr_title=$(gh pr list --state merged --search "sha:${{ github.sha }}" --json "title" -q ".[0].title") pr_author=$(gh pr list --state merged --search "sha:${{ github.sha }}" --json "author" -q ".[0].author.login") echo "pr_url=${pr_url}" >> $GITHUB_OUTPUT echo "pr_title=${pr_title}" >> $GITHUB_OUTPUT echo "pr_author=${pr_author}" >> $GITHUB_OUTPUT env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create Pull Request uses: peter-evans/create-pull-request@v5 with: token: ${{ secrets.GITHUB_TOKEN }} title: "Update generated documentation" body: | [${{ steps.load_pr.outputs.pr_title }}](${{ steps.load_pr.outputs.pr_url }}) でスキーマが更新されたのでスキーマのドキュメントも更新します commit-message: "update generated documentation" base: develop branch: feat/update-generated-docs reviewers: ${{ steps.load_pr.outputs.pr_author }} author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
実際に動かしてみた
以下の画像の差分を反映させる PR を作成します。
マージ後、GitHub Actions
が起動します。
すべての step が完了すると、スキーマ情報のドキュメントを更新する PR ができます。
差分を見ると、今回追加した teacher テーブルに関連した情報が追加されています。
詳細については画像の PR のリンクを貼りましたのでご覧ください。
余談
.tbls.yml or tbls.yml
に設定を加えることが可能と紹介しましたが、
この中で特にチームの要件にマッチしていのが、detectVirtualRelations という設定です。
detectVirtualRelations: enabled: true strategy: singularTableName
上記の設定をすることで、外部キー制約を付けていなくも user.school_id
を school.id
の外部キーとして扱ってドキュメントに反映してくれます。
この仕組みは、過去の経緯から外部キー制約を採用していない自分のチームとしては大変ありがたいものです。
以前、頑張って外部キー制約をつけて ER 図を作成したことがあったのです中々大変でした
まとめ
DB のスキーマ情報を管理する仕組みとして、tbls
と GitHub Actions
を使ったものを紹介しました。
やりたかったことをできたので、メンバーの意見を踏まえてブラッシュアップして導入をしていきたいと思います!