サンプルデータがあらかじめ入った MySQL を Docker で作成する

こんにちは。エクセルソフトの田淵です。

MySQL を Docker で動かします。

公式 Docker Hub(詳しい英語ドキュメント付き)

公式にある通り、以下のコマンドで実行するだけで起動します。

$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

ただ、デフォルトの文字コードが latan1 だったり、テーブルも何もない状態なので、予めデータが入っていたり、サーバーの文字コードや検索順序を適切に設定した状態で起動したいと思いました。

検証環境

macOS: Mojave 10.14.6
Docker Desktop: 2.1.0.3
MySQL image: 5.7 (docker pull mysql:5.7

(今回は社内に 5.x 系の MySQL があるので、それに合わせ 5.7 のイメージを使っています。恐らく 8.x 系でも問題ないのでは?と思います。)

Dockerfile を作るまで

基本的には公式の Docker Hub のドキュメントを見ながら設定すれば大丈夫だとは思います。

公式ドキュメントの「Using a custom MySQL configuration file」からが参照した部分です。

環境変数の設定

利用できる環境変数は日本語のエントリーだと

Dockerの公式MySQLイメージの使い方を徹底的に解説するよ · DQNEO起業日記

に一覧がありました。ありがたい。

公式ドキュメントの「Environment Variables」をご覧ください。

公式サンプルにある -e MYSQL_ROOT_PASSWORD=my-secret-pw をそのまま Dockerfile の環境変数 ENV として利用します。

現時点で Dockerfile は以下のようになる予定です。

FROM mysql:5.7

ENV MYSQL_ROOT_PASSWORD=my-secret-pw

実運用などでベタがきするのはちょっと… という場合は、Docker Hub の公式ドキュメント の「Docker Secrets」の項目をご覧ください。

-e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql-root のような書き方でファイルを参照することができるようです。

文字コードの設定

次に文字コードを utf8mb4 にした状態で起動してみます。(Dockerfile はまだ作っていないので -e を使っています。)

$ docker run --rm -d \
    -e MYSQL_ROOT_PASSWORD=my-secret-pw \
    -p 3306:3306 --name mysql mysql:5.7 \
    --character-set-server=utf8mb4 \
    --collation-server=utf8mb4_general_ci

1行バージョン

$ docker run --rm -d -e MYSQL_ROOT_PASSWORD=my-secret-pw -p 3306:3306 --name mysql mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci

このうち、--character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci のパラメーターの部分は公式ドキュメント「Using a custom MySQL configuration file」を使うことで解決できます。

The default configuration for MySQL can be found in /etc/mysql/my.cnf, which may !includedir additional directories such as /etc/mysql/conf.d or /etc/mysql/mysql.conf.d. Please inspect the relevant files and directories within the mysql image itself for more details.
MySQLのデフォルト設定は /etc/mysql/my.cnf にあります。これには、/etc/mysql/conf.d/etc/mysql/mysql.conf.d などの追加ディレクトリが含まれます。 詳細については、mysql イメージ内の関連ファイルとディレクトリを調べてください。

$ docker run --name some-mysql -v /my/custom:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

のように、-v オプションでローカルボリュームをコンテナの /etc/mysql/conf.d にマウントして、ローカルの /my/customcnf ファイルを置いても良いでしょう。

Dockerfile の場合はコンテナのディレクトリに以下のような my.cnf をコピーすれば良いですね。

 
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci

[client]
default-character-set=utf8mb4

現時点での Dockerfile は以下のようになる予定です。

FROM mysql:5.7

ENV MYSQL_ROOT_PASSWORD=my-secret-pw

COPY my.cnf /etc/mysql/conf.d/my.cnf

初期起動時に DB を投入する設定

テスト用の DB とか練習用の DB はデータが入っていて欲しいですよね。

私は以下の 2つのエントリーを参考にしながら /docker-entrypoint-initdb.d.sh.sql.sql.gz を置く方法を利用しました。

事前にデータ投入をした MySQL Docker イメージを作る場合は /docker-entrypoint-initdb.d を活用すると便利 - kakakakakku blog

Dockerで使い捨てのMySQL環境を用意する。事前データを投入して起動する。 - My External Storage

公式ドキュメントでは「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.
コンテナが初めて起動されると、指定された名前の新しいデータベースが作成され、提供された構成変数で初期化されます。さらに、/docker-entrypoint-initdb.d にある拡張子 .sh.sql、および .sql.gz のファイルを実行します。ファイルはアルファベット順に実行されます。SQL ダンプをそのディレクトリにマウントして、提供されたデータを含むカスタムイメージを提供することにより、mysql サービスを簡単に作成できます。 SQL ファイルは、デフォルトで MYSQL_DATABASE 変数で指定されたデータベースにインポートされます。

MySQL で公開されている world database は sql ファイルで、

  1. schema があれば drop してその後 create
  2. table があれば drop してその後 create
  3. 作成した table を使い、value を insert して commit

の流れになっていました。

この world database を使用する場合は、world.sql.gz/docker-entrypoint-initdb.d にコピーすれば良いので、Dockerfile は次のようになります。

FROM mysql:5.7

ENV MYSQL_ROOT_PASSWORD=my-secret-pw

COPY my.cnf /etc/mysql/conf.d/my.cnf
COPY world.sql.gz /docker-entrypoint-initdb.d/world.sql.gz

今回はもう少し実用的なデータで試してみたかったので、私の GitHub のリポジトリ にあるように 01_init_db.sql02_insert_data.sql を用意し、insert するデータとして郵便局の 郵便番号ダウンロード のローマ字版を使いました。(社内で英語の住所が必要になることがあり、その課題を解決したいためw)

ダウンロードした csv ファイルを Excel とちょっとしたプログラムで整形しました。

ということで、最終的には以下の Dockerfile になりました。

FROM mysql:5.7

ENV MYSQL_ROOT_PASSWORD=my-secret-pw

COPY my.cnf /etc/mysql/conf.d/my.cnf
COPY 01_init_db.sql /docker-entrypoint-initdb.d/01_init_db.sql
COPY 02_insert_data.sql /docker-entrypoint-initdb.d/02_insert_data.sql

作ってしまえば簡単ですね。

動かしてみる

作成した docker image は 私の Docker Hub にアップしてあります。

動かしてみましょう。今後他のコンテナーからもアクセスすることを想定し、docker network create mysql-network でネットワークは作成済みです。

$ docker pull ytabuchi/jp-address-db
$ docker run --name mysql --rm -d --network mysql-network -p 43306:3306 ytabuchi/jp-address-db

データが入っているか確認しましょう。

mysql> SELECT * FROM city WHERE Zip LIKE '108007%';
+-------+---------+---------------+---------+--------------------------------------+------------+-----------+-------------------------------+
| ID    | Zip     | JP-Prefecture | JP-City | JP-Address                           | Prefecture | City      | Address                       |
+-------+---------+---------------+---------+--------------------------------------+------------+-----------+-------------------------------+
| 37960 | 1080075 | 東京都        | 港区    | 港南 (次のビルを除く)             | Tokyo To   | Minato Ku | Konan (次のビルを除く)        |
| 38064 | 1080072 | 東京都        | 港区    | 白金                                 | Tokyo To   | Minato Ku | Shirokane                     |
| 38065 | 1080071 | 東京都        | 港区    | 白金台                               | Tokyo To   | Minato Ku | Shirokanedai                  |
| 38068 | 1080074 | 東京都        | 港区    | 高輪                                 | Tokyo To   | Minato Ku | Takanawa                      |
| 38389 | 1080073 | 東京都        | 港区    | 三田 (次のビルを除く)             | Tokyo To   | Minato Ku | Mita (次のビルを除く)         |
+-------+---------+---------------+---------+--------------------------------------+------------+-----------+-------------------------------+
5 rows in set (0.09 sec)

いい感じですね!

次は

データベースができたので、API を作ってみようと思います。

参考サイト

事前にデータ投入をした MySQL Docker イメージを作る場合は /docker-entrypoint-initdb.d を活用すると便利 - kakakakakku blog

Dockerで使い捨てのMySQL環境を用意する。事前データを投入して起動する。 - My External Storage

Dockerの公式MySQLイメージの使い方を徹底的に解説するよ · DQNEO起業日記

utf8mb4 に関連した寿司ビール問題については Google 検索の結果 を貼っておきます。

以上です。

タイトルとURLをコピーしました