White Box技術部

WEB開発のあれこれ(と何か)

【MySQL 8向け】MyBatis Migrationsのコンテナ化

JVM系のマイグレーションツールの導入

新しくSpring Bootの開発環境をコンテナ上で作る上で、DBマイグレーションツールのMyBatis Migrationsをコンテナで使えるようしたので、その手順をまとめておきます。

f:id:seri_wb:20190605223604p:plain

Docker Composeの構成

作っていた開発環境のマイグレーション関連部分に絞ってディレクトリ構成を表すと、以下のようになっています。

$ tree -d
.
├── sample
│   └── migration
│       ├── drivers
│       └── sample
│           ├── environments
│           └── scripts
└── mysql
    ├── conf.d
    ├── data
    ├── log
    ├── sql
    └── tmp
        └── data

プロジェクトルートにdocker-compose.ymlを置き、それ起因でコンテナを運用するようにしています。

マイグレーション自体はdocker composeを持つリポジトリとは別で管理しているので、 アプリケーション名のディレクトリ(ここではsample)配下に、migrationディレクトリとしてgit cloneして利用するイメージです。

  • docker-compose.yml
version: '3.7'
services:
  migration:
    build:
      context: ./sample/migration/
    image: sample-migration
    container_name: sample_migration
    command: /bin/bash
    tty: true
    working_dir: "/sample/migration"
    volumes:
      - ./sample/migration:/sample/migration:cached
    depends_on:
      - db

  db:
    image: mysql:8
    container_name: sample_db
    environment:
      MYSQL_ROOT_PASSWORD: "root"
      #MYSQL_DATABASE: "sample"
      MYSQL_USER: "admin"
      MYSQL_PASSWORD: "admin"
    volumes:
      - ./mysql/sql:/docker-entrypoint-initdb.d
      - ./mysql/conf.d:/etc/mysql/conf.d
      - ./mysql/data:/var/lib/mysql
      - ./mysql/tmp/data:/tmp/data
      - ./mysql/log:/var/log/mysql
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    ports:
      - "3306:3306"

このdocker-compose.ymlでは、MySQL 8のコンテナを立ち上げ、その後マイグレーション用のコンテナを立ち上げています。

MySQLのコンテナイメージ

MySQLのコンテナイメージでは、MYSQL_DATABASEを指定することで、予めDBを作成することもできるのですが、 DBは複数利用することを考え、コンテナイメージ作成時に実行されるinit.sqlで作成するようにしています。

CREATE DATABASE sample CHARACTER SET utf8mb4;
GRANT ALL ON *.* TO 'admin'@'%' WITH GRANT OPTION;
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'admin';
CREATE USER 'admin'@'127.0.0.1' IDENTIFIED BY 'admin';
FLUSH PRIVILEGES;
MyBatis Migrationsのコンテナイメージ

本題のMyBatis Migrationsのコンテナイメージは、OpenJDKのイメージをベースに作成します。

  • sample/migration/Dockerfile
FROM openjdk:11-slim

RUN apt-get update && apt-get install -y \
        wget \
        unzip \
    && apt-get clean \
    && rm -rf /var/lib/apt

RUN wget https://github.com/mybatis/migrations/releases/download/mybatis-migrations-3.3.5/mybatis-migrations-3.3.5-bundle.zip \
    && unzip mybatis-migrations-3.3.5-bundle.zip -d /usr/local \
    && rm mybatis-migrations-3.3.5-bundle.zip

ENV MYBATIS_MIGRATIONS_HOME /usr/local/mybatis-migrations-3.3.5
ENV PATH $PATH:$MYBATIS_MIGRATIONS_HOME/bin

WORKDIR /sample/migration

COPY . .
CMD ["/bin/bash"]

docker-compose up -d後(コンテナイメージ起動後)、コンテナに入ってマイグレーションスクリプトのテンプレートを作成します。

mkdir sample
cd sample
migrate init

この際、コマンド実行ディレクトリにdriversディレクトリが作成されますが、複数DBのスクリプト管理をすることを考え、WORKDIR配下にdriversを移動させます。

実際に利用するMySQLJDBCコネクタは、以下からダウンロードし、先ほどのディレクトリに配置してください。

その後、プロパティの以下を生成された値から変更します。

  • time_zoneをAsia/Tokyoに
  • script_char_setをアンコメント
  • JDBCに必要な設定を追加(driverのクラスに注意)
  • send_full_scriptをアンコメントしてfalseに
  • driver_pathをJDBCコネクタを配置したコンテナ内の絶対パス

  • sample/migration/sample/environments/development.properties

## Base time zone to ensure times are consistent across machines
time_zone=Asia/Tokyo

## The character set that scripts are encoded with
script_char_set=UTF-8

## JDBC connection properties.
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://db:3306/sample
username=admin
password=admin

#
# A NOTE ON STORED PROCEDURES AND DELIMITERS
#
# Stored procedures and functions commonly have nested delimiters
# that conflict with the schema migration parsing.  If you tend
# to use procs, functions, triggers or anything that could create
# this situation, then you may want to experiment with
# send_full_script=true (preferred), or if you can't use
# send_full_script, then you may have to resort to a full
# line delimiter such as "GO" or "/" or "!RUN!".
#
# Also play with the autocommit settings, as some drivers
# or databases don't support creating procs, functions or
# even tables in a transaction, and others require it.
#

# This ignores the line delimiters and
# simply sends the entire script at once.
# Use with JDBC drivers that can accept large
# blocks of delimited text at once.
send_full_script=false

# This controls how statements are delimited.
# By default statements are delimited by an
# end of line semicolon.  Some databases may
# (e.g. MS SQL Server) may require a full line
# delimiter such as GO.
# These are ignored if send_full_script is true.
delimiter=;
full_line_delimiter=false

# If set to true, each statement is isolated
# in its own transaction.  Otherwise the entire
# script is executed in one transaction.
# Few databases should need this set to true,
# but some do.
auto_commit=false

# If set to false, warnings from the database will interrupt migrations.
ignore_warnings=true

# Custom driver path to allow you to centralize your driver files
# Default requires the drivers to be in the drivers directory of your
# initialized migration directory (created with "migrate init")
driver_path=/sample/migration/drivers

# Name of the table that tracks changes to the database
changelog=CHANGELOG

# Migrations support variable substitutions in the form of ${variable}
# in the migration scripts.  All of the above properties will be ignored though,
# with the exception of changelog.
# Example: The following would be referenced in a migration file as ${ip_address}
# ip_address=192.168.0.1

これで準備完了です。

使い方

実際に利用する際は、initしたときのように起動後にコンテナ内に入ってmigrate upを実行でもいいですが、以下のように直接実行することもできます。

$ docker-compose up -d
$ docker-compose exec migration bash -c "cd sample && migrate up"

初回の起動スクリプトなどを組む場合は、こちらの使い方が便利です。

手順は以上です。よいコンテナライフを!