かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Docker コンテナ内の MySQL にコンテナ外からアクセスできないにハマる ERROR 1045 (28000): Access denied

docker-compose で作成した MySQL にコンテナ外から mysql コマンドでアクセスしようとしたら Access denied になるにハマったのメモ。※ 本エントリーは経過と事象のメモで詳しく調べてはいません。

環境
  • Mac OS 11.6
  • Docker desktop 4.5.0
  • MySQL 8.0.28 (Homebrew にてインストール)

Docker コンテナ内の MySQL にコンテナ外からアクセスできない問題

docker-compose.yml

services:
  db:
    image: mysql:8.0
    ports:
      - 3306:3306
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    environment:
      TZ: ${TZ}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}

DB_USER=phper, DB_PASSWORD=secret のユーザーを作成するようにしました。
これを docker compose up したら localhost3306 ポートで MySQL が動作している想定です。

外部から MySQL に接続をしてみる

$ mysql -h 127.0.0.1 -P 3306 -u phper -psecret
ERROR 1045 (28000): Access denied for user 'phper'@'localhost' (using password: YES)

アクセスできない。
ホストを127.0.0.1 から localhost に変更してみても同様の状態でした

$ mysql -h localhost -P 3306 -u phper -psecret
ERROR 1045 (28000): Access denied for user 'phper'@'localhost' (using password: YES)

Host を localhost にして --protocol=tcp を与えるとコンテナ外からアクセス可能になった

$ mysql -h localhost -P 3306 -u phper -psecret --protocol=tcp
mysql>

ホストを 127.0.0.1 とすると --protocol=tcp オプションを与えてもダメだった

$ mysql -h 127.0.0.1 -P 3306 -u phper -psecret --protocol=tcp
ERROR 1045 (28000): Access denied for user 'phper'@'localhost' (using password: YES)

root ユーザーだと一見アクセスできているように見えるが、Docker ではなくローカルの MySQL に繋がっていた

root ユーザーだと --protocol=tcp オプション無しでもアクセスできているように見えていたのですが、Docker コンテナの DB に database を作成してみた結果、phper で Access denied になっていた時はローカルにある MySQL の DB に繋がっているだけでした。

# local の DB に接続している
$ mysql -h 127.0.0.1 -P 3306 -u root -proot
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

# local の DB に接続している
$ mysql -h localhost -P 3306 -u root -proot
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

# local の DB に接続している
$ mysql -h 127.0.0.1 -P 3306 -u root -proot --protocol=tcp
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

# localhost + --protocol=tcp の時だけ Docker コンテナの DB に接続している
$ mysql -h localhost -P 3306 -u root -proot --protocol=tcp
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| my_docker_db       |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

root ユーザーの場合ローカルに MySQL をインストールしていると発見が遅れそうなので、show databases; などで何処に繋がっているのかまでを確認できるようにしておくと良さそうです。

localhost127.0.0.1

ホスト名が localhost だった場合、パフォーマンスのためなのかソケットが暗黙で使用されます。 ですが。その場合 127.0.0.1 を使うとTCP/IP接続が同PCであっても使用され問題なくTCP経由で接続できます。
localhost を接続先ホストに指定すると、ポート指定のオプションを無視し socket 経由で接続しようとします。

  • mysql -h localhost -uroot -p --port=3307 こうやった場合でもポート指定が無視されちゃいます。
  • mysql -h 127.0.0.1 -uroot -p --port=3307 この場合はすんなり接続されるはずです

cf. MySQLでlocalhostと127.0.0.1の違い - Qiita

こちらの記事を見た感じだと 127.0.0.1 の方が良さそうな気がしたのですが、今回自分の環境では localhost + 明示的に --protocol=tcp オプションを渡す でしか Docker のコンテナに繋ぐことができませんでした。

ホストは localhost と指定するとローカルマシンのmysqlソケットを探しに行くのでエラーになる。
cf. docker内のMySQLに接続したい - かもメモ

以前自分自身で localhost にするとアクセスできなかったという記事を書いているので、今回のは渡されたマシンだったのでマシン側の設定が原因な気もしています。
ネットワークとかの知識が皆無なので、何故なのかという部分は理解できていませんが、発生した事象と解決した方法だけをメモとして残しておくこととしました。(そのうち自分で同じようにハマると思うので…)


[参考]