SchemaSpyを使用してRDBからER図を自動生成する
こんにちは、PharmaX エンジニアの尾崎(@FooOzaki)です。
本記事ではSchemaSpyというツールを使ってRDBからER図を自動生成する方法をご紹介します。
SchemaSpyのDocker実行環境を準備し、ER図の自動生成&閲覧まで順を追ってご紹介するのでぜひ手軽に試してもらえればと思います。
使用感は後述の公式sampleで触ってみるのが一番わかりやすいと思うので、本記事では具体のセットアップ手順を主に紹介します。
SchemaSpyとは
SchemaSpyはデータベースのメタデータからER図を自動生成してくれるオープンソースのツールです。
SchemaSpyはJava製なので、Dockerベースとjarベース(Java製アプリケーション)の2種類で使うことができます。
データベースとの接続にはJDBCを利用しているので、JDBCドライバが提供されているDBであれば解析対象にできるかと思います。メジャーどころのMysql、Postgresql、Oracle、SQLServer等は問題なく使えるかと思います。
出力イメージと使用感
出力イメージを見てみたいという方は 公式sample を触ってみていただけると良いかと思います。
出力イメージは公式に任せることにして、実際使ってみて良かったところは以下の2点です。
リレーション推察(Railsオプション)
弊社はRuby on Railsでバックエンドサーバを構築しており、Railsの命名規則に則りリレーションを推察してくれるOption設定があったのは精度が上がって有り難かったです。(設定は後述)
テーブル個別ビュー
SchemaSpyは関連テーブルのリレーションを個別テーブル単位に閲覧可能で、テーブルごとビューが存在します。大きなDBだとリレーション線が蜘蛛の巣のように複雑なっていきがちなのでこの辺はMUST要件かなと思っていました。
HTMLベースで出力されるのでブラウザでドリルダウンしていけます。
紹介する構築手順の前提
本記事では既に動いているRDBに対して、ER図を出力してアクセスする手順をご紹介していきます。
利用シーンに併せて調整いただけるよう、複数の運用シナリオを想定して執筆しましたので導入時の参考になれば幸いです!
RDBの環境構築方法は詳しく紹介しません
既に稼働しているRDBのER図を出力したいというケースが多いのかなと思ったのと、お使いのDBもさまざまだと思うので詳しくは説明しません。
その代わり、接続先のDB環境に応じて設定変更が必要な箇所は明示してご説明ます。
Schemaspy公式Dockerイメージをそのまま使う形でご紹介します。
今の所問題なく使えていますが、実行環境やDB側の都合等によってはDockerfileで多少手を加える必要はあるかもしれません。
また、本記事ではJavaの環境をセットアップするのが面倒だったこともあり、jarベースで構築する方法には触れません。
ディレクトリ構成と運用シナリオについて
実際の運用例でご紹介した方がイメージがつきやすいかと思い、私のディレクトリ構成例や運用例でご説明していきます。
また、導入するにあたって幾つかの運用パターンは検討したので補足的にご紹介していきます。
適宜ディレクトリ構成はチューニングしていただけると良いかと思いますが、ER図を出力したいプロジェクト配下にSchemaSpy実行環境も作るような構成にしています。
project
├── app // アプリケーションのディレクトリ
├── tmp
│ └── schemaspy //SchemaSpyの出力ファイル等はtmp配下に置いてgitignore
│ └── output // SchemaSpyのドキュメント生成ディレクトリ
├ docker
│ ├── db
│ │ └── Dockerfile
│ │ └── init, confファイルとか
│ ├── docker-compose.yml // アプリケーションやDBの起動用
│ ├── schemaspy
│ │ └──schemaspy.properties // schemaspyの設定ファイル
│ └── docker-compose-schemaspy.yml // schemaspy実行・ER図閲覧用
SchemaSpyの実行はER図を見る時だけ実行する形にしたいため、composeファイルを分割しています。
docker-compose -f docker-compose-schemaspy.yml up
こんな感じでER図を見たい時に立ち上げるという運用イメージです。
ドキュメント出力だけであればrunコマンドでタスクランナー的に実行できるので、出力しなおしたいタイミングでタスクランナーやMakefile等で実行するような運用もできると思います。
こちらもComposeファイル内容をご紹介するとき補足説明しようかと思います!
SchemaSpyの設定ファイル(schemaspy.properties)の作成
SchemaSpyは schemaspy.properties
という設定ファイルをデフォルトで読み込むので、特に理由がなければこのファイル名で作成していただければ問題ありません。
以下はMySQLの設定例です。
docker/schemaspy/schemaspy.properties
# データベースのタイプを指定する
schemaspy.t=mysql
# データベースのドライバのパスを指定する
schemaspy.dp=/drivers
# データベースのホスト名を指定する
schemaspy.host=db
# データベースのポート番号を指定する
schemaspy.port=3306
# データベースの名前を指定する
schemaspy.db=db_name
# データベースのユーザ名を指定する
schemaspy.u=user
# データベースのパスワードを指定する
schemaspy.p=password
# データベースのスキーマを指定する
schemaspy.s=schema_name
# Railsベースの命名規則を使用して、Relation推察
schemaspy.rails
利用するDBごとに違いがある部分は以下のあたりかと思いますが、PostgreSQLのプロジェクトではこんな感じにしています。
schemaspy.dp=/drivers
schemaspy.t=pgsql
schemaspy.port=5432
DBドライバの設定 schemaspy.dp=/drivers
についてはドライバのパスを指定するプロパティです。
SchemaSpyの公式Dockerイメージをそのまま使うのであれば /drivers
で基本的に動作するはずです。
DockerイメージにないDBドライバーを利用する場合にはドライバーのパスを変更していただければと思います。
SchemaSpyの実行結果ドキュメントの出力先は以下で指定可能です。Dockerのファイルマウント先に関わってくるため、今回は後述のDockerの環境変数として設定をする形をとっています。
schemaspy.o=./outputdir
Railsオプション
schemaspy.rails
の設定を追加するだけで設定可能で、Railsベースの命名規則を使用して関係を推測してくれます。
例えばdocumentsテーブルにINT型のtag_idがある場合、tagsというテーブルへリレーションがあると判断してくれます。
この命名は割と一般的なので、Railsを使用していない場合も命名ルールがこのパターンであれば推察してくれます。
(補足)SchemaSpyからのDBの接続設定
DBの接続設定は特殊なプロパティはそんなにないかと思うので、一般的なRDBとDockerの知識があれば特筆する箇所はありませんが、広い読者を想定して詰まりそうなポイントだけ記載しておきます。
DBをDockerを用いずにローカルホストで立ち上げている方はSchemaSpyのDockerコンテナからローカルホストへアクセスする必要が出てきます。
ネット上に記事もたくさんあるので後述のDockerの設定と併せて調整していただければと思いますが、Dockerに詳しくない方はjarベースでDockerを使わずにローカル実行した方が手軽に試せるかもしれません。
DBをDockerで構築している場合の例は実際の設定ファイルを後でご紹介するので参考にしてもらえればと思います。
DBコンテナと同じDocker networkに内においてDBコンテナのサービス名orコンテナ名orホスト名を schemaspy.host
へ指定していただければと思います。
Docker Composeファイル作成
続いてComposeファイルです。
ディレクトリ構成の章でご説明した通り、今回は独立したComposeファイルを作成するので、docker/docker-compose-schemaspy.yml
というファイル名で作成しています。
services:
schemaspy:
container_name: app_name_schemaspy
image: schemaspy/schemaspy:snapshot
volumes:
- ./schemaspy/schemaspy.properties:/schemaspy.properties
- ../tmp/schemaspy/output:/output
environment:
SCHEMASPY_OUTPUT: /output
# memo: DBコンテナと同じDocker networkに配置できるよう設定してください
networks:
- default
nginx_schemaspy:
image: nginx
container_name: app_name_nginx_schemaspy
depends_on:
- schemaspy
ports:
- "8088:80"
volumes:
- ../tmp/schemaspy/output:/usr/share/nginx/html:ro
# memo: DBコンテナと同じDocker networkに配置できるよう設定してください
networks:
default:
name: app_name_default
以下で実行する形です。
docker-compose -f docker-compose-schemaspy.yml up
実行するとoutput用のディレクトリへドキュメントが出力されます。
今回紹介するディレクトリ構成と設定例だとproject/tmp/schemaspy/output
配下に出力されるはずです。
ファイルはたくさん出力されますが、index.html
を開いていただければトップベージを閲覧可能です。
今回は出力されたHTMLはnginx経由でブラウジング可能にしています。
nginxは導入しなくともSchemaSpyで出力したHTMLファイルを直接ブラウジングは可能です。
nginx経由だとHTMLの出力先とその配下のドキュメント群を意識する必要がなくなるので、認知負荷は下がるかと思います。
http://localhost:8088
でアクセス可能なよう設定していますが、port等は自由に設定いただければと思います。
nginxを利用しない場合はnginxのコンテナの設定は丸っと省略していただければ結構です。
その場合は、runコマンドでタスク実行していただく形でも構いません。タスクランナーやMakafile等でタスク定義することも可能かと思います。
docker-compose -f docker-compose-schemaspy.yml run --rm schemaspy
出力したファイルproject/tmp/schemaspy/output/index.html
等をブラウザで閲覧していただければOKです。
SchemaSpyコンテナの設定について
冒頭でご説明した通り、SchemaSpy公式のDockerイメージを利用しています。
schemaspy:
image: schemaspy/schemaspy:snapshot
まず、前章で作成した設定ファイルですが、/schemaspy.properties
に配置しておくと、自動で実行時に読み取ってくれます。
schemaspy:
volumes:
- ./schemaspy/schemaspy.properties:/schemaspy.properties
また、Schemaspyのドキュメント出力先は以下の環境変数で設定可能ですので、ホスト端末とマウントしておけばホストから参照可能です。
schemaspy:
environment:
SCHEMASPY_OUTPUT: /output
volumes:
- ../tmp/schemaspy/output:/output
DBと疎通する必要があるため、Docker Network名は適宜調整して、DBコンテナと同じネットワーク内に配置してください。
services:
schemaspy:
# memo: DBコンテナと同じDocker networkに配置できるよう設定してください
networks:
- default
# memo: DBコンテナと同じDocker networkに配置できるよう設定してください
networks:
default:
name: app_name_default
(参考)DB起動時にSchemaSpyも実行する
最後に、SchemaSpy実行のオーバーヘッドが気にならない方はDB起動時にSchemaSpyも実行しても良いかと思うので簡単に紹介しておきます。
MySQLで動作確認した時に使ったDBのDockerfileも載せておくので参考にしていただければと思います。
docker/db/Dockerfile
FROM mysql:8.3.0
ADD /docker/db/my.cnf /etc/mysql/my.cnf
RUN chmod 644 /etc/mysql/my.cnf
docker/docker-compose.yml
services:
db:
build:
context: ..
dockerfile: docker/db/Dockerfile
environment:
MYSQL_ROOT_HOST: "%"
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: root
container_name: app_name_db
ports:
- "3306:3306"
volumes:
- ../tmp/db:/var/lib/mysql
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
timeout: 20s
retries: 10
schemaspy:
container_name: app_name_schemaspy
image: schemaspy/schemaspy:snapshot
volumes:
- ./schemaspy/schemaspy.properties:/schemaspy.properties
- ../tmp/schemaspy/output:/output
depends_on:
db:
condition: service_healthy
environment:
SCHEMASPY_OUTPUT: /output
nginx_schemaspy:
image: nginx
container_name: app_name_nginx_schemaspy
depends_on:
- schemaspy
ports:
- "8088:80"
volumes:
- ../tmp/schemaspy/output:/usr/share/nginx/html:ro
networks:
default:
name: app_name_default
DBと同時に起動する場合はDBプロセスの立ち上がり前にSchemaSpyが実行されるとfailするので、ヘルスチェックで立ち上がったのを確認しておくのが安全だと思います。
mysqlだとこんな感じでヘルスチェックができます。他のデータベースでも類似のコマンドがあるかと思います。
services:
db:
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
timeout: 20s
retries: 10
以下のように定義すればschemaspyコンテナはdbコンテナの立ち上がりを待って実行されます。
services:
schemaspy:
depends_on:
db:
condition: service_healthy
終わりに
以上、SchemaSpyのご紹介でしたが、DB固有のパラメータやディレクトリ構成だけ読み替えてもらえればほぼコピペで動くかと思います。ぜひサクッと試していただければ幸いです。
PharmaX では、様々なバックグラウンドを持つエンジニアの採用をしております。
興味がある方はぜひ気軽にお声がけください。
もし、興味をお持ちの場合は、私の X アカウント(@FooOzaki)にお気軽にメッセージいただけますと幸いです。
まずはカジュアルにお話できれば嬉しいです!
PharmaXエンジニアチームのテックブログです。エンジニアメンバーが、PharmaXの事業を通じて得た技術的な知見や、チームマネジメントについての知見を共有します。 PharmaXエンジニアチームやメンバーの雰囲気が分かるような記事は、note(note.com/pharmax)もご覧ください。
Discussion