docker compose upだけでSchemaSpyを同時起動!!
はじめに
この記事は エンジニア組織の開発生産性・開発者体験向上の取り組みをシェアしよう! by Findy Advent Calendar 2023 シリーズ3 の21日目の記事となります。
株式会社DELTAでエンジニアをしている長田(おさだ)です。
既存のデータベースからER図を出力してくれるSchemaSpyを導入しようとしたものの、『docker compose up
[1]の一発実行で他のサービスと一緒にSchemaSpyも同時に起動できるようにする』を実現させようとしているうちに、色々とハマって時間を溶かしてしまったので備忘録として残したいと思います。
背景
私たちの開発チームではdocker compose up
の一発実行だけでデータベースやAPIサーバー・フロントエンドまで全てのサービスを起動させることで、開発環境のセットアップを効率化して開発者間の環境差異も最小限にしています。
今回はSchemaSpyも同じ様に導入しようと思ったものの、別々に起動する方法の記事が多かったことと、個人的にもDockerについて知らない部分を学ぶ機会になったので記事にしました。
とはいえ、SchemaSpyの導入方法を主軸にしていますので、SchemaSpyを導入しようと思ったときに役に立てれば幸いです。
結果
以下の構成にすることで同時起動が可能になります
実行環境
❯ docker compose version
Docker Compose version v2.22.0-desktop.2
❯ docker --version
Docker version 24.0.6, build ed223bc820
ディレクトリ構成
├── compose.yml
└── schemaspy
├── Dockerfile.dev
├── output // SchemaSpyによって生成されたドキュメント
│ ├── anomalies.js
│ ├── bower
│ ├── column.js
│ ├── constraint.js
│ ├── favicon.png
│ ├── fonts
│ ├── images
│ ├── index.html
│ ├── main.js
│ ├── public
│ ├── relationships.js
│ ├── routines
│ ├── routines.js
│ ├── schemaSpy.css
│ ├── schemaSpy.js
│ └── tables
└── schemaspy.properties
services:
db:
container_name: postgres_db
image: postgres:15.3
restart: always
ports:
- 5432:5432
networks:
- app_network
environment:
- TZ=Asia/Tokyo
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- database:/var/lib/postgresql/data
healthcheck:
test: "psql -U postgres"
interval: 3s
timeout: 3s
retries: 5
schemaspy:
build:
context: .
dockerfile: ./schemaspy/Dockerfile.dev
container_name: schemaspy
image: schemaspy/schemaspy
networks:
- app_network
volumes:
- ./schemaspy/output:/schemaspy_output
- ./schemaspy/schemaspy.properties:/schemaspy.properties
command: "java -jar schemaspy.jar -vizjs"
depends_on:
db:
condition: service_healthy
nginx_schemaspy:
image: nginx
container_name: "nginx_schemaspy"
depends_on:
- schemaspy
ports:
- "8088:80"
volumes:
- ./schemaspy/output:/usr/share/nginx/html:ro
volumes:
database:
networks:
app_network:
FROM openjdk:11-jdk
RUN apt-get update && apt-get install -y fontconfig fonts-dejavu && \
wget -O schemaspy.jar https://github.com/schemaspy/schemaspy/releases/download/v6.2.4/schemaspy-6.2.4.jar && \
wget -O /postgresql.jar https://jdbc.postgresql.org/download/postgresql-42.6.0.jar && \
rm -rf /var/lib/apt/lists/*
# データベースのタイプをpgsqlで指定
schemaspy.t=pgsql
# schemaspyのコンテナ内でのJDBCドライバのパス
# Dockerfile.devで`wget -O /postgresql.jar~~~`とルート直下で指定している
schemaspy.dp=/postgresql.jar
# データベースのプロパティを指定
# hostはサービス名を指定(コンテナ名ではない)
schemaspy.host=db
schemaspy.port=5432
# dbはコンテナ作成時に指定していないためデフォルトのpostgres
schemaspy.db=postgres
schemaspy.u=postgres
schemaspy.p=postgres
# schemaspyのコンテナ内での出力先
schemaspy.o=./schemaspy_output
# どのデータベーススキーマに対して生成するか指定。pgsqlはpublicと指定
schemaspy.schemas=public
結論
- SchemaSpyの起動
- データベースとSchemaSpyのコンテナ間アクセス
- SchemaSpyコンテナの出力とホスト側へのデータ受け渡し
- SchemaSpyの生成したデータへホスティング
を順番に整理していくことでdocker compose up
の一発起動による開発環境の構築が可能になりました。
動作確認と一部解説
動作確認
上記「結果」の構成をまるっと導入することでSchemaSpyによって生成されたHTMLにNginxを通じてアクセス(localhost:8088)できるようになります。が、テーブル定義がないためリレーションの画面では下記のようなエラーが出ています。
テーブルが作成されてないので当然です。
テーブル定義
そこで、テーブル作成して動作確認をします。
以下のコマンドでpostgres_dbへアクセスして
docker exec -it postgres_db psql -U postgres
以下のSQLを流します
CREATE TABLE IF NOT EXISTS clinics (
"id" serial PRIMARY KEY,
"name" VARCHAR (256) NOT NULL,
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS departments (
"id" serial PRIMARY KEY,
"name" VARCHAR (256) NOT NULL,
"clinic_id" INT, -- 外部キーとしてクリニックIDを追加
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY ("clinic_id") REFERENCES clinics ("id") ON DELETE SET NULL -- 外部キー制約を追加
);
CREATE TABLE IF NOT EXISTS patients (
"id" serial PRIMARY KEY,
"name" VARCHAR (256) NOT NULL,
"sex" VARCHAR (256) NOT NULL,
"clinic_id" INT, -- 外部キーとしてクリニックIDを追加
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY ("clinic_id") REFERENCES clinics ("id") ON DELETE SET NULL
);
CREATE TABLE IF NOT EXISTS treatments (
"id" serial PRIMARY KEY,
"name" VARCHAR (256) NOT NULL,
"department_id" INT, -- 外部キーとして診療科IDを追加
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY ("department_id") REFERENCES departments ("id") ON DELETE SET NULL
);
SchemaSpyコンテナの再起動
SchemaSpyにはデータベースの変更を自動的に検出して出力を更新する機能がないので再読み込みをする必要がありますので、SchemaSpyコンテナを再起動します。
docker-compose restart schemaspy
http://localhost:8088/public/relationships.htmlにアクセスしてみることで以下のようにER図が作成されていることが確認できます。
SchemaSpyを起動してPostgreSQLにアクセスできるようにする
SchemaSpyのDockerfile.dev
SchemaSpy本体の他にPostgreSQLのJDBC Driverが必要になります。
Dockerfile.devでSchemaSpyのコンテナ内にダウンロードして、schemaspy.propertiesで使用するための指定をしています。
上記のDockerfile.devとschemaspy.propertiesの該当部分を再記載
# SchemaSpyのダウンロード
wget -O schemaspy.jar https://github.com/schemaspy/schemaspy/releases/download/v6.2.4/schemaspy-6.2.4.jar && \
# PostgreSQLのJDBC Driverのダウンロード
wget -O /postgresql.jar https://jdbc.postgresql.org/download/postgresql-42.6.0.jar && \
rm -rf /var/lib/apt/lists/*
# schemaspyのコンテナ内でのJDBCドライバのパス
# Dockerfile.devで`wget -O /postgresql.jar~~~`とルート直下で指定している
schemaspy.dp=/postgresql.jar
データベースとSchemaSpyのコンテナ間アクセス
schemaspy.propertiesのhost
schemaspy.propertiesのコメントでも記載していますが、サービス名を指定します。
コンテナ名を指定していたため、アクセスできずに時間を溶かしました。
schemaspy.propertiesの該当部分を再記載
# データベースのプロパティを指定
# hostはサービス名を指定(コンテナ名のpostgres_dbではない)
schemaspy.host=db
schemaspy.port=5432
# dbはコンテナ作成時に指定していないためデフォルトのpostgres
schemaspy.db=postgres
schemaspy.u=postgres
schemaspy.p=postgres
SchemaSpyで出力されたドキュメントをホストへ受け渡し
ここは基本的なコンテナとホストのデータ受け渡しについて理解が曖昧でハマりました。
識別しやすいようにホスト側を/schemaspy/output
で、SchemaSpy側を/schemaspy_output
としています。
schemaspy.propertiesの該当部分を再記載
# schemaspyのコンテナ内での出力先
schemaspy.o=./schemaspy_output
schemaspy:
build:
context: .
dockerfile: ./schemaspy/Dockerfile.dev
container_name: schemaspy
image: schemaspy/schemaspy
networks:
- app_network
volumes:
# ここでホスト側へ受け渡し
- ./schemaspy/output:/schemaspy_output
- ./schemaspy/schemaspy.properties:/schemaspy.properties
command: "java -jar schemaspy.jar -vizjs"
depends_on:
db:
condition: service_healthy
SchemaSpyのホスティング
もともとローカル環境の開発で使用しているものに追加していて、記載しているものの他ににAPIサーバーやnext.jsの起動もしています。
またCloudBeaverを8080
で起動していたため、8088
というポート番号にしています。
schemaspy.propertiesの該当部分を再記載
nginx_schemaspy:
image: nginx
container_name: "nginx_schemaspy"
depends_on:
- schemaspy
ports:
- "8088:80"
volumes:
- ./schemaspy/output:/usr/share/nginx/html:ro
おわりに
SchemaSpy導入を主軸に、私たちの開発チームが開発環境を効率化していることについて書かせてもらいました。これまで私はサーバーサイドのアプリケーション開発が中心でしたが、チームの変化に伴い、ミドルウェアの実装やビジネスサイドとの対話など、新たな役割にも取り組むようになっています。
手を動かすような実装タスクが減って技術から離れているわけではなく。むしろ、他の開発者が快適に作業できる環境を整えること、将来的なサービス展開を見据えた設計を考えることで、技術のキャッチアップの観点が変わり、より総合的な技術力の向上につながっていると思っています。
Docker Composeを使った開発環境の自動化は、単に作業を楽にするだけではなく、チーム全体の生産性を高め、より創造的な作業に集中できるようにしてくれます。他の開発チームやエンジニアにとって、少しでも参考になれば幸いです。
We're Hiring!
最後までお読みいただきありがとうございます。
株式会社DELTAでは仲間を募集中です!!
まずはカジュアル面談からできればと思います、ぜひPittaから
またはGoogle Formから お申込みください!
-
今はハイフンなしのcomposeになったようです。
docker-compose up
で止まっていたので勉強になりました。Docker Compose 概要 ↩︎
Discussion