docker-compose MySQL8.0 のDBコンテナを作成する

MySQL8.0のデータベースコンテナを10分でサクッと作りたい人向け。

## 追記: 2021.07.28

### PHPからMySQLへ接続する場合

PHP 7.1.16, 7.2.4 以降のバージョンから `caching_sha2_password` に対応するようになりましたので、デフォルト認証プラグインの設定は不要になります。

https://www.php.net/manual/ja/ref.pdo-mysql.php

### Sequel Proをお使いの場合

Sequel Aceという新しいクライアントツールがリリースされました。
MySQL8系でもSequel Proとほぼ同じUIで操作できます。

https://qiita.com/ucan-lab/items/b1304eee2157dbef7774

## ベースイメージ

- https://hub.docker.com/_/mysql

## ファイル・ディレクトリ構成

```
$ tree -a .
.
├── .env
├── docker
│   └── mysql
│       └── my.cnf
├── docker-compose.yml
└── logs
    ├── mysql-error.log
    ├── mysql-query.log
    └── mysql-slow.log

3 directories, 6 files
```

## docker-compose.yml

```yml
version: "3"
services:
  db:
    image: mysql:8.0
    volumes:
      - db-store:/var/lib/mysql
      - ./logs:/var/log/mysql
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    environment:
      - MYSQL_DATABASE=${DB_NAME}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASS}
      - MYSQL_ROOT_PASSWORD=${DB_PASS}
      - TZ=${TZ}
    ports:
      - ${DB_PORT}:3306

  db-testing:
    image: mysql:8.0
    volumes:
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    tmpfs:
      - /var/lib/mysql
      - /var/log/mysql
    environment:
      - MYSQL_DATABASE=${DB_NAME}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASS}
      - MYSQL_ROOT_PASSWORD=${DB_PASS}
      - TZ=${TZ}

volumes:
  db-store:
```

### 補足

`db` コンテナは開発用、 `db-testing` コンテナはテスト用です。
`db` は名前付きボリューム(db-store)を定義して永続化しています。
`db-testing` はtmpfs一時的なファイルシステムをマウントしているので、コンテナを削除するとデータベースの中身も破棄されます。
データベースの接続情報やタイムゾーンは環境変数から設定します。
その他のデータベースの設定は `./docker/mysql/my.cnf` に配置したファイルをコンテナの `/etc/mysql/conf.d/my.cnf` にマウントしてます。
my.cnfの変更は down して up すれば反映されます。
ただ、デフォルト認証プラグインや既に作成したテーブルの文字コード変更などは手動で変更が必要なものもあります。それは名前付きボリュームを削除して作り直した方が早いかもです。

## .env

```shell
DB_NAME=homestead
DB_USER=homestead
DB_PASS=secret
DB_PORT=13306
TZ=Asia/Tokyo
```

## my.cnf

```config
# MySQLサーバーへの設定
[mysqld]
# 文字コード/照合順序の設定
character-set-server = utf8mb4
collation-server = utf8mb4_bin

# タイムゾーンの設定
default-time-zone = SYSTEM
log_timestamps = SYSTEM

# デフォルト認証プラグインの設定
default-authentication-plugin = mysql_native_password

# エラーログの設定
log-error = /var/log/mysql/mysql-error.log

# スロークエリログの設定
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 5.0
log_queries_not_using_indexes = 0

# 実行ログの設定
general_log = 1
general_log_file = /var/log/mysql/mysql-query.log

# mysqlオプションの設定
[mysql]
# 文字コードの設定
default-character-set = utf8mb4

# mysqlクライアントツールの設定
[client]
# 文字コードの設定
default-character-set = utf8mb4
```

### 補足

詳しくはリファレンスマニュアル等を参照

- [MySQL 8.0 Reference Manual](https://dev.mysql.com/doc/refman/8.0/en)
- [MySQLパフォーマンスチューニング -my.cnfの見直し-](https://qiita.com/mamy1326/items/9c5eaee3c986cff65a55)
- [my.cnf についてまとめた](https://qiita.com/at_1016/items/874788e375938837a027)
- [MySQLオプション（/etc/my.cnf）の設定例](https://easyramble.com/example-of-mysql-options.html)

デフォルト認証プラグインの設定してるのはこちらの記事で発生した問題の対策です。

- [MySQL8.0 認証方式を変更する(Laravel5)](https://qiita.com/ucan-lab/items/3ae911b7e13287a5b917)

## build & up

```shell
$ docker-compose up -d
```

```shell
$ docker-compose ps
       Name                     Command             State                 Ports               
----------------------------------------------------------------------------------------------
mysql8_db-testing_1   docker-entrypoint.sh mysqld   Up      3306/tcp, 33060/tcp               
mysql8_db_1           docker-entrypoint.sh mysqld   Up      0.0.0.0:13306->3306/tcp, 33060/tcp
```

```shell
$ docker-compose exec db mysql -V
mysql  Ver 8.0.16 for Linux on x86_64 (MySQL Community Server - GPL)
```

## dbコンテナのmysqlへログイン

```shell
$ docker-compose exec db bash -c 'mysql -u${MYSQL_USER} -p${MYSQL_PASSWORD} ${MYSQL_DATABASE}'
```

## 文字コードの設定

```shell
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-8.0/charsets/ |
+--------------------------+--------------------------------+
8 rows in set (0.01 sec)
```

## ユーザー一覧(rootユーザーで実行してます)

```shell
mysql> select Host, User from mysql.user;
+-----------+------------------+
| Host      | User             |
+-----------+------------------+
| %         | homestead        |
| %         | root             |
| localhost | mysql.infoschema |
| localhost | mysql.session    |
| localhost | mysql.sys        |
| localhost | root             |
+-----------+------------------+
6 rows in set (0.00 sec)
```

## MySQLのデータを初期化

```shell
$ docker-compose down --volumes
$ docker-compose up -d
```

`down` コマンド時に `--volumes` オプションを付けるとコンテナと名前付きボリュームの削除が行えます。
`up` コマンドで再びコンテナを作成すれば初期化された綺麗なdbコンテナを使えます。

## MySQLクライアントGUIツールで接続

### Sequel Pro で接続

2019年7月5日現在の `Sequel Pro v1.1.2` は MySQL8.0 非サポートです。
どうしても接続したい場合は、 [Test Build版](https://sequelpro.com/test-builds) を利用してください。

<img width="233" alt="スクリーンショット 2019-07-04 23.58.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/8b6a937a-f9be-3591-340b-a84caf62e3d7.png">

Test Build版のアイコンはグレーカラーでなんかカッコイイです

![スクリーンショット 2019-07-04 23.58.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/a550a7a7-fc41-dc4d-6c7c-2d0292a860f1.png)

- Name: `db-mysql8.0` 任意
- Username: `homestead` DB_USER
- Password: `secret` DB_PASS
- Database: `homestead` DB_NAME
- Port: `13306` DB_PORT

### Table Plus で接続

MySQL8.0に対応しているMySQLクライアントツールです。

https://tableplus.io

<img width="500" alt="スクリーンショット 2019-07-05 0.02.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/2a0afbde-1f82-4155-c8c7-eb7c143b3906.png">

- Name: `db-mysql8.0` 任意
- Username: `homestead` DB_USER
- Password: `secret` DB_PASS
- Database: `homestead` DB_NAME
- Port: `13306` DB_PORT