タグ: schemaspy

  • SchemaSpy で SQLファイル からスキーマ情報を出せるようにした

    SchemaSpy で SQLファイル からスキーマ情報を出せるようにした

    tl;dr;

    ER図などを自動生成してくれる SchemaSpy というツールがある。
    このツールは接続先のDBを指定する事でそのDBサーバのスキーマ情報を読み取って解析してくれる作りだ。
    しかし、DBに接続させたくない場合は多い。手元にcreate table文などを盛り込んだDDL文の塊を用意する事で対応できるようにした。

    対処した事

    と言っても SchemaSpy 自体をいじったわけではなく、SQLファイルを手元に用意して、DBのコンテナに読み込ませ、そのコンテナに対して SchemaSpy を叩かせるようにしただけ。

    見えてきた未来

    DBをダイレクトに繋ぎに行かずにすむ事で、ブランチごとにDB構成を管理することができるようになり、CIに組み込めばスキーマのレビューもしやすくなる。

    考えなければならなかったところ

    SchemaSpy が動く前にDBコンテナに適切にデータが作られてないといけない。

    もしテーブルが作られていないと SchemaSpy が空振りしてしまい、期待している結果に至らないからだ。そのため、DBコンテナにテーブルが作られていることを確認してから SchemaSpy が動かす必要がある。

    しかし、docker-compose では、それ自体で細かな起動順番を指定することができない。

    docker 公式ドキュメントでも以下のような記載がある。

    Compose はコンテナの準備が「整う」まで待ちません(つまり、特定のアプリケーションが利用可能になるまで待ちません)。単に起動するだけです。

    http://docs.docker.jp/compose/startup-order.html

    自分で制御するしかないようだ。起動したい順番をシーケンス図でかくとこのような感じ。

    SchemaSpyコンテナ側での制御はシンプルにシェルで行っており、mysqlに繋がったら CREATE TABLE 含むDB側の準備は完了とみなし、SchemaSpy側の実際の処理をするようにした。

    #!/bin/sh
    
    set -e
    echo $@
    
    host=$1
    shift
    user=$1
    shift
    password=$1
    shift
    cmd="java -jar schemaspy.jar"
    
    echo "Waiting for mysql"
    until mysql -h"$host" -u"$user" -p"$password" &> /dev/null
    do
            >$2 echo -n "."
            sleep 1
    done
    
    >&2 echo "MySQL is up - executing command"
    exec $cmd

    https://github.com/GitSumito/schemaspy-with-sql/blob/master/docker/schemaspy/bin/wait.sh

    MySQLに繋がったらtableも作られていると解釈するのは危険ではないかと感じるかもしれない。

    これは  mysql のコンテナの設定を用いてもう少し説明したい。

    version: '3'
    
    services:
      nginx:
        image: nginx:latest
        container_name: schemaspy_nginx
        volumes:
          - ./schemaspy:/var/www/html:ro
          - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
        ports:
          - "80:80"
        environment:
          - LANG=ja_JP.UTF-8
          - TZ=Asia/Tokyo
    
      schemaspy:
        build: ./docker/schemaspy
        image: treetips/schemaspy-mysql
        container_name: schemaspy
        volumes:
          - ./schemaspy:/app/html:rw
          - ./docker/schemaspy/config/schemaspy.properties:/app/schemaspy.properties:ro
        environment:
          - LANG=ja_JP.UTF-8
          - TZ=Asia/Tokyo
        working_dir: "/app"
        depends_on:
          - mysql
        command: "sh -x /app/bin/wait.sh mysql docker docker employee java -jar schemaspy.jar"
    # also modify db info docker/schemaspy/config/schemaspy.properties
    
      mysql:
        image: mysql:5.7
        container_name: mysql_host
        environment:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: employee
          MYSQL_USER: docker
          MYSQL_PASSWORD: docker
          TZ: 'Asia/Tokyo'
          MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
        command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
        volumes:
          - ./docker/mysql/sql:/docker-entrypoint-initdb.d
        ports:
          - 3306:3306

    https://github.com/GitSumito/schemaspy-with-sql/blob/master/docker-compose.yml

    mysqlのvolumesでは

    `./docker/mysql/sql` を`/docker-entrypoint-initdb.d`へマウントするよう設定している。

    これはMySQLコンテナの仕様で、デフォルトでこのディレクトリの`.sh`ファイル、`.sql`ファイル、 `.sql.gz`ファイル があれば初期化段階で読み込み、MYSQL_DATABASEに指定したデータベースに作られる。

    Initializing a fresh instance

    When a container is started for the first time, a new database with the specified name will be created and initialized with the provided configuration variables. Furthermore, it will execute files with extensions .sh.sql and .sql.gz that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. You can easily populate your mysql services by mounting a SQL dump into that directory and provide custom images with contributed data. SQL files will be imported by default to the database specified by the MYSQL_DATABASE variable.

    https://hub.docker.com/_/mysql

    念のためdocker-compose をupしてログを確認してみると、`mysqld: ready for connections.`になる前に、実行されている。

    mysql_host   | 2020-01-19 23:12:16+09:00 [Note] [Entrypoint]: Creating database employee
    mysql_host   | 2020-01-19 23:12:16+09:00 [Note] [Entrypoint]: Creating user docker
    mysql_host   | 2020-01-19 23:12:16+09:00 [Note] [Entrypoint]: Giving user docker access to schema employee
    mysql_host   | 
    mysql_host   | 2020-01-19 23:12:17+09:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/001-create-tables.sql
    (中略)
    mysql_host   | 2020-01-19T14:12:20.391989Z 0 [Note] mysqld: ready for connections.
    mysql_host   | Version: '5.7.29'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)

    使ってみる

    githubに置いておいたので適宜clone

    git clone https://github.com/GitSumito/schemaspy-with-sql.git
    make build
    make up
    

     その後、自分のPCにhttp接続するとSchemaSpyが作ったアウトプットを見ることができる。schemaspy-1

    ER図はこのような感じ。非常に見やすい。

    なお、今回はMySQLで公開されているemployeeテーブルから一部情報を使って描写した。

    https://github.com/datacharmer/test_db/blob/master/employees.sql

    手取り早く手元のDDLに置き換えたい場合は、

    schemaspy-with-sql/blob/master/docker/mysql/sql/001-create-tables.sql

    ファイルの中身を変更してdocker-composeを起動するだけでSchemaSpyを起動させることができるようにしてある。

    最後に

    Migraiton ファイルをそのまま読み込ませることができればもっと便利になると思うので、次回はその対処を行いたいと思う。