dockerコンテナからmysqlに接続できたはいいが、appコンテナからmysqlに接続できない
タイトルの通り、appコンテナからmysqlに接続できなかったので試したことの記録として書き残す。
ディレクトリ構成
├── Dockerfile
├── README.md
├── __tests__
├── components
├── db
├── docker-compose.yml
├── jest.config.js
├── lib
├── next-env.d.ts
├── node_modules
├── package-lock.json
├── package.json
├── pages
├── postcss.config.js
├── posts
├── prisma
├── public
├── styles
├── tailwind.config.js
├── test
└── tsconfig.json
docker-compose.yml
version: '3'
services:
node:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./:/usr/src/app
depends_on:
- mysql
command: sh -c "npm run dev"
ports:
- '3000:3000'
tty: true
mysql:
image: mysql:latest
command: --default-authentication-plugin=mysql_native_password
env_file:
- .env
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- 3306:3306
# データを永続化させる場合
volumes:
# 初期データを投入するSQLが格納されているdir
- ./db/mysql_init:/docker-entrypoint-initdb.d
# 永続化するときにマウントするdir
- ./db/mysql_data:/var/lib/mysql
tty: true
まず、コンテナを起動
$ docker-compose up -d
Starting nextjs-blog_mysql_1 ... done
Starting nextjs-blog_node_1 ... done
起動完了。次に、mysqlのコンテナに接続
$ docker-compose exec mysql sh
#
次にmysqlにログイン
# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.19 MySQL Community Server - GPL
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
mysqlに接続することはできた。ちなみにshow databases;
を実行すると、
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mydb |
| mysql |
| performance_schema |
| sample_db |
| sys |
+--------------------+
6 rows in set (0.02 sec)
こんな感じでdbが表示される。
問題はここから。
アプリケーションのコンテナを起動する。
$ docker-compose exec node sh
/usr/src/app #
起動できた。
mysqlにログインしようとして、
$ mysql -u root -p
sh: mysql: not found
mysql自体インストールされてない???
別のターミナルを開いて、
$ mysql --version
mysql Ver 8.0.23 for osx10.16 on x86_64 (Homebrew)
インストールされてる。(mysqlコンテナでは接続できてたし、当たり前か。。)
ちなみにmysqlのパッケージをinstall済み。
package.json
色々省略
"dependencies": {
"mysql": "^2.18.1",
}
アプリのコンテナでmysql-client的なものをインストールする必要がある?
Dockerのコンテナ内でアプリからmysqlに接続したい。
Debianのdockerイメージでmysql-clientが無くてハマった人へ
npmでmysql-client
と検索してみたものの、mysql-clientは最終更新が10年前なので、next.js+docker+prisma+mysqlで使っている人はいなそう。。
別のターミナルでmysql
が動くのはホスト(macOS)にmysqlがインストールされているからで、nodeサービスのとは無関係のように思います。docker-composeで起動しているコンテナ同士はports
でポートを開けなくても<サービス名>:<ポート>
でアクセス出来ます。今回の場合はmysqlサービスにportsを書かなくても、nodeサービスからmysql:3306
で繋がると思います。
あとはnodeのmysql
ですが、これはcliはなさそうなのでinstall -g mysql
してもmysql
で起動出来ないのでは?と思います。
コメントありがとうございます!!
なんとなく理解はできた気がするのですが、mysql:3306
というのは、node
サービスのports
に書けばいいのでしょうか?一度そのように書いてbuildを試してみたのですが、書き方が正しくないみたいな趣旨のエラーが出ました。一応エラーは下記です。
ERROR: The Compose file './docker-compose.yml' is invalid because:
services.node.ports contains an invalid type, it should be a number, or an object
それとも、node
サービスを立ち上げて、コンテナ内でアクセスするようなコマンドを打てばいいのでしょうか?
よかったらご教授いただきたいです。よろしくお願いします!
portsは書かないですね。こういうのは、自分で調べるのがおすすめです。色々な要素が関わっていて、わかりにくければ、自分の確認したいことに絞って簡単なケースで実験出来るようになる必要があります。
お互いに信頼関係があれば、「自分で調べて下さい」で終わりでも良いと思いますが、そうではないので、ここで今言ったことを実践してみます。
まずdocker-compose.yml
は
version: '3'
services:
node:
image: node:14.16.0-buster
command: /bin/bash -c "while sleep 1000; do :; done"
volumes:
- ./node:/src
working_dir: /src
depends_on:
- mysql
mysql:
image: mysql:5.7.33
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_DATABASE: db_name
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
このように変えます(使用するdockerイメージはlatestだと常に変わるので、できればバージョンを指定した方が良いと思います。このあたりは簡単な実験でしかないので好みです)。node
プロジェクトのルートパスは'./node'とします。この状態で、まずdocker-compose up
を実行して、起動したら
docker exec -i mysql_test_mysql_1 sh -c 'exec mysql -D db_name' < db.sql
で、db_name
にテーブルを追加します。db.sql
の中身は次の通りです。
DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (
`name` varchar(20) NOT NULL,
`email` varchar(20) NOT NULL,
PRIMARY KEY (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
LOCK TABLES `person` WRITE;
INSERT INTO `person` VALUES ('Tom','tom@example.com');
UNLOCK TABLES;
とりあえずDBの中身を確認します。docker-compose exec mysql mysql
でmysqlにログインしたら
SELECT * FROM person;
を入力して、レコードが1行表示されることを確認します。もし、mysqlに繋がらない場合はvolumeの状態がおかしくなっている可能性があるのでdocker-compose down --volumes
で初期化します。
次にdocker-compose exec node
でnodeサービスに入ります。次のようにして、プロジェクトを作成します。
cd /src
touch client.js
npm init
全てデフォルトのまま連打してプロジェクトを作成したあと、npm install mysql
をインストールし、client.js
を編集します。
const mysql = require('mysql');
const connection = mysql.createConnection({
host : 'mysql',
user : 'root',
database: 'db_name'
});
connection.connect();
connection.query('SELECT name, email from person;', function (err, rows, fields) {
if (err) { console.log('err: ' + err); }
console.log('name: ' + rows[0].name);
console.log('email: ' + rows[0].email);
});
connection.end();
この状態でnpx node client.js
でレコードが表示されればOK。これでコンテナ同士は<サービス名>:<ポート番号>
で繋がることが確認できました。
記載していただいたのを参考にしつつ進めていったら、下記のように
# npx node client.js
name: Tom
email: tom@example.com
と表示されました。
本当にありがとうございます🙇♂️
npxコマンドで試してみる
/usr/src/app # npx mysql -u root -p
npm ERR! could not determine executable to run
npm ERR! A complete log of this run can be found in:
npm ERR! /root/.npm/_logs/2021-02-24T09_22_47_997Z-debug.log
ログを確認
0 verbose cli [
0 verbose cli '/usr/local/bin/node',
0 verbose cli '/usr/local/lib/node_modules/npm/bin/npm-cli.js',
0 verbose cli 'exec',
0 verbose cli '--',
0 verbose cli 'mysql',
0 verbose cli '-u',
0 verbose cli 'root',
0 verbose cli '-p'
0 verbose cli ]
1 info using npm@7.5.1
2 info using node@v15.8.0
3 timing config:load:defaults Completed in 4ms
4 timing config:load:file:/usr/local/lib/node_modules/npm/npmrc Completed in 2ms
5 timing config:load:builtin Completed in 2ms
6 timing config:load:cli Completed in 3ms
7 timing config:load:env Completed in 0ms
8 timing config:load:file:/usr/src/app/.npmrc Completed in 3ms
9 timing config:load:project Completed in 5ms
10 timing config:load:file:/root/.npmrc Completed in 1ms
11 timing config:load:user Completed in 1ms
12 timing config:load:file:/usr/local/etc/npmrc Completed in 0ms
13 timing config:load:global Completed in 1ms
14 timing config:load:cafile Completed in 1ms
15 timing config:load:validate Completed in 0ms
16 timing config:load:setUserAgent Completed in 1ms
17 timing config:load:setEnvs Completed in 2ms
18 timing config:load Completed in 21ms
19 verbose npm-session b60d3143ec60cc6a
20 timing npm:load Completed in 47ms
21 http fetch GET 304 https://registry.npmjs.org/mysql 281ms (from cache)
22 timing command:exec Completed in 311ms
23 verbose stack Error: could not determine executable to run
23 verbose stack at getBinFromManifest (/usr/local/lib/node_modules/npm/lib/exec.js:264:23)
23 verbose stack at exec (/usr/local/lib/node_modules/npm/lib/exec.js:178:15)
24 verbose cwd /usr/src/app
25 verbose Linux 4.19.121-linuxkit
26 verbose argv "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/bin/npm-cli.js" "exec" "--"
27 verbose node v15.8.0
28 verbose npm v7.5.1
29 error could not determine executable to run
30 verbose exit 1
よくわからない。。
npm install -g mysql
しなおしてもエラーは変わらず。。