前提
docker-composeとSQL系のデータベースを使用したことがなかったので、これらの技術を利用して
ハンズオンをしようとしていた際にエラーに直面。調べてもなかなか解決しなかったので議事録を残します。
DB:MySQL
API:Node.js
Node.jsなのでSequelizeで接続を試みています。
環境
version: "3"
services:
api:
build: ./
container_name: todo-api
environment:
DB_HOST: db
DB_USER: todo
DB_PASS: todo
DB_DATABASE: todo
DEBUG: todoapi:server
tty: true
ports:
- 5001:5001
volumes:
- ./api:/home/node
networks:
- todoapp-network
command: "npm run dev"
depends_on:
- db
db:
image: mysql:5.7
platform: linux/amd64
container_name: mysql
restart: always
environment:
MYSQL_ROOT_HOST: todo-api
MYSQL_ROOT_PASSWORD: ${DB_PASS}
MYSQL_DATABASE: todo
MYSQL_USER: todo
MYSQL_PASSWORD: todo
ports:
- 3306:3306
volumes:
- ./db/docker/data:/var/lib/mysql
networks:
- todoapp-network
adminer:
image: adminer
restart: always
ports:
- 8080:8080
networks:
- todoapp-network
networks:
todoapp-network:
FROM node:18-slim
WORKDIR /home/node
USER node
const express = require("express");
const app = express();
const { Sequelize } = require("sequelize");
const PORT = 5001;
const sequelize = new Sequelize("todo", "todo", "todo", {
host: "localhost",
dialect: "mysql",
});
// expressでサーバー起動
app.listen(PORT, console.log("サーバーが" + PORT + "で起動しました。"));
// 接続の確認
const a = async () => {
try {
await sequelize.authenticate();
console.log("Connection has been established successfully.");
} catch (error) {
console.error("Unable to connect to the database:", error);
}
}
a();
https://sequelize.org/docs/v6/getting-started/#testing-the-connection
公式ドキュメントを確認すると関数aのように記述すると接続の確認ができるとのことでやってみました。
エラー内容
上記の環境でコンテナを立てて
$ docker-compose logs -f api
でログを確認したところ(docker-compose.ymlのファイル内のcommandでnpm run devでnodemonが動くようにしてます。)
todo-api | Unable to connect to the database: ConnectionRefusedError [SequelizeConnectionRefusedError]: connect ECONNREFUSED 127.0.0.1:3306
todo-api | at ConnectionManager.connect (/home/node/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:92:17)
todo-api | at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
todo-api | at async ConnectionManager._connect (/home/node/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:220:24)
todo-api | at async /home/node/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:174:32
todo-api | at async ConnectionManager.getConnection (/home/node/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:197:7)
todo-api | at async /home/node/node_modules/sequelize/lib/sequelize.js:304:26
todo-api | at async Sequelize.authenticate (/home/node/node_modules/sequelize/lib/sequelize.js:456:5)
todo-api | at async a (/home/node/app.js:38:5) {
todo-api | parent: Error: connect ECONNREFUSED 127.0.0.1:3306
todo-api | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16) {
todo-api | errno: -111,
todo-api | code: 'ECONNREFUSED',
todo-api | syscall: 'connect',
todo-api | address: '127.0.0.1',
todo-api | port: 3306,
todo-api | fatal: true
todo-api | },
todo-api | original: Error: connect ECONNREFUSED 127.0.0.1:3306
todo-api | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16) {
todo-api | errno: -111,
todo-api | code: 'ECONNREFUSED',
todo-api | syscall: 'connect',
todo-api | address: '127.0.0.1',
todo-api | port: 3306,
todo-api | fatal: true
todo-api | }
todo-api | }
確認したこと
基礎的な確認
・コンテナが起動し動作しているかの確認
・DBコンテナに入れるか
・DBコンテナに入った後、MySQLにログインできるか
など基礎的なことを確認したのちエラーについて調査。
エラー調査
「Error: connect ECONNREFUSED 127.0.0.1:3306」というエラーの記事はありましたが、
MySQLのversionが8からは認証の仕様が変わっているため
・hostの指定をlocalhostではなく、127.0.0.1にする
などがありましたが、Nodeとの互換性が悪いなどの記事を確認していたので5.7を使用しているため違いそう...
原因
docker-compose側の仕様でhost名はIPアドレスを指定するのではなく、DBコンテナのcontainer_nameを指定する必要がありました。
[他のDockerコンテナからコンテナ内のMySQLに接続する]
https://qiita.com/YuitoSato/items/4a4b46f5670b45739a37
この記事を確認するとSequelizeどうこうというよりも、mysqlのログインでhostを指定する場合、別コンテナにアクセスするにはIPアドレスではなくコンテナ名を指定する必要がある模様。
色々すっ飛ばして勉強するとインフラの肝心な部分の理解ができなくて困った案件でした。。。
const sequelize = new Sequelize("todo", "todo", "todo", {
host: "mysql", // <= 私の場合はDBコンテナのcontainer_nameはmysqlだったので変更するだけ
dialect: "mysql",
});
todo-api | Executing (default): SELECT 1+1 AS result
todo-api | Connection has been established successfully.
(1行目のログの意味もわかっていないのでまた勉強。DB側の話だと思うが...)