code & booze

自己学習とは無縁なSIer業界に身を置くエンジニアがアウトプットします

Dockerで初期データを投入してMySQLコンテナを起動する

docker MySQL

DockerでMySQLコンテナを立ち上げた時の手順、および初期データ投入時に注意することのメモ。

MySQL on Docker

現在はさまざまなソフトウェアがコンテナ化されていますが、MySQLも当然ながらコンテナ化されています
今までは、ちょっといじってみたい時でもローカルPCにインストールしてセットアップする作業がありましたからね。ありがたいことです。

ちなみに、MySQL以外のDBMSとしては↓のようなものがあります。コンテナを使えば何でも試せますね!

MySQLコンテナを使ってみる

実際にMySQLをコンテナで起動してみます。
DockerコマンドからとDockerfile/docker-compose.ymlに定義してからの起動の2通りで試します。

Dockerコマンドから起動する

まずは一番簡単な方法であるDockerコマンドで、MySQLを起動してみます。
といっても何も難しいことはなく、Docker Hubにも起動コマンドが載っています。

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

docker runコマンドで起動します。ローカルにコンテナイメージが存在しない場合でも、runコマンドであればイメージの取得から処理されるので本当にこれだけで起動できてしまいます。
使うオプションの意味は↓になります。

option 意味
--name 起動するコンテナに明示的に名前を指定する
-e 環境変数を設定する
-d コンテナをバックグランドで実行する

上記を踏まえて、以下のコマンドで実際に実行してみます。今回はMySQL5.7を使用するため、Tagで"5.7"を指定します。

$ docker run --name mysql_test -e MYSQL_ROOT_PASSWORD=password -d mysql:5.7

f:id:kiy-s:20190313120901p:plain

私の環境では既にローカルPCにMySQL:5.7のイメージが存在していたため、イメージのpullは行われていませんが、問題なく起動しました。

試しにexecコマンドでbashを起動して、MySQLに接続してみます。

$ docker exec -it mysql_test bash
root@399409de641b:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.25 MySQL Community Server (GPL)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

database一覧↓

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

良い感じですね。あとは適当にDB・テーブル作って色々試せます。

ただ、このままだとデータの永続化をしておらずコンテナを削除した場合データがふっとんでしまいます。。
また、コマンド実行というのは、構成管理できず基本的にはイケてない方法なのでファイルに定義したやり方を次に試したいと思います。

Dockerfile/docker-compose.ymlから起動する

次に、コマンドから起動ではなく、定義ファイルからのコンテナ起動を行います。
ついでに、コンテナを削除してもデータが消えないように、データの永続化をするようにもしてみます。

フォルダ構成は以下。

mysql
    │  docker-compose.yml
    │  Dockerfile
    │  my.cnf
    │
    └─InitData
            init.sql

まずはdocker-compose.ymlを定義します。

version: '3'
services:
  db:
    build: .
    container_name: mysql_test
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: testdb
      TZ: Asia/Tokyo
    volumes:
      - db-data:/var/lib/mysql
    command: mysqld
volumes:
  db-data:

環境変数をセットできるenvironmentMYSQL_DATABASETZを指定しています。

MYSQL_DATABASEは設定することでイメージの初回起動時にDBを作成してくれます。
TZタイムゾーン指定です。

トップレベルのvolumesで"db-data"というボリュームを作成するようにしています。それをdb以下のvolumesでコンテナの"/var/lib/mysql"を"db-data"にマウントします。
これにより、mysqlコンテナを削除してしまってもvolumeのdb-dataにデータが保持されているのでデータが消し飛ぶことがなくなります。

次にDockerfile

FROM mysql:5.7

# MySQLの設定
COPY ./my.cnf /etc/mysql/conf.d/my.cnf
# 初期投入データ
COPY ./InitData/init.sql /docker-entrypoint-initdb.d

文字コード設定のために用意したMySQL設定ファイルの"my.cnf"をコンテナの"/etc/mysql/conf.d/my.cnf"へコピーします。
続けて初期投入データ用のinit.sqlをコンテナの"/docker-entrypoint-initdb.d"へコピーします。

初期データですが、docker-entrypoint-initdb.dへ~.sql, ~.sh, ~sql.gzを拡張子にもつファイルをコピーしておくと、コンテナ初回起動時に自動で実行してくれます。

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.

Docker Hub

my.cnfにはutf8を使うよう文字コードの設定を記載しておきます↓

[mysqld]
character-set-server=utf8

[mysql]
default-character-set=utf8

[client]
default-character-set=utf8

最後にinit.sql↓。初期投入用の適当なsqlです。

CREATE TABLE sample_table (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(30) NOT NULL,
    comment TEXT NOT NULL,
    createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

insert into sample_table
    (name, comment)
values
    ('テストName1', 'テストcomment1'),
    ('テストName2', 'テストcomment2'),
    ('テストName3', 'テストcomment3'),
    ('テストName4', 'テストcomment4'),
    ('テストName5', 'テストcomment5'),
    ('テストName6', 'テストcomment6');

これで必要なファイルがそろったので、起動してみます。
docker-compose.ymlがある場所で以下のコマンドを実行します。

最初にビルドしてイメージを作成します。

$ docker-compose build

バックグラウンドでコンテナを起動します。

$ docker-compose up -d

f:id:kiy-s:20190313142253p:plain

ビルド後、コンテナが正常に起動できていることを確認できました。

init.sqlが実行されているか確認してみます。

execコマンドからコンテナでbashを起動し、MySQLへ接続して確認します。

$ docker exec -it mysql_test bash

f:id:kiy-s:20190313142941p:plain

ちゃんとinit.sqlに定義したsqlが実行されていることが確認できました!

また、volumeによってデータの永続化もできているので、コンテナを削除してもMySQLのデータが消えることはありません。
ただし、当たり前ですが、volumeを削除すると消えてしまうので注意してください。

特に、docker-compose downコマンドはファイルに定義したコンテナを一度に停止・削除までやってくれるので便利ですが、docker-compose.ymlに定義されたvolumeまで削除されてしまうので注意してください。

初期データ投入の条件

MySQLコンテナはdocker-entrypoint-initdb.dsqlファイルをコピーしておくと、コンテナ初回起動時に自動実行してくれます。

ですが、volumeを使っている場合に1点注意することがあります↓

マウントしたvolumeにMySQLのデータが存在すると、コンテナが初回起動の場合でも、初回起動とみなされず"docker-entrypoint-initdb.d"にあるsqlは実行されません。

当たり前といえば当たり前ですが、私は最初、この挙動についてあまり理解しおらずだいぶはまりました。。 これからやる人はぜひ気を付けてください。。

Dockerコマンド

今回はDockerコマンドについてあまり詳しく説明しませんでしたので関連および公式ドキュメントをリンクしておきます。

docs.docker.jp

docs.docker.jp

docs.docker.com