こんにちは。エクセルソフトの田淵です。
MySQL を Docker で動かします。
公式にある通り、以下のコマンドで実行するだけで起動します。
$ 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/custom
に cnf
ファイルを置いても良いでしょう。
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 theMYSQL_DATABASE
variable.
コンテナが初めて起動されると、指定された名前の新しいデータベースが作成され、提供された構成変数で初期化されます。さらに、/docker-entrypoint-initdb.d
にある拡張子.sh
、.sql
、および.sql.gz
のファイルを実行します。ファイルはアルファベット順に実行されます。SQL ダンプをそのディレクトリにマウントして、提供されたデータを含むカスタムイメージを提供することにより、mysql サービスを簡単に作成できます。 SQL ファイルは、デフォルトでMYSQL_DATABASE
変数で指定されたデータベースにインポートされます。
MySQL で公開されている world database は sql ファイルで、
- schema があれば drop してその後 create
- table があれば drop してその後 create
- 作成した 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.sql
と 02_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 検索の結果 を貼っておきます。
以上です。