新しいプロジェクトでは、過去に同じような構成をDockerで作っていればDockerfileを流用しています。
さて、
今回は、最新のMySQLイメージを使う際に発生する問題について記載していきます。
イントロダクション
この記事で得られること
- MySQLの古いバージョンから、8.0系に移行した際に生じる問題についてわかる。
- 久しぶりにMySQLのイメージを使ったらエラーが起きた時の対処方法がわかる
環境
ツール
種類 | バージョン |
---|---|
Docker | 18.03.1 |
ライブラリ
種類 | バージョン |
---|---|
laravel | 5.5 |
状況
Laravelでアプリケーションを作っています。
Dockerで使うイメージは、ApacheとMySQLそれぞれの最新イメージを使用しています。
MySQLのDockerfileは下記です。
FROM mysql
COPY ./docker-entrypoint-initdb.d/ ./docker-entrypoint-initdb.d/
COPY ./conf.d/ /etc/mysql/conf.d/
RUN chmod 644 /etc/mysql/conf.d/*
問題
php ansible migrate
を実行すると次のエラーが発生する。
The server requested authentication method unknown to the client [caching_sha2_password]
(サーバーがクライアントに知られていない認証方法を要求しました[caching_sha2_password])
数日前は問題なく実行できていたのですが、MySQLのイメージを作り直してからエラーが起こるようになりました。 blog.websandbag.com
原因
MySQL8.0からセキュリティが強化されたようです。
MySQL :: MySQL 8.0 Release Notes :: Changes in MySQL 8.0.4 (2018-01-23, Release Candidate)
パスワードの生成方法が選択できるようになっており、ユーザー追加時に指定する必要があるようです。
設定は、default_authentication_plugin
に次のどちらかを設定することになります。
- 従来の
mysql_native_password
- ハッシュ化をする
caching_sha2_password
。
これが、2018年1月の事で、私が最初にMySQLのイメージを作ったのが2017年でした。
特にバージョンの指定はしていませんので、常に最新のバージョンを取ってくるようになっています。 MySQLイメージのキャッシュが残っており、プロジェクトは変わっても参照しているイメージは同じものだったと考えられます。
FROM mysql
参考
解決方法
解決方法は2種類あります。
MySQLのバージョンを固定する
確実に動作するバージョンに固定します。
実際サーバーがDocker運用ではなかったり、サーバーを更新する権限がないのであれば、バージョンを固定するのが無難です。
FROM mysql:5 # 省略
MySQLのバージョンに合わせて更新する
MySQL8の仕様に合わせます。
公式の説明よるとハッシュ化方式(caching_sha2_password
)が、デフォルトで設定されているようです。
For the server, the default value of the default_authentication_plugin system variable changes from mysql_native_password to caching_sha2_password.
本記事は、従来の方式(mysql_native_password
)で説明します。
Step 1. コンテナに同期するmysqlのコンフィグファイルに設定を追加
default_authentication_plugin
を指定します。
私の構成では、プロジェクトディレクトリ配下にconf.d
というディレクトリを作り、コンテナのconf.d
に同期しています。
その中にmy.conf
という、カスタマイズ用のコンフィグファイルを追加していますので、次のように指定します。
conf.d/my.conf
[mysqld] # 省略 default_authentication_plugin = mysql_native_password #<--追加
Step 2. ユーザーを追加する処理を変更
プラグインの指定が必要になるので、従来の方法とは少し変わるようです。 そのためユーザーの追加処理に変更を加えます。
前述したconfの件と同様、docker-entrypoint-initdb.d
というディレクトリで同期しています。
その中に、初期構築時で流し込むSQLファイルを置いています。
その記述は前のバージョンのものなので、次のように調整します。
CREATE USER '<ユーザー名>'@'localhost' IDENTIFIED WITH mysql_native_password BY <password>; CREATE USER '<ユーザー名>'@'%' IDENTIFIED WITH mysql_native_password BY <password>; GRANT ALL PRIVILEGES ON <指定するDB>.* TO '<ユーザー名>'@'localhost' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON <指定するDB>.* TO '<ユーザー名>'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES ;
Step 3. コンテナリビルド
コンテナをリビルドします。
もし、退避したいデータがあれば実行する前に移動して置いてください。
$ docker-compose --no-cache
Step 4. マイグレートを実行
コンテナができたら、マイグレートを実行して完了です。
Tips
LaravelのMySQL8.0サポート状況について
投稿日時点での話です。
設定した状態で、docker-compose up
を実行すると、次のエラーが発生します。
Variable 'sql_mode' can't be set to the value of 'NO_AUTO_CREATE_USER'
(変数 'sql_mode'は 'NO_AUTO_CREATE_USER'の値に設定できません)
これは、LaravelのMySQLの最新版をサポートしていないためのようです。
今後アップデートされるようですが、状況によってはMySQLのバージョンを固定する方法を取る必要があるかもしれません。
そのため、今回は最終的にバージョンを固定しました。
2019年6月時点でも状況は変わらないようですが、MySQL8.0でも動かせる方法がありました。