Dockerを利用することで異なるバージョンのMySQL開発環境を構築することができます。また作成したDocker上のMySQLはDocker上の他のコンテナから利用できるだけではなくDocker上にないローカル環境のアプリケーション(本文書ではLaravel)からも利用することができます。ローカルに直接MySQLをインストールしたくない場合やバージョンをすぐに切り替えたい場合、バージョン毎に動作検証を行いたい場合に利用することができます。

本文書の動作確認はMacを利用して行っています。

Dockerのインストール

Dockerを利用するためにはDockerのインストールを行う必要があります。DockerのインストールはHomebrewを利用して行います。

Dockerのインストールは公式サイトからDocker Desktop for Macをダウンロードしてインストールすることもできます。

 % brew cask install docker
インストールする時はcaskのdockerをインストールしてください。

brewコマンド実行後アプリケーションフォルダにDockerのアイコンが作成されているのでダブルクリックを行ってください。Docker Desktop for Macのインストールが開始し、ユーザのパスワードの確認画面が表示されるのでパスワードを入力してください。

Dockerアプリケーション
Dockerアプリケーション

インストール完了後、docker -vコマンドを実行しバージョン情報が表示されるか確認してください。


 % docker -v
Docker version 19.03.5, build 633a0ea

MySQLのコンテナの作成

Dockerのインストールが完了したので早速MySQLのコンテナの作成を行います。

Dockerでコンテナを作成するためにはコンテナの元になるimageが必要になりますが、下記のコマンドを実行するとimageをダウンロードした後にコンテナの作成まで行ってくれます。


 % docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -p 3306:3306 -d mysql:tag

-nameの後には任意のコンテナ名をつけることができコンテナの起動・停止・削除に利用することができます。MYSQL_ROOT_PASSWORDにはMySQLのrootのパスワードを設定します。-pはポートの設定を行います。mysql:tagのタグにはMySQLのバージョンを指定します。latestを設定すると最新版、5.7を指定するバージョン5.7をインストールすることができます。-dをつけるとバックグランドで起動し、つけない場合はフォアグランドで起動し起動メッセージがコンソールに表示されます。

-eで設定しているのは環境変数でMYSQL_ROOT_PASSWORD以外にもMYSQL_DATABASE、MYSQL_USER、MYSQL_PASSWORDがあります。

実際に5.7のバージョンを設定してコンテナを作成します。コンテナ名はmysql5.7、ルートのパスワードはpassword、バージョンは5.7、ポートは3306を設定しています。


 % docker run --name mysql5.7 -e MYSQL_ROOT_PASSWORD=password -p 3306:3306 -d mysql:5.7  
Unable to find image 'mysql:5.7' locally
5.7: Pulling from library/mysql
 ・

実行のメッセージに表示されている通り、mysql5.7のイメージがローカルにない(Unable to find image ‘mysql:5.7’ locally)のでダウンロード(Pull)を行います。そのため初回の起動には時間がかかります。バージョン5.7のMySQLを再度別のコンテナ名で作成したり、再作成する場合はイメージのダウンロードは行われないため起動時間も短くなります。

作成したコンテナを確認します。docker ps -aでは設定したポートやコンテナの名前、起動状態を確認することができます。


 % docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
65fcabee4e36        mysql:5.7           "docker-entrypoint.s…"   7 seconds ago       Up 6 seconds        0.0.0.0:3306->3306/tcp, 33060/tcp   mysql5.7
dockerではコンテナの状態を一覧表示するためにdocker psコマンドを頻繁に使います。psはprocess snapshotの略です。

MySQLコンテナへの接続

Docker上のMySQLコンテナへの接続は以下のコマンドで行うことができます。ログイン後は、mysqlコマンドを使ってMySQLに接続することも可能です。コンテナのベースはLinuxなのでlsやcd等のコマンドを実行することができますがviなどのファイルを編集するコマンドはインストールされていません。


 % docker exec -it mysql5.7 /bin/bash                                            
root@65fcabee4e36:/# uname -a
Linux d2330dd35421 4.19.76-linuxkit #1 SMP Thu Oct 17 19:31:58 UTC 2019 x86_64 GNU/Linux
root@65fcabee4e36:/# vi
bash: vi: command not found

MySQLへの接続

Docker上のコンテナにあるMySQLにはコマンドを利用して直接接続することもできます。パスワードを聞かれるので作成時に指定したMYSQL_ROOT_PASSWORDの設定値を指定します。


 % docker exec -it mysql5.7 mysql -u root -p         
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.29 MySQL Community Server (GPL)
 ・
 ・

ログインのメッセージからMySQLのバージョンは5.7.29であることが確認できます。

データベースの作成

MySQLへのログインができればデータベースの作成も行うことができます。


mysql> create database test;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+

テーブルの作成

作成したtestデータベースにusersテーブルを作成してデータが挿入できることを確認します。


mysql> connect test;
Connection id:    3
Current database: test

mysql> create table users(id int(6) auto_increment primary key, name varchar(30));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into users(name) values('John');
Query OK, 1 row affected (0.01 sec)

mysql> select * from users;
+----+------+
| id | name |
+----+------+
|  1 | John |
+----+------+
1 row in set (0.00 sec)

日本語対応

ここまでの設定で、データベース、テーブルの作成、行の挿入(アルファベットの文字列)を行うことができますが、日本語を入力しようとするとエラーが発生し挿入することができません。

データベース管理GUIのTablePlusを利用して日本語を挿入するとIncorrect string value: ‘\xE4\xBC\x8A\xE8\x97\xA4’ for column ‘name’ at row 1
All changes were reverted (DDL statements can’t be reverted).が表示され挿入できません。

理由はMySQLの文字コードのデフォルトがlatin1に設定されているためです。文字コードはMySQLに接続して下記のコマンドで確認することができます。


mysql> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
データベース作成時にdefault character set utf8mb4を追加するとテーブルへの日本語挿入を行うことができます。またTablePlusやSequel Proなどのソフトウェアを利用するとデーターベース作成時に文字コードの選択画面が表示されます。

日本語の設定(コマンド編)

データベースのテーブルに日本語を挿入するためにはコンテナを作成時のコマンドに文字コードに関連するオプションを追加することで実現できます。

作成したコンテナを再作成するために一度作成したMySQLのコンテナを削除します。docker stopで停止し、docker rmで削除することができます。


 % docker stop mysql5.7
mysql5.7
 % docker rm mysql5.7
mysql5.7

文字コードを作成して再作成します。その際は–character-set-server=utf8mb4 –collation-server=utf8mb4_unicode_ciを追加します。


 % docker run --name mysql5.7 -e MYSQL_ROOT_PASSWORD=password -p 3306:3306 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci 
b7a8beecca73b3c6247b853a79fba5fee26901dc702847945ee8def0e38d58f8

docker ps -aコマンドで作成したコンテナが起動していることを確認してください。


 % docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
b7a8beecca73        mysql:5.7           "docker-entrypoint.s…"   8 seconds ago       Up 7 seconds        0.0.0.0:3306->3306/tcp, 33060/tcp   mysql5.7

起動していない場合はコマンドやオプションの入力ミスの可能性があります。その場合はdocker logs mysql5.7を実行して原因を確認してください。

コンテナに接続し、再度文字コードを確認します。character_set_databaseやcharacter_set_serverの文字コードはlatin1から設定したutf8mb4に変更されていることが確認できます。しかしcharacter_set_clientとcharacter_set_connectionはlatin1のままです。


mysql> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec

この設定のままデータベースを作成してもテーブルへは日本語の文字を挿入することができます

docker runを実行時に–character_set_client等があるか確認したのですが、そのようなパラメータはないとエラーになりコンテナを起動することができませんでした。設定できるパラメータと初期値はdocker run -it –rm mysql:5.7 –verbose –helpコマンドで確認することができます。

日本語設定(cnfファイル編)

character_set_clientも含めた文字コードをutf8mb4に設定するためにMySQLのcnfファイルのフォルダをdocker runコマンド時に指定することで実現することができます。

任意の場所にフォルダを作成し、そのフォルダの中にmysql5.7.cnfという名前のファイルを作成し以下の設定を記述します。

本環境ではユーザのホームディレクトリの下にmysql_confフォルダを作成していします。ファイル名も拡張子にcnfが付けば名前は任意です。その他のMySQLに関する設定もこのファイルで行うことができます。

[mysqld]
character-set-server=utf8mb4

[client]
default-character-set=utf8mb4

docker runコマンドを実行する際はファイルではなく保存したフォルダを指定して以下のように実行します。


 % docker run -v /Users/reffect/mysql_conf:/etc/mysql/conf.d/ --name mysql5.7 -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql:5.7
-vオプションを使うとローカルフォルトとコンテナ上のフォルダのリンクを貼ることができます。-v ローカルのパス:コンテナ上のパス

MySQLコンテナに接続して文字コードを確認します。文字コードが指定した通りに設定されていることが確認できます。


mysql> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8mb4                    |
| character_set_connection | utf8mb4                    |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | utf8mb4                    |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)

データの保存先

MySQLのデータはコンテナ上の/var/lib/mysqlに保存されます。そのためコンテナの再作成を行うと再作成前に追加したデータはすべて削除されてしまいます。データを保持したい場合は、コンテナの外にフォルダを作成しコンテナ上の/var/lib/mysqlとリンクを貼ることで実現することができます。

データが保持できないとは

データが保持できることを確認する前に保持でないとはどういうことか確認しておきます。


 % docker run -v /Users/reffect/mysql_conf:/etc/mysql/conf.d/ --name mysql5.7 -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql:5.7

mysqlに接続します。


 % docker exec -it mysql5.7 mysql -u root -p

データベースを作成し、テーブルにデータを挿入します。


mysql> create database test;
Query OK, 1 row affected (0.00 sec)

mysql> connect test
Connection id:    4
Current database: test

mysql>  create table users(id int(6) auto_increment primary key, name varchar(30));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into users(name) values('John');
Query OK, 1 row affected (0.01 sec)

mysql> select * from users;
+----+------+
| id | name |
+----+------+
|  1 | John |
+----+------+
1 row in set (0.00 sec)

コンテナを停止して削除します。


 % docker stop mysql5.7
mysql5.7
 % docker rm mysql5.7
mysql5.7

再度コンテナの作成を行ってMySQLに接続しても作成したtestデータベースはありません。データが保持できていないためコンテナを削除するとMySQLに保存されたデータは消えてしまいます。


 % docker run -v /Users/reffect/mysql_conf:/etc/mysql/conf.d/ --name mysql5.7 -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql:5.7

 % docker exec -it mysql5.7 mysql -u root -p

mysql> connect test
ERROR 1049 (42000): Unknown database 'test'

データを保持する方法

コンテナを再作成してもデータが保持できるようにローカルのOS上にデータ保存用のフォルダを作成します。フォルダ名もフォルダの作成場所も任意の場所を指定してください。ここでは/Users/reffect/dbとしています。


 % mkdir db

コンテナの作成を行います。


 % docker run -v /Users/reffect/mysql_conf:/etc/mysql/conf.d/ -v /Users/reffect/db:/var/lib/mysql --name mysql5.7 -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql:5.7

-vオプションでMysqlの設定ファイルの場所を指定していましたがもう一つ-vオプションを追加したローカルのフォルダのパスとコンテナ上のフォルダのパスを指定して実行します。

作成後dbフォルダに移動するとコンテナの/var/lib/mysqlフォルダの中身を確認することができます。


 % cd db
 % ls
auto.cnf		client-cert.pem		ib_logfile1		mysql			public_key.pem
ca-key.pem		client-key.pem		ibdata1			performance_schema	server-cert.pem
ca.pem			ib_logfile0		ibtmp1			private_key.pem		server-key.pem

コンテナ作成後、先ほどと同様にデータベースを作成しデータを挿入した後にコンテナの再作成を行ってください。挿入したが保持されていることが確認できるはずです。

別バージョンのMySQLコンテナの作成

別のバージョンである5.6のコンテナを作成します。


% docker run --name mysql5.6 -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql:5.6
Unable to find image 'mysql:5.6' locally
5.6: Pulling from library/mysql
 ・
Bind for 0.0.0.0:3306 failed: port is already allocated.

バージョン5.6のイメージがローカルにないのでダウンロードを行っています。しかし、現在稼働している5.7のポートと重複しているため起動することができません。

一度5.7を停止して5.6を起動すること正常に起動させることができます。同時に起動させる時はポートが重複しないように作成する必要があります。


 % docker stop mysql5.7
mysql5.7
 % docker start mysql5.6
mysql5.6

docker-composeからの作成

dockerコマンドを使ってMySQLコンテナが作成できることを確認してきましたが、-vオプションや様々なパラメータを追加したためコマンドがなりました。docker-compose.ymlファイルに各種情報を入力し保存しておくことで同じコンテナ環境を構築することができます。

dockerコマンドで実行した内容と同じ環境を作成するため、/Users/reffectフォルダの下にdocker-compose.ymlファイルを作成し、下記を記述します。


version: '3'

services:
  mysql:
    image: mysql:5.7
    container_name: mysql
    restart: unless-stopped
    ports:
      -  "3306:3306"
    volumes:
      -  /Users/reffect/db:/var/lib/mysql
      -  /Users/reffect/mysql_conf:/etc/mysql/conf.d
    environment:
      MYSQL_ROOT_PASSWORD: password

作成後、docker-compose.ymlファイルが保存されているフォルダでdocker-composeコマンドを実行するとMySQLコンテナを作成することができます。


 % docker-compose up -d 
Creating network "reffect_default" with the default driver
Creating mysql ... done

docker-compose ps -aコマンドで状態を確認することができます。


 % docker-compose ps -a
Name              Command             State                 Ports              
-------------------------------------------------------------------------------
mysql   docker-entrypoint.sh mysqld   Up      0.0.0.0:3306->3306/tcp, 33060/tcp

データベースへの接続等はdockerコマンドと同様の方法で行うことができます。

Laravelからの接続

Laravelである必要ではありませんが、コンテナ上にないアプリケーションからDocker上のMySQLにアクセスすることができるのかどうか確認を行っておきましょう。

laravelからDocker上に作成したMySQLコンテナのMySQLに接続しテーブルが作成できるか確認してみましょう。Laravelはローカル環境にそのままインストールしValet等は利用していません。

Laravelのインストールにはcomposerが必要なので事前にインストールを完了させておいてください。任意のフォルダで以下のコマンドを実行してください。


 % composer create-project --prefer-dist laravel/laravel laravel6

作成後にMySQLコンテナに接続してデータベースを作成しておきます。データベース名はlaravelとしています。


 % docker exec -it mysql5.7 mysql -u root -p 

mysql> create database laravel;
Query OK, 1 row affected (0.00 sec)

Laravel6のインストールフォルダにある.envファイルでデータベースの接続情報を更新します。docker runを実行した際のポート番号やrootのパスワード、作成したデータベース名を指定してください。


DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=33306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=password

.envファイルを更新したらテーブルの作成をphp artisan migrateコマンドで行います。


 % php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.03 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.02 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.01 seconds)

上記のようにテーブルが作成できたらLaravelからDocker上のMySQLに接続できていることがわかります。