ytooyamaのブログ

サーバ構築とか、仕事で発見したこととか、趣味のこととかを書いています。

コンテナーでMySQL Server 8を動かしてNode.jsからアクセスする

導入

前回の記事(というか、さっき書いた記事)

ytooyama.hatenadiary.jp

「そのうち」といったのですが、このネタを年を跨いで書くのはなんかアレなので、早速コンテナー版MySQL Server 8で試すことにしました。 前回の記事で何をやっているのかは説明したので、今回はコマンドの羅列で失礼します。

% docker container run -d --name some-mysql8 -e MYSQL_USER=root -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_PASSWORD=my-secret-pw   -p 53306:3306 docker.io/mysql/mysql-server:latest
% docker exec -it some-mysql8 mysql -uroot -p

mysql> CREATE USER 'nodejsuser'@'localhost' IDENTIFIED BY 'my-secret-pw';
mysql> GRANT all ON *.* TO 'nodejsuser'@'localhost';
mysql> ALTER USER 'nodejsuser'@'localhost' IDENTIFIED WITH mysql_native_password BY 'my-secret-pw';
mysql> FLUSH PRIVILEGES;

mysql> CREATE DATABASE list_app;
mysql> USE list_app;

mysql> CREATE TABLE users (id int, name varchar(10));
mysql> INSERT INTO users VALUES (1,'Yamada');
mysql> INSERT INTO users VALUES (2,'Tanaka');
mysql> INSERT INTO users VALUES (3,'Suzuki');

IPアドレス、ポートなどを修正して実行してみると...エラーメッセージが表示されます。 なるほど、docker0のゲートウェイIPアドレスですね。

$ node mysql.js
/Users/ytooyama/working/nodejs/mysql.js:13
  if (error) throw error;
             ^
Error: Access denied for user 'ytooyama'@'172.17.0.1' (using password: YES)
    at Packet.asError (/Users/ytooyama/working/nodejs/node_modules/mysql2/lib/packets/packet.js:728:17)
    at ClientHandshake.execute (/Users/ytooyama/working/nodejs/node_modules/mysql2/lib/commands/command.js:29:26)
    at Connection.handlePacket (/Users/ytooyama/working/nodejs/node_modules/mysql2/lib/connection.js:456:32)
    at PacketParser.onPacket (/Users/ytooyama/working/nodejs/node_modules/mysql2/lib/connection.js:85:12)
    at PacketParser.executeStart (/Users/ytooyama/working/nodejs/node_modules/mysql2/lib/packet_parser.js:75:16)
    at Socket.<anonymous> (/Users/ytooyama/working/nodejs/node_modules/mysql2/lib/connection.js:92:25)
    at Socket.emit (node:events:390:28)
    at addChunk (node:internal/streams/readable:315:12)
    at readableAddChunk (node:internal/streams/readable:289:9)
    at Socket.Readable.push (node:internal/streams/readable:228:10) {
  code: 'ER_ACCESS_DENIED_ERROR',
  errno: 1045,
  sqlState: '28000',
  sqlMessage: "Access denied for user 'nodejsuser'@'172.17.0.1' (using password: YES)",
  sql: undefined
}

ちょっと脱線

DockerでMySQLをコンテナーで動かす場合、外からのアクセスはポートバインドで許可すると思います。 Dockerのデフォルトではdocker0というインターフェイスがあって、これが172.17.0.1/16のIPアドレスになっています(ちなみに172.17.0.0/16のネットワークが使われていると判断されると、第2オクテットの数字を1つ加えてdocker0のIPアドレスが設定され、コンテナーにはそのネットワークからIPアドレスを割り当てます。以降同様に使われていないネットワークでデフォルトネットワークが構成される)。

DockerをLinuxで動かしている場合はip addrとかifconfigコマンドでdocker0を確認できると思いますが、Docker for macの場合は次のように実行してVMにログインするとそのシェル上でdocker0のIPアドレスを確認できます。

stackoverflow.com

$ docker run -it --rm --privileged --pid=host busybox nsenter -t1 -m -u -i -n

結論

話を戻して、つまり今回の場合は、'nodejsuser'@'172.17.0.1'からのアクセスを許可する必要があるということみたいです。 以下のように実行します。

mysql> CREATE USER 'nodejsuser'@'172.17.0.1' IDENTIFIED BY 'my-secret-pw';
mysql> GRANT all ON *.* TO 'nodejsuser'@'172.17.0.1';
mysql> ALTER USER 'nodejsuser'@'172.17.0.1' IDENTIFIED WITH mysql_native_password BY 'my-secret-pw';
mysql> FLUSH PRIVILEGES;
...
$ node mysql.js
[
  { id: 1, name: 'Yamada' },
  { id: 2, name: 'Tanaka' },
  { id: 3, name: 'Suzuki' }
]

これでようやくコンテナでMySQLを使えるようになったかも。

このブログサイトはJavaScriptを使っていますが、読み込んでいるJavaScriptは全てはてなが提供しているものであり、筆者が設置しているものではありません。